# documentación de Django - 3.2.11.dev

# Escribiendo su primera aplicación en Django, parte 2

Este tutorial comienza donde quedó el Tutorial 1. Vamos a configurar la base de datos, crear su primer modelo y recibir una introducción rápida al sitio administrativo generado automáticamente de Django.

Dónde obtener ayuda:

If you’re having trouble going through this tutorial, please head over to the Getting Help section of the FAQ.

## Configuración de la base de datos

Ahora, abra el archivo `mysite/settings.py`. Es un módulo normal de Python con variables de nivel de módulo que representan la configuración de Django.

Por defecto la configuración utiliza SQLite. Si tiene poca experiencia con bases de datos o su interés es solo probar Django esta es la opción más fácil. SQLite está incluido en Python por lo que no tendrá que instalar nada más para soportar su base de datos. Sin embargo, al iniciar su primer proyecto real, es posible que desee utilizar una base de datos más potente como PostgreSQL para evitar dolores de cabeza en el futuro al tener que cambiar entre base de datos.

Si desea utilizar otra base de datos, instale los conectores de base de datos apropiados, y cambie las siguientes claves en el ítem `DATABASES` `'default'` para que se ajusten a la configuración de conexión de la base de datos:

- `ENGINE` – bien sea `'django.db.backends.sqlite3'`, `'django.db.backends.postgresql_psycopg2'`, `'django.db.backends.mysql'`, o `'django.db.backends.oracle'`. Otros backends también están disponibles.
- `NAME` – The name of your database. If you’re using SQLite, the database will be a file on your computer; in that case, `NAME` should be the full absolute path, including filename, of that file. The default value, `BASE_DIR / 'db.sqlite3'`, will store the file in your project directory.

Si no está utilizando SQLite como su base de datos, se deben añadir ajustes adicionales tales como `USER`, `PASSWORD`, y `HOST` se deben añadir. Para más información, vea la documentación de referencia para `DATABASES`.

Para bases de datos distintas a SQLite

Si está utilizando una base de datos SQLite, asegúrese de que ha creado ya la base de datos en este punto. Hágalo con el comando «`CREATE DATABASE database_name;`» en la consola interactiva de la base de datos.

Del mismo modo asegúrese de que la base de datos proporcionada en el archivo `mysite/settings.py` tiene permisos de tipo «create database». Esto permitirá la creación automática de test database que será necesaria en un tutorial posterior.

Si estás usando SQLite, no es necesario crear nada de antemano - el archivo de base de datos se creará automáticamente cuando sea necesario.

Mientras que usted está editando el archivo `mysite/settings.py`, configure `TIME_ZONE` a su zona horaria.

Además, observe que la configuración de `INSTALLED_APPS` se encuentra en la parte superior del archivo. Esta contiene los nombres de todas las aplicaciones Django que están activadas en esta instancia de Django. Las aplicaciones se pueden usar en diversos proyectos y usted puede empaquetar y distribuirlas para que otras personas las puedan utilizar en sus proyectos.

Por defecto, `INSTALLED_APPS` contiene las siguientes aplicaciones y Django viene equipado con todas ellas:

- `django.contrib.admin` - El sitio administrativo. Usted lo utilizará dentro de poco.
- `django.contrib.auth`– Un sistema de autenticación.
- `django.contrib.contenttypes`– Un framework para los tipos de contenido.
- `django.contrib.sessions` – Un framework de sesión.
- `django.contrib.messages` – Un framework de mensajería.
- `django.contrib.staticfiles` – Un framework para la gestión de archivos estáticos.

Estas aplicaciones se incluyen de forma predeterminada como una conveniencia para el caso común.

Algunas de estas aplicaciones utilizan al menos una tabla de base de datos, por lo que necesitamos crear las tablas en la base de datos antes de poder utilizarlas. Para ello, ejecute el siguiente comando:

/ 

    $ python manage.py migrate

    ...\> py manage.py migrate

The `migrate` command looks at the `INSTALLED_APPS` setting and creates any necessary database tables according to the database settings in your `mysite/settings.py` file and the database migrations shipped with the app (we’ll cover those later). You’ll see a message for each migration it applies. If you’re interested, run the command-line client for your database and type `\dt` (PostgreSQL), `SHOW TABLES;` (MariaDB, MySQL), `.schema` (SQLite), or `SELECT TABLE_NAME FROM USER_TABLES;` (Oracle) to display the tables Django created.

Para los minimalistas

Como dijimos anteriormente, las aplicaciones predeterminadas se incluyen para el caso común, pero no todos las necesitan. Si usted no necesita alguna o ninguna de ellas, no dude en dejar fuera o borrar las línea(s) correspondientes desde `INSTALLED_APPS` antes de ejecutar el comando `migrate`. El comando `migrate` solo ejecutará migraciones para aplicaciones en `INSTALLED_APPS`.

## Creando modelos

A continuación definiremos sus modelos, sobre todo su estructura de base de datos, con metadatos adicionales.

Filosofía

A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Django follows the DRY Principle. The goal is to define your data model in one place and automatically derive things from it.

This includes the migrations - unlike in Ruby On Rails, for example, migrations are entirely derived from your models file, and are essentially a history that Django can roll through to update your database schema to match your current models.

In our poll app, we’ll create two models: `Question` and `Choice`. A `Question` has a question and a publication date. A `Choice` has two fields: the text of the choice and a vote tally. Each `Choice` is associated with a `Question`.

These concepts are represented by Python classes. Edit the `polls/models.py` file so it looks like this:

polls/models.py

    from django.db import models

    class Question(models.Model):
        question_text = models.CharField(max_length=200)
        pub_date = models.DateTimeField('date published')

    class Choice(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE)
        choice_text = models.CharField(max_length=200)
        votes = models.IntegerField(default=0)

Here, each model is represented by a class that subclasses `django.db.models.Model`. Each model has a number of class variables, each of which represents a database field in the model.

Cada campo está representado por una instancia de una clase `Field`, por ejemplo, `CharField` para campos de caracteres y `DateTimeField` para variables de tiempo y fecha. Esto le dice a Django qué tipo de datos cada campo contiene.

El nombre de cada instancia `Field` (por ejemplo, `question_text` o `pub_date`)` es el nombre del campo, en formato adaptado al lenguaje de la máquina. Va a usar este valor en el código Python y su base de datos va a usarlo como el nombre de la columna.

Puede emplear un primer argumento posicional opcional a una `Field` para designar un nombre legible por humanos. Ese se utiliza en varias partes introspectivas de Django y sirve al mismo tiempo como documentación. Si no se proporciona este campo, Django usará el nombre legible por la máquina. En este ejemplo, sólo hemos definido un nombre legible para `Question.pub_date`. Para el resto de los campos en este modelo, el nombre del campo legible por la máquina servirá como el nombre legible por humanos.

Algunas clases `Field` precisan argumentos. La clase `CharField`, por ejemplo, requiere que usted le asigne un `max_length`. Esta se utiliza no sólo en el esquema de la base de datos, sino también en la validación como veremos dentro de poco.

Una clase `Field` también puede tener varios argumentos opcionales; en este caso, le hemos fijado al `default` el valor de `votes` en 0.

Por último, tenga en cuenta que una relación se define usando `ForeignKey`. Eso le indica a Django que cada `Choice` se relaciona con un sola `Question`. Django es compatible con todas las relaciones de bases de datos comunes: varias a una, varias a varias y una a una.

## Activando los modelos

Ese pequeño fragmento de código de modelo le proporciona a Django mucha información. Con él Django es capaz de:

- Crear un esquema de base de datos para esta aplicación (oraciones `CREATE TABLE`).
- Crear una API de acceso a la base datos Python para acceder a los objetos `Question` y `Choice`.

Pero primero tenemos que indicarle a nuestro proyecto que la aplicación `polls` está instalada.

Filosofía

Las aplicaciones Django son «conectables»: Usted puede utilizar una aplicación en diversos proyectos y puede distribuir aplicaciones porque ellas no necesitan estar atadas a una determinada instalación de Django.

Para incluir la aplicación en nuestro proyecto necesitamos agregar una referencia a su clase de configuración en la configuración `INSTALLED_APPS`. La clase `PollsConfig` está en el archivo `polls/apps.py` por lo que su ruta punteada es `'polls.apps.PollsConfig'`. Edite el archivo mysite/settings.py y agregue la ruta punteada a la configuración `INSTALLED_APPS`. Se verá así:

mysite/settings.py

    INSTALLED_APPS = [
        'polls.apps.PollsConfig',
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]

Ahora Django sabe incluir la aplicación `polls`. Vamos a ejecutar otro comando:

/ 

    $ python manage.py makemigrations polls

    ...\> py manage.py makemigrations polls

Usted debe ver algo similar a lo siguiente:

    Migrations for 'polls':
      polls/migrations/0001_initial.py
        - Create model Question
        - Create model Choice

Al ejecutar `makemigrations`, usted le indica a Django que ha realizado algunos cambios a sus modelos (en este caso, ha realizado cambios nuevos) y que le gustaría que los guarde como una migración.

Migrations are how Django stores changes to your models (and thus your database schema) - they’re files on disk. You can read the migration for your new model if you like; it’s the file `polls/migrations/0001_initial.py`. Don’t worry, you’re not expected to read them every time Django makes one, but they’re designed to be human-editable in case you want to manually tweak how Django changes things.

Hay un comando que ejecutará las migraciones para usted y gestionará el esquema de base de datos automáticamente; este se denomina `migrate`, y hablaremos de ello en un momento, pero primero, vamos a ver cuál SQL esa migración ejecutaría . El comando `sqlmigrate` recibe nombres de migración y devuelve su SQL:

/ 

    $ python manage.py sqlmigrate polls 0001

    ...\> py manage.py sqlmigrate polls 0001

Debería ver algo similar a lo siguiente (lo hemos reformateado para facilitar la lectura):

    BEGIN;
    --
    -- Create model Question
    --
    CREATE TABLE "polls_question" (
        "id" serial NOT NULL PRIMARY KEY,
        "question_text" varchar(200) NOT NULL,
        "pub_date" timestamp with time zone NOT NULL
    );
    --
    -- Create model Choice
    --
    CREATE TABLE "polls_choice" (
        "id" serial NOT NULL PRIMARY KEY,
        "choice_text" varchar(200) NOT NULL,
        "votes" integer NOT NULL,
        "question_id" integer NOT NULL
    );
    ALTER TABLE "polls_choice"
      ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
        FOREIGN KEY ("question_id")
        REFERENCES "polls_question" ("id")
        DEFERRABLE INITIALLY DEFERRED;
    CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

    COMMIT;

Tenga en cuenta lo siguiente:

- La salida exacta variará dependiendo de la base de datos que esté utilizando. El ejemplo anterior se genera para PostgreSQL.
- Los nombres de las tablas se generan automáticamente combinando el nombre de la aplicación (`polls`) y el nombre del modelo en minúscula; `question` y `choice`. (Usted puede anular este comportamiento)
- Las claves primarias (IDs) se agregan automáticamente. (Usted también puede anular esto)
- Convencionalmente, Django añade `"_id"` al nombre del campo de la clave externa (sí, usted también puede anular esto)
- The foreign key relationship is made explicit by a `FOREIGN KEY` constraint. Don’t worry about the `DEFERRABLE` parts; it’s telling PostgreSQL to not enforce the foreign key until the end of the transaction.
- Se adapta a la base de datos que está utilizando, así que los tipos de campos específicos de la bases de datos como `auto_increment` (MySQL), `serial` (PostgreSQL) o `integer primary key autoincrement` (SQLite) se gestionan de forma automática. Lo mismo se aplica para la cita de nombres de campos, por ejemplo, el uso de comillas dobles o comillas simples.
- The `sqlmigrate` command doesn’t actually run the migration on your database - instead, it prints it to the screen so that you can see what SQL Django thinks is required. It’s useful for checking what Django is going to do or if you have database administrators who require SQL scripts for changes.

Si le interesa, usted también puede ejecutar el comando `python manage.py check`; este revisa cualquier problema en su proyecto sin hacer migraciones o modificar la base de datos.

A continuación, ejecute de nuevo el comando `migrate` para crear esas tablas modelos en su base de datos:

/ 

    $ python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, polls, sessions
    Running migrations:
      Rendering model states... DONE
      Applying polls.0001_initial... OK

    ...\> py manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, polls, sessions
    Running migrations:
      Rendering model states... DONE
      Applying polls.0001_initial... OK

El comando `migrate` toma todas las migraciones que no han sido aplicadas (Django rastrea cuales se aplican utilizando una tabla especial en su base de datos llamada `django_migrations`) y las ejecuta contra su base de datos; básicamente, sincronizando los cambios que usted ha realizado a sus modelos con el esquema en la base de datos.

Las migraciones son muy potentes y le permiten modificar sus modelos con el tiempo, a medida que desarrolla su proyecto, sin necesidad de eliminar su base de datos o las tablas y hacer otras nuevas. Este se especializa en la actualización de su base de datos en vivo, sin perder datos. Vamos a hablar de ellas en mayor profundidad más tarde en el tutorial, pero por ahora, recuerde la guía de tres pasos para hacer cambios de modelo:

- Cambie sus modelos (en `models.py`).
- Ejecute el comando `python manage.py makemigrations` para crear migraciones para esos cambios
- Ejecute el comando `python manage.py migrate` para aplicar esos cambios a la base de datos.

The reason that there are separate commands to make and apply migrations is because you’ll commit migrations to your version control system and ship them with your app; they not only make your development easier, they’re also usable by other developers and in production.

Lea la documentación del django-admin para obtener información detallada sobre lo que puede hacer la utilidad `manage.py`.

## Jugando con la API

Ahora vayamos al shell interactivo de Python y juguemos con la API gratuita que Django le proporciona. Para llamar el shell de Python, utilice este comando:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

We’re using this instead of simply typing «python», because `manage.py` sets the `DJANGO_SETTINGS_MODULE` environment variable, which gives Django the Python import path to your `mysite/settings.py` file.

Una vez que esté en el shell, explore la API de base de datos:

    >>> from polls.models import Choice, Question  # Import the model classes we just wrote.

    # No questions are in the system yet.
    >>> Question.objects.all()
    <QuerySet []>

    # Create a new Question.
    # Support for time zones is enabled in the default settings file, so
    # Django expects a datetime with tzinfo for pub_date. Use timezone.now()
    # instead of datetime.datetime.now() and it will do the right thing.
    >>> from django.utils import timezone
    >>> q = Question(question_text="What's new?", pub_date=timezone.now())

    # Save the object into the database. You have to call save() explicitly.
    >>> q.save()

    # Now it has an ID.
    >>> q.id
    1

    # Access model field values via Python attributes.
    >>> q.question_text
    "What's new?"
    >>> q.pub_date
    datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

    # Change values by changing the attributes, then calling save().
    >>> q.question_text = "What's up?"
    >>> q.save()

    # objects.all() displays all the questions in the database.
    >>> Question.objects.all()
    <QuerySet [<Question: Question object (1)>]>

Un segundo. `<Question: Question object (1)>` no es una representación útil de este objeto. Arreglemos esto modificando el modelo `Question` (en el archivo `polls/models.py`) y agregando un metodo `__str__()` a los dos modelos, `Question` y `Choice`:

polls/models.py

    from django.db import models

    class Question(models.Model):
        # ...
        def __str__(self):
            return self.question_text

    class Choice(models.Model):
        # ...
        def __str__(self):
            return self.choice_text

Es importante añadir los métodos `__str__()` a sus modelos, no solo para su conveniencia al lidiar con la línea de comandos interactiva, sino también porque las representaciones de objetos se usan en todo el sitio administrativo generado automáticamente de Django.

Let’s also add a custom method to this model:

polls/models.py

    import datetime

    from django.db import models
    from django.utils import timezone

    class Question(models.Model):
        # ...
        def was_published_recently(self):
            return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Tenga en cuenta la adición de `import datetime` y `from django.utils import timezone`, para hacer referencia el módulo estándar de Python `datetime` y las herramientas relacionadas con el huso horario de Django `django.utils.timezone` respectivamente. Si usted no está familiarizado con el manejo de la zona horaria en Python, usted puede aprender más en la documentación de soporte de zona horaria.

Guarde estos cambios e inicie un nuevo shell interactivo Python ejecutando de nuevo `python manage.py shell`:

    >>> from polls.models import Choice, Question

    # Make sure our __str__() addition worked.
    >>> Question.objects.all()
    <QuerySet [<Question: What's up?>]>

    # Django provides a rich database lookup API that's entirely driven by
    # keyword arguments.
    >>> Question.objects.filter(id=1)
    <QuerySet [<Question: What's up?>]>
    >>> Question.objects.filter(question_text__startswith='What')
    <QuerySet [<Question: What's up?>]>

    # Get the question that was published this year.
    >>> from django.utils import timezone
    >>> current_year = timezone.now().year
    >>> Question.objects.get(pub_date__year=current_year)
    <Question: What's up?>

    # Request an ID that doesn't exist, this will raise an exception.
    >>> Question.objects.get(id=2)
    Traceback (most recent call last):
        ...
    DoesNotExist: Question matching query does not exist.

    # Lookup by a primary key is the most common case, so Django provides a
    # shortcut for primary-key exact lookups.
    # The following is identical to Question.objects.get(id=1).
    >>> Question.objects.get(pk=1)
    <Question: What's up?>

    # Make sure our custom method worked.
    >>> q = Question.objects.get(pk=1)
    >>> q.was_published_recently()
    True

    # Give the Question a couple of Choices. The create call constructs a new
    # Choice object, does the INSERT statement, adds the choice to the set
    # of available choices and returns the new Choice object. Django creates
    # a set to hold the "other side" of a ForeignKey relation
    # (e.g. a question's choice) which can be accessed via the API.
    >>> q = Question.objects.get(pk=1)

    # Display any choices from the related object set -- none so far.
    >>> q.choice_set.all()
    <QuerySet []>

    # Create three choices.
    >>> q.choice_set.create(choice_text='Not much', votes=0)
    <Choice: Not much>
    >>> q.choice_set.create(choice_text='The sky', votes=0)
    <Choice: The sky>
    >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

    # Choice objects have API access to their related Question objects.
    >>> c.question
    <Question: What's up?>

    # And vice versa: Question objects get access to Choice objects.
    >>> q.choice_set.all()
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
    >>> q.choice_set.count()
    3

    # The API automatically follows relationships as far as you need.
    # Use double underscores to separate relationships.
    # This works as many levels deep as you want; there's no limit.
    # Find all Choices for any question whose pub_date is in this year
    # (reusing the 'current_year' variable we created above).
    >>> Choice.objects.filter(question__pub_date__year=current_year)
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

    # Let's delete one of the choices. Use delete() for that.
    >>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
    >>> c.delete()

Para obtener más información sobre las relaciones de modelos, consulte Accediendo a objetos relacionados. Para más información sobre cómo utilizar guiones bajos para realizar búsquedas de campo a través de la API, consulte :ref: Búsquedas de campos <field-lookups-intro>. Para más detalles sobre la API de base de datos, consulte nuestra Referencia de API de base de datos.

## Presentando el sitio administrativo de Django

Filosofía

La generación de sitios administrativos para su personal o clientes para agregar, modificar y eliminar contenido es un trabajo aburrido que no requiere mucha creatividad. Por esa razón, Django automatiza completamente la creación de interfaces de sitios administrativos para los modelos.

Django fue escrito en un entorno de sala de redacción, con una separación muy clara entre «los editores de contenido» y el sitio «público». Los administradores del sitio utilizan el sistema para agregar noticias, eventos, resultados deportivos, etc., y ese contenido se muestra en el sitio público. Django resuelve el problema de crear una interfaz unificada para los administradores del sitio para editar el contenido.

El sitio admin no está destinado a ser utilizado por los visitantes del sitio. Es para los administradores del sitio.

### Creando un usuario del admin

Primero tendremos que crear un usuario que pueda iniciar sesión en el sitio administrativo. Ejecute el siguiente comando:

/ 

    $ python manage.py createsuperuser

    ...\> py manage.py createsuperuser

Introduzca su nombre de usuario deseado y pulse enter.

    Username: admin

A continuación se le solicitará su dirección de correo electrónico deseada:

    Email address: admin@example.com

El paso final es introducir su contraseña. Se le pedirá que introduzca su contraseña dos veces, la segunda vez como confirmación de la primera.

    Password: **********
    Password (again): *********
    Superuser created successfully.

### Inicie el servidor de desarrollo

El sitio administrativo de Django se activa de forma predeterminada. Vamos a iniciar el servidor de desarrollo y a explorarlo.

Si el servidor no está en marcha, inícielo de la siguiente forma:

/ 

    $ python manage.py runserver

    ...\> py manage.py runserver

A continuación, abra un navegador Web y vaya a «/admin/» en su dominio local, por ejemplo, http://127.0.0.1:8000/admin/. Usted debe ver la pantalla de inicio de sesión del sitio administrativo:

Since translation is turned on by default, if you set `LANGUAGE_CODE`, the login screen will be displayed in the given language (if Django has appropriate translations).

### Acceda al sitio administrativo

Ahora, intente iniciar sesión con la cuenta de superusuario que creó en el paso anterior. Debería ver la página de índice del sitio administrativo de Django:

Usted debería ver algunos tipos de contenidos editables: grupos y usuarios. Ellos son proporcionados por `django.contrib.auth`, el framework de autenticación enviado por Django.

### Haga que la aplicación encuesta se pueda modificar en el sitio administrativo

Pero, ¿dónde está nuestra aplicación de encuesta? No se muestra en la página de índice del sitio administrativo.

Only one more thing to do: we need to tell the admin that `Question` objects have an admin interface. To do this, open the `polls/admin.py` file, and edit it to look like this:

polls/admin.py

    from django.contrib import admin

    from .models import Question

    admin.site.register(Question)

### Explore la funcionalidad gratuita del sitio administrativo

Ahora que hemos registrado el modelo `Question`, Django sabe que se debe desplegar en la página de índice del sitio administrativo:

Haga clic en «Questions». Ahora usted está en la página «lista de cambios» para las preguntas. Esta página muestra todas las preguntas de la base de datos y le permite seleccionar una para modificarla. Ahí está la pregunta «¿Qué pasa?» que creamos anteriormente:

Haga clic en la pregunta «¿Qué pasa?» para editarla:

Cosas a tener en cuenta aquí:

- El formulario se genera automáticamente a partir del modelo `Question`.
- Los diferentes tipos de campos del modelo (`DateTimeField`, `CharField`) corresponden al widget de entrada HTML adecuado. Cada tipo de campo sabe cómo mostrarse en el sitio administrativo de Django.
- Cada `DateTimeField` tiene atajos de JavaScript sin restricciónes. Las fechas tienen un atajo «Hoy» y una ventana emergente del calendario, mientras que las horas tienen un atajo «Ahora» y una ventana emergente conveniente que enumera las horas que se registran comúnmente.

La parte inferior de la página le da un par de opciones:

- Guardar – Guarda los cambios y retorna a la página de la lista de cambios para este tipo de objeto.
- Guardar y continuar editando – Guarda los cambios y recarga la página del sitio administrativo para este objeto.
- Guardar y añadir otro – Guarda los cambios y carga un nuevo formulario vacio para este tipo de objeto.
- Eliminar – Muestra una página de confirmación de eliminación.

Si el valor de «Date published» no coincide con la hora en la que creó la pregunta en el Tutorial 1, probablemente significa que se olvidó de establecer el valor correcto para la configuración de `TIME_ZONE`. Modifíquelo, recargue la página y compruebe que aparezca el valor correcto.

Modifique la «Date published» haciendo clic en los atajos «Hoy» y «Ahora». Después, haga clic en «Guardar y continuar editando». Luego haga clic en «Historial» en la parte superior derecha. Usted verá una página que enumera todos los cambios realizados a este objeto a través del sitio administrativo de Django, con el registro de tiempo y el nombre de usuario de la persona que realizó el cambio:

Cuando se sienta cómodo con la API de modelos y se haya familiarizado con el sitio administrativo, lea la parte 3 de este tutorial para aprender sobre cómo agregar más vistas a nuestra aplicación encuestas.