Introdução
Este tutorial começa onde o Creation of a Basic Poll Application parou. Vamos configurar o banco de dados, criar seu primeiro modelo e obter uma rápida introdução ao site de administração gerado automaticamente pelo Django.
Este tutorial começa onde o Creation of a Basic Poll Application parou. Vamos configurar o banco de dados, criar seu primeiro modelo e obter uma rápida introdução ao site de administração gerado automaticamente pelo Django.
Agora, abra mysite/settings.py. É um módulo Python normal com variáveis de nível de módulo que representam as configurações do Django.
Por padrão, a configuração usa SQLite. Se você é novo em bancos de dados, ou se está apenas interessado em experimentar o Django, esta é a escolha mais fácil. SQLite está incluído no Python, então você não precisará instalar mais nada para suportar seu banco de dados. Ao iniciar seu primeiro projeto real, no entanto, você pode querer usar um banco de dados mais escalável como PostgreSQL, para evitar dores de cabeça com a troca de banco de dados no futuro.
Se você deseja usar outro banco de dados, instale os database bindings <database-installation> apropriados e altere as seguintes chaves no item 'default' de DATABASES para corresponder às configurações de conexão do seu banco de dados:
ENGINE <DATABASE-ENGINE> -- Seja 'django.db.backends.sqlite3', 'django.db.backends.postgresql', 'django.db.backends.mysql', ou 'django.db.backends.oracle'. Outros backends também estão disponíveis <third-party-notes>.NAME -- O nome do seu banco de dados. Se você estiver usando SQLite, o banco de dados será um arquivo no seu computador; nesse caso, NAME deve ser o caminho absoluto completo, incluindo o nome do arquivo, desse arquivo. O valor padrão, BASE_DIR / 'db.sqlite3', armazenará o arquivo no diretório do seu projeto.Se você não estiver usando SQLite como seu banco de dados, configurações adicionais como USER, PASSWORD e HOST devem ser adicionadas. Para mais detalhes, consulte a documentação de referência para DATABASES.
Para bancos de dados diferentes de SQLite
Se você estiver usando um banco de dados além do SQLite, certifique-se de ter criado um banco de dados neste ponto. Faça isso com "CREATE DATABASE database_name;" dentro do prompt interativo do seu banco de dados.
Certifique-se também de que o usuário do banco de dados fornecido em mysite/settings.py tenha privilégios de "criar banco de dados". Isso permite a criação automática de um test database <the-test-database> que será necessário em um tutorial posterior.
Se você estiver usando SQLite, não precisa criar nada antes - o arquivo do banco de dados será criado automaticamente quando for necessário.
Enquanto você estiver editando mysite/settings.py, defina TIME_ZONE para seu fuso horário.
Além disso, observe a configuração INSTALLED_APPS no topo do arquivo. Ela contém os nomes de todos os aplicativos Django que estão ativados nesta instância do Django. Os aplicativos podem ser usados em vários projetos, e você pode empacotá-los e distribuí-los para uso por outros em seus projetos.
Por padrão, INSTALLED_APPS contém os seguintes aplicativos, todos os quais vêm com o Django:
django.contrib.admin -- O site de administração. Você o usará em breve.django.contrib.auth -- Um sistema de autenticação.django.contrib.contenttypes -- Uma estrutura para tipos de conteúdo.django.contrib.sessions -- Uma estrutura de sessão.django.contrib.messages -- Uma estrutura de mensagens.django.contrib.staticfiles -- Uma estrutura para gerenciar arquivos estáticos.Esses aplicativos são incluídos por padrão como uma conveniência para o caso comum.
Alguns desses aplicativos usam pelo menos uma tabela de banco de dados, no entanto, então precisamos criar as tabelas no banco de dados antes de podermos usá-los. Para fazer isso, execute o seguinte comando:
cd ~/project/mysite
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
O comando migrate olha para a configuração INSTALLED_APPS e cria quaisquer tabelas de banco de dados necessárias de acordo com as configurações do banco de dados em seu arquivo mysite/settings.py e as migrações do banco de dados fornecidas com o aplicativo (abordaremos isso mais tarde). Você verá uma mensagem para cada migração que ele aplicar. Se você estiver interessado, execute o cliente de linha de comando para seu banco de dados e digite \dt (PostgreSQL), SHOW TABLES; (MariaDB, MySQL), .tables (SQLite), ou SELECT TABLE_NAME FROM USER_TABLES; (Oracle) para exibir as tabelas que o Django criou.
Para os minimalistas
Como dissemos acima, os aplicativos padrão são incluídos para o caso comum, mas nem todo mundo precisa deles. Se você não precisar de nenhum ou de todos eles, sinta-se à vontade para comentar ou excluir a(s) linha(s) apropriada(s) de INSTALLED_APPS antes de executar migrate. O comando migrate só executará migrações para aplicativos em INSTALLED_APPS.
Agora, vamos definir seus modelos -- essencialmente, seu layout de banco de dados, com metadados adicionais.
Um modelo é a única fonte definitiva de informações sobre seus dados. Ele contém os campos e comportamentos essenciais dos dados que você está armazenando. Django segue o Princípio DRY <dry>. O objetivo é definir seu modelo de dados em um só lugar e derivar automaticamente as coisas dele.
Isso inclui as migrações - ao contrário do Ruby On Rails, por exemplo, as migrações são inteiramente derivadas do seu arquivo de modelos e são essencialmente um histórico que o Django pode percorrer para atualizar o esquema do seu banco de dados para corresponder aos seus modelos atuais.
Em nosso aplicativo de enquete, criaremos dois modelos: Question (Pergunta) e Choice (Escolha). Uma Question tem uma pergunta e uma data de publicação. Uma Choice tem dois campos: o texto da escolha e uma contagem de votos. Cada Choice está associada a uma Question.
Esses conceitos são representados por classes Python. Edite o arquivo polls/models.py para que ele se pareça com isto:
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)
Aqui, cada modelo é representado por uma classe que subclasse django.db.models.Model. Cada modelo tem um número de variáveis de classe, cada uma das quais representa um campo de banco de dados no modelo.
Cada campo é representado por uma instância de uma classe ~django.db.models.Field -- por exemplo, ~django.db.models.CharField para campos de caracteres e ~django.db.models.DateTimeField para datas e horários. Isso informa ao Django que tipo de dados cada campo contém.
O nome de cada instância ~django.db.models.Field (por exemplo, question_text ou pub_date) é o nome do campo, em formato amigável para a máquina. Você usará esse valor em seu código Python, e seu banco de dados o usará como o nome da coluna.
Você pode usar um primeiro argumento posicional opcional para um ~django.db.models.Field para designar um nome legível por humanos. Isso é usado em algumas partes introspectivas do Django, e funciona como documentação. Se este campo não for fornecido, o Django usará o nome legível por máquina. Neste exemplo, definimos apenas um nome legível por humanos para Question.pub_date. Para todos os outros campos neste modelo, o nome legível por máquina do campo será suficiente como seu nome legível por humanos.
Algumas classes ~django.db.models.Field têm argumentos obrigatórios. ~django.db.models.CharField, por exemplo, exige que você forneça um ~django.db.models.CharField.max_length. Isso é usado não apenas no esquema do banco de dados, mas na validação, como veremos em breve.
Um ~django.db.models.Field também pode ter vários argumentos opcionais; neste caso, definimos o valor ~django.db.models.Field.default de votes como 0.
Finalmente, observe que uma relação é definida, usando ~django.db.models.ForeignKey. Isso informa ao Django que cada Choice está relacionada a uma única Question. Django suporta todos os relacionamentos comuns de banco de dados: muitos-para-um, muitos-para-muitos e um-para-um.
Aquele pequeno trecho de código do modelo dá ao Django muita informação. Com ele, o Django é capaz de:
CREATE TABLE) para este aplicativo.Question e Choice.Mas primeiro precisamos dizer ao nosso projeto que o aplicativo polls está instalado.
Os aplicativos Django são "plugáveis": você pode usar um aplicativo em vários projetos e pode distribuir aplicativos, porque eles não precisam estar vinculados a uma determinada instalação do Django.
Para incluir o aplicativo em nosso projeto, precisamos adicionar uma referência à sua classe de configuração na configuração INSTALLED_APPS. A classe PollsConfig está no arquivo polls/apps.py, então seu caminho pontilhado é 'polls.apps.PollsConfig'. Edite o arquivo mysite/settings.py e adicione esse caminho pontilhado à configuração INSTALLED_APPS. Ele ficará assim:
INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
Agora o Django sabe para incluir o aplicativo polls. Vamos executar outro comando:
python manage.py makemigrations polls
Você deve ver algo semelhante ao seguinte:
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice
Ao executar makemigrations, você está dizendo ao Django que fez algumas alterações em seus modelos (neste caso, você fez novos) e que gostaria que as alterações fossem armazenadas como uma migration (migração).
As migrações são como o Django armazena as alterações em seus modelos (e, portanto, em seu esquema de banco de dados) - elas são arquivos em disco. Você pode ler a migração para seu novo modelo, se quiser; é o arquivo polls/migrations/0001_initial.py. Não se preocupe, não se espera que você as leia toda vez que o Django fizer uma, mas elas são projetadas para serem editáveis por humanos, caso você queira ajustar manualmente como o Django altera as coisas.
Existe um comando que executará as migrações para você e gerenciará seu esquema de banco de dados automaticamente - isso é chamado de migrate, e chegaremos a ele em um momento - mas primeiro, vamos ver qual SQL essa migração executaria. O comando sqlmigrate recebe nomes de migração e retorna seu SQL:
python manage.py sqlmigrate polls 0001
Você deve ver algo semelhante ao seguinte (reformatamos para legibilidade):
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" bigint 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;
Observe o seguinte:
polls) e o nome do modelo em letras minúsculas -- question e choice. (Você pode substituir esse comportamento.)"_id" ao nome do campo de chave estrangeira. (Sim, você também pode substituir isso.)FOREIGN KEY. Não se preocupe com as partes DEFERRABLE; ele está dizendo ao PostgreSQL para não impor a chave estrangeira até o final da transação.auto_increment (MySQL), bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (PostgreSQL) ou integer primary key autoincrement (SQLite) são tratados automaticamente para você. O mesmo vale para a citação de nomes de campos -- por exemplo, usando aspas duplas ou aspas simples.sqlmigrate na verdade não executa a migração em seu banco de dados - em vez disso, ele a imprime na tela para que você possa ver qual SQL o Django acha que é necessário. É útil para verificar o que o Django vai fazer ou se você tem administradores de banco de dados que exigem scripts SQL para alterações.Se você estiver interessado, também pode executar python manage.py check <check>; isso verifica se há algum problema em seu projeto sem fazer migrações ou tocar no banco de dados.
Agora, execute migrate novamente para criar essas tabelas de modelo em seu banco de dados:
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
O comando migrate pega todas as migrações que não foram aplicadas (o Django acompanha quais são aplicadas usando uma tabela especial em seu banco de dados chamada django_migrations) e as executa em seu banco de dados - essencialmente, sincronizando as alterações que você fez em seus modelos com o esquema no banco de dados.
As migrações são muito poderosas e permitem que você altere seus modelos ao longo do tempo, à medida que você desenvolve seu projeto, sem a necessidade de excluir seu banco de dados ou tabelas e criar novos - ele se especializa em atualizar seu banco de dados ao vivo, sem perder dados. Abordaremos isso com mais profundidade em uma parte posterior do tutorial, mas por enquanto, lembre-se do guia de três etapas para fazer alterações no modelo:
models.py).python manage.py makemigrations <makemigrations> para criar migrações para essas alteraçõespython manage.py migrate <migrate> para aplicar essas alterações ao banco de dados.A razão pela qual existem comandos separados para fazer e aplicar migrações é porque você confirmará as migrações em seu sistema de controle de versão e as enviará com seu aplicativo; elas não apenas tornam seu desenvolvimento mais fácil, mas também são utilizáveis por outros desenvolvedores e em produção.
Leia a documentação do django-admin </ref/django-admin> para obter informações completas sobre o que o utilitário manage.py pode fazer.
Agora, vamos entrar no shell interativo do Python e brincar com a API gratuita que o Django oferece. Para invocar o shell do Python, use este comando:
python manage.py shell
Estamos usando isso em vez de simplesmente digitar "python", porque manage.py define a variável de ambiente DJANGO_SETTINGS_MODULE, que fornece ao Django o caminho de importação Python para o seu arquivo mysite/settings.py.
Depois de entrar no shell, explore a API do banco de dados </topics/db/queries>:
>>> from polls.models import Choice, Question ## Importe as classes de modelo que acabamos de escrever.
## Nenhuma pergunta está no sistema ainda.
>>> Question.objects.all()
<QuerySet []>
## Crie uma nova Pergunta.
## O suporte para fusos horários está habilitado no arquivo de configurações padrão, então
## Django espera um datetime com tzinfo para pub_date. Use timezone.now()
## em vez de datetime.datetime.now() e ele fará a coisa certa.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
## Salve o objeto no banco de dados. Você deve chamar save() explicitamente.
>>> q.save()
## Agora ele tem um ID.
>>> q.id
1
## Acesse os valores dos campos do modelo via atributos Python.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2023, 9, 7, 1, 18, 48, 335644, tzinfo=datetime.timezone.utc)
## Altere os valores alterando os atributos e, em seguida, chamando save().
>>> q.question_text = "What's up?"
>>> q.save()
## objects.all() exibe todas as perguntas no banco de dados.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
Espere um minuto. <Question: Question object (1)> não é uma representação útil deste objeto. Vamos corrigir isso editando o modelo Question (no arquivo polls/models.py) e adicionando um método ~django.db.models.Model.__str__ a Question e Choice:
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
É importante adicionar métodos ~django.db.models.Model.__str__ aos seus modelos, não apenas para sua própria conveniência ao lidar com o prompt interativo, mas também porque as representações dos objetos são usadas em toda a administração gerada automaticamente do Django.
Vamos também adicionar um método personalizado a este modelo:
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)
Observe a adição de import datetime e from django.utils import timezone, para referenciar o módulo datetime padrão do Python e os utilitários relacionados ao fuso horário do Django em django.utils.timezone, respectivamente. Se você não estiver familiarizado com o tratamento de fuso horário no Python, pode aprender mais nos documentos de suporte ao fuso horário </topics/i18n/timezones>.
Salve essas alterações e inicie um novo shell interativo do Python executando python manage.py shell novamente:
>>> from polls.models import Choice, Question
## Certifique-se de que nossa adição __str__() funcionou.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
## Django fornece uma rica API de pesquisa de banco de dados que é totalmente impulsionada por
## argumentos de palavra-chave.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith="What")
<QuerySet [<Question: What's up?>]>
## Obtenha a pergunta que foi publicada este ano.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
## Solicite um ID que não existe, isso levantará uma exceção.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
## A pesquisa por uma chave primária é o caso mais comum, então o Django fornece um
## atalho para pesquisas exatas de chave primária.
## O seguinte é idêntico a Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>
## Certifique-se de que nosso método personalizado funcionou.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
## Dê à Pergunta algumas Escolhas. A chamada create constrói um novo
## Objeto Choice, faz a instrução INSERT, adiciona a escolha ao conjunto
## de escolhas disponíveis e retorna o novo objeto Choice. Django cria
## um conjunto para conter o "outro lado" de uma relação ForeignKey
## (por exemplo, a escolha de uma pergunta) que pode ser acessada via API.
>>> q = Question.objects.get(pk=1)
## Exiba quaisquer escolhas do conjunto de objetos relacionados -- nenhum até agora.
>>> q.choice_set.all()
<QuerySet []>
## Crie três escolhas.
>>> 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)
## Os objetos Choice têm acesso à API aos seus objetos Question relacionados.
>>> c.question
<Question: What's up?>
## E vice-versa: os objetos Question obtêm acesso aos objetos Choice.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
## A API segue automaticamente as relações até onde você precisa.
## Use sublinhados duplos para separar relacionamentos.
## Isso funciona em quantos níveis você quiser; não há limite.
## Encontre todas as Escolhas para qualquer pergunta cuja pub_date esteja neste ano
## (reutilizando a variável 'current_year' que criamos acima).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
## Vamos excluir uma das escolhas. Use delete() para isso.
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()
Para obter mais informações sobre as relações de modelo, consulte Acessando objetos relacionados </ref/models/relations>. Para obter mais informações sobre como usar sublinhados duplos para realizar pesquisas de campo via API, consulte Pesquisas de campo <field-lookups-intro>. Para obter detalhes completos sobre a API do banco de dados, consulte nossa referência da API do banco de dados </topics/db/queries>.
Gerar sites de administração para sua equipe ou clientes adicionarem, alterarem e excluírem conteúdo é um trabalho tedioso que não requer muita criatividade. Por essa razão, o Django automatiza totalmente a criação de interfaces de administração para modelos.
O Django foi escrito em um ambiente de redação, com uma separação muito clara entre "editores de conteúdo" e o site "público". Os gerentes de site usam o sistema para adicionar notícias, eventos, placares esportivos, etc., e esse conteúdo é exibido no site público. O Django resolve o problema de criar uma interface unificada para os administradores do site editarem o conteúdo.
O admin não se destina a ser usado pelos visitantes do site. É para gerentes de site.
Primeiro, precisaremos criar um usuário que possa fazer login no site de administração. Execute o seguinte comando:
python manage.py createsuperuser
Digite o nome de usuário desejado e pressione Enter.
Username: admin
Você será solicitado a inserir o endereço de e-mail desejado:
Email address: admin@example.com
A etapa final é inserir sua senha. Você será solicitado a inserir sua senha duas vezes, a segunda vez como uma confirmação da primeira.
Password: 12345678
Password (again): 12345678
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
O site de administração do Django é ativado por padrão. Vamos iniciar o servidor de desenvolvimento e explorá-lo.
Se o servidor não estiver em execução, inicie-o assim:
python manage.py runserver
Agora, abra um navegador da web na guia VNC e vá para "/admin/" em seu domínio local -- por exemplo, http://127.0.0.1:8000/admin/. Você deve ver a tela de login do admin:

Como a tradução </topics/i18n/translation> está ativada por padrão, se você definir LANGUAGE_CODE, a tela de login será exibida no idioma fornecido (se o Django tiver as traduções apropriadas).
Agora, tente fazer login com a conta de superusuário que você criou na etapa anterior. Você deve ver a página de índice do Django admin:

Você deve ver alguns tipos de conteúdo editável: grupos e usuários. Eles são fornecidos por django.contrib.auth, a estrutura de autenticação fornecida pelo Django.
Mas onde está nosso aplicativo de pesquisa? Ele não é exibido na página de índice do admin.
Só falta mais uma coisa: precisamos dizer ao admin que os objetos Question têm uma interface de administração. Para fazer isso, abra o arquivo polls/admin.py e edite-o para que fique assim:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
Agora que registramos Question, o Django sabe que ele deve ser exibido na página de índice do admin:

Clique em "Questions". Agora você está na página "change list" (lista de alterações) para perguntas. Esta página exibe todas as perguntas no banco de dados e permite que você escolha uma para alterá-la. Existe a pergunta "What's up?" que criamos anteriormente:

Clique na pergunta "What's up?" para editá-la:

Coisas a serem observadas aqui:
Question.~django.db.models.DateTimeField, ~django.db.models.CharField) correspondem ao widget de entrada HTML apropriado. Cada tipo de campo sabe como se exibir no Django admin.~django.db.models.DateTimeField recebe atalhos JavaScript gratuitos. As datas recebem um atalho "Today" (Hoje) e um popup de calendário, e os horários recebem um atalho "Now" (Agora) e um popup conveniente que lista os horários comumente inseridos.A parte inferior da página oferece algumas opções:
Se o valor de "Date published" (Data de publicação) não corresponder ao horário em que você criou a pergunta em Criação de um aplicativo de pesquisa básico, provavelmente significa que você esqueceu de definir o valor correto para a configuração TIME_ZONE. Altere-o, recarregue a página e verifique se o valor correto aparece.
Altere a "Date published" (Data de publicação) clicando nos atalhos "Today" (Hoje) e "Now" (Agora). Em seguida, clique em "Save and continue editing" (Salvar e continuar editando). Em seguida, clique em "History" (Histórico) no canto superior direito. Você verá uma página listando todas as alterações feitas neste objeto via Django admin, com o carimbo de data/hora e o nome de usuário da pessoa que fez a alteração:

Quando você estiver confortável com a API de modelos e se familiarizou com o site de administração, leia Criando as visualizações da interface pública para aprender como adicionar mais visualizações ao nosso aplicativo de pesquisa.
Parabéns! Você concluiu o laboratório Configurar o Banco de Dados. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.