Escrevendo sua primeira aplicação Django, parte 1

Vamos aprender através de um exemplo.

Ao longo deste tutorial nós iremos guiá-lo na criação de uma aplicação básica de enquete.

Ela consistirá em duas partes:

  • Um site público em que as pessoas poderão visualizar e votar em enquetes.
  • Um site de administração que você poderá adicionar, alterar e deletar enquetes.

Iremos assumir que você já possui o Django instalado. Você pode saber se o Django está instalado rodando o interpretador interativo do Python e digitando import django. Se esse comando rodar com sucesso, sem nenhum erro, o Django está instalado.

Onde conseguir ajuda:

Se você estiver tendo problemas no decorrer desse tutorial, por favor envie uma mensagem para a django-brasil ou para a django-users (em inglês) ou deixe-a em #django-br ou #django no irc.freenode.net para bater-papo com outros usuários Django dispostos a ajudar.

Criando um projeto

Se esta é a primeira vez em que você está utilizando o Django, você terá que preocupar-se com algumas configurações iniciais. Isto é, você precisará auto-gerar um código para iniciar um projeto Django – uma coleção de configurações para uma instância do Django, incluindo configuração do banco de dados, opções específicas do Django e configurações específicas da aplicação.

A partir da linha de comando, cd para o diretório onde você gostaria de armazenar seu código, então execute o comando django-admin.py startproject mysite. Isto irá criar o diretório mysite no seu diretório atual.

Permissões do Mac OS X

Se você estiver usando Mac OS X, você poderá ver a mensagem “permissão negada” quando você tentar rodar o django-admin.py startproject. Isto porque, em sistemas baseados em Unix como o OS X, um arquivo precisa ser marcado como “executável” antes que possa ser executado como um programa. Para fazer isso, abra o Terminal.app e navegue (usando o comando cd) até o diretório onde o django-admin.py está instalado, então rode o comando chmod +x django-admin.py.

Note

Você precisará evitar dar nomes a projetos que remetam a componentes internos do Python ou do Django. Particularmente, isso significa que você deve evitar usar nomes como django (que irá conflitar com o próprio Django) ou test (que irá conflitar com um pacote interno do Python).

O django-admin.py deverá estar no “path” do sistema se você instalou o Django via python setup.py. Se ele não estiver no path, você poderá encontrá-lo em site-packages/django/bin, onde site-packages é um diretório dentro da sua instalação do Python. Considere a possibilidade de criar um link simbólico para o django-admin.py em algum lugar em seu path, como em /usr/local/bin.

Onde esse código deve ficar?

Se você tem experiência prévia em PHP, você deve estar acostumado a colocar o código dentro do “document root” de seu servidor Web (em um lugar como /var/www). Com o Django você não fará isto. Não é uma boa idéia colocar qualquer código Python no document root de seu servidor Web, porque existe o risco de pessoas conseguirem ver seu código através da Web. Isso não é bom para a segurança.

Coloque seu código em algum diretório fora do document root, como em /home/mycode.

Vamos olhar o que o startproject criou:

mysite/
    __init__.py
    manage.py
    settings.py
    urls.py

Estes arquivos são:

  • __init__.py: Um arquivo vazio que diz ao Python que esse diretório deve ser considerado como um pacote Python. (Leia mais sobre pacotes na documentação oficial do Python se você for iniciante em Python.)
  • manage.py: Um utilitário de linha de comando que permite a você interagir com esse projeto Django de várias maneiras. Você pode ler todos os detalhes sobre o manage.py em django-admin.py e manage.py.
  • settings.py: Configurações para este projeto Django. Django settings Irá revelar para você tudo sobre como o settings funciona.
  • urls.py: As declarações de URLs para este projeto Django; um “índice” de seu site movido a Django. Você pode ler mais sobre URLs em URL dispatcher.

O servidor de desenvolvimento

Vamos verificar se ele funciona. Vá para o diretório mysite, se você ainda não estiver nele, e rode o comando python manage.py runserver. Você irá ver a seguinte saída na sua linha de comando:

Validating models...
0 errors found.

Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Você iniciou o servidor de desenvolvimento do Django, um servidor Web leve escrito puramente em Python. Nós incluímos ele com o Django, então você pode desenvolver coisas rapidamente, sem ter que lidar com a configuração de um servidor Web de produção – como o Apache – até que você esteja pronto para a produção.

Agora é uma boa hora para anotar: NÃO use esse servidor em nada relacionado a um ambiente de produção. Seu objetivo é ser utilizado apenas durante o desenvolvimento. (Nós estamos na atividade de criação de frameworks Web, não de servidores Web.)

Agora que o servidor está rodando, visite http://127.0.0.1:8000/ com seu navegador Web. Você irá ver a página “Welcome to Django”, em agradáveis tons de azul claro pastel. Ele funcionou!

Mudando a porta

Por padrão, o comando runserver inicia o servidor de desenvolvimento no IP interno na porta 8000.

Se você quer mudar a porta do servidor, passe ela como um argumento na linha de comando. Por exemplo, este comando iniciará o servidor na porta 8080:

python manage.py runserver 8080

Se você quer mudar o IP do servidor, passe-o junto com a porta. Para então escutar em todos os IPs públicos (útil se você quer mostrar seu trabalho em outros computadores), use:

python manage.py runserver 0.0.0.0:8000

A documentação completa para o servidor de desenvolvimento está na referência runserver.

Configuração do banco de dados

Agora, edite o settings.py. Ele é um módulo normal do Python com variáveis representando as configurações do Django. Altere essas configurações para que atendam aos parâmetros de conexão do seu banco de dados:

  • DATABASE_ENGINE – Um entre ‘postgresql_psycopg2’, ‘mysql’ ou ‘sqlite3’. Outros backends também estão disponíveis.

  • DATABASE_NAME – O nome do seu banco de dados, se você estiver usando SQLite, o banco de dados será uma arquivo no seu computador; neste caso, DATABASE_NAME deve ser o caminho completo, incluindo o nome, para este arquivo. Se este arquivo não existir, ele sera automaticamente criado quando você sincronizar o banco de dados pela primeira vez (veja abaixo).

    Quando estiver especificando o caminho, sempre use a barra normal até mesmo no Windows (e.g. C:/homes/user/mysite/sqlite3.db).

  • DATABASE_USER – Usuário do seu banco de dados (não utilizado para o SQLite).

  • DATABASE_PASSWORD – Senha do seu banco de dados (não utilizado para o SQLite).

  • DATABASE_HOST – O host onde seu banco de dados está. Deixe isso em branco se o seu servidor de banco de dados está na mesma máquina física (não utilizado para o SQLite).

Se você é novo em banco de dados, nós recomendamos simplesmente utilizar o SQLite (configurando DATABASE_ENGINE para 'sqlite3'). SQLite é incluído como parte do Python 2.5 e posterior, então você não precisará instalar qualquer outra coisa.

Nota

Se você estiver utilizando PostgreSQL ou MySQL, certifique-se de que já tenha criado o banco de dados a partir deste ponto. Faça isso com “CREATE DATABASE database_name;” no prompt interativo do seu banco de dados.

Se você está utilizando SQLite você não precisa criar nada de antemão - o arquivo do banco de dados será criado automaticamente quando ele for necessário.

Enquanto edita o settings.py, observe a configuração do INSTALLED_APPS próximo ao final do arquivo. Ela possui os nomes de todas as aplicações Django ativas para essa instância do Django. Aplicações podem ser usadas em múltiplos projetos, e você pode empacotá-las e distribuí-las para uso por outros em seus projetos.

Por padrão, o INSTALLED_APPS contém as seguintes aplicações, que vêm com o Django:

Essas aplicações são incluídas por padrão como uma conveniência para os casos comuns.

Cada uma dessas aplicações faz uso de pelo menos uma tabela no banco de dados, assim sendo, nós precisamos criar as tabelas no banco de dados antes que possamos utilizá-las. Para isso rode o seguinte comando:

python manage.py syncdb

O comando syncdb verifica a configuração em INSTALLED_APPS e cria todas as tabelas necessárias de acordo com a configuração do banco de dados em seu arquivo settings.py. Você irá ver uma mensagem para cada tabela do banco de dados que ele criar, e você irá receber um prompt perguntando se gostaria de criar uma conta de super-usuário para o sistema de autenticação. Vá em frente e faça isso.

Se você estiver interessado, rode o cliente de linha de comando do seu banco de dados e digite \dt (PostgreSQL), SHOW TABLES; (MySQL), ou .schema (SQLite) para mostrar as tabelas que o Django criou.

Para os minimalistas

Como dissemos acima, as aplicações padrão são incluídas para casos comuns, mas nem todo mundo precisa delas. Se você não precisa de nenhuma delas, sinta-se livre para comentar ou deletar a(s) linha(s) apropriadas do INSTALLED_APPS antes de rodar o syncdb. O comando syncdb irá criar apenas as tabelas para as aplicações que estiverem no INSTALLED_APPS.

Criando models

Agora que seu ambiente – um “projeto” – está configurado, você está pronto para começar o trabalho.

Cada aplicação que você escreve no Django consiste de um pacote Python, em algum lugar no path do Python, que seguirá uma certa convenção. O Django vem com um utilitário que gera automaticamente a estrutura básica de diretório de uma aplicação, então você pode se concentrar apenas em escrever código em vez de ficar criando diretórios.

Projetos vs. aplicações

Qual é a diferença entre um projeto e uma aplicação? Uma aplicação é uma aplicação Web que faz alguma coisa – ex., um sistema de blog, um banco de dados de registros públicos ou uma simples aplicação de enquete. Um projeto é uma coleção de configurações e aplicações para um determinado Web site. Um projeto pode conter múltiplas aplicações. Uma aplicação pode estar em múltiplos projetos.

Neste tutorial nós iremos criar nossa aplicação de enquete no diretório mysite, por simplicidade. Conseqüentemente, a aplicação irá ser acoplada ao projeto – no caso, o código Python da aplicação de enquete irá se referir a mysite.polls. Posteriormente, neste tutorial, nós iremos discutir como desacoplar suas aplicações para serem distribuídas.

Para criar sua aplicação, certifique-se de que esteja no diretório mysite e digite o seguinte comando:

python manage.py startapp polls

Que irá criar o diretório polls com a seguinte estrutura:

polls/
    __init__.py
    models.py
    views.py

Esta estrutura de diretório irá abrigar a aplicação de enquete.

O primeiro passo ao escrever um banco de dados de uma aplicação Web no Django é definir seus models – essencialmente, o layout do banco de dados, com metadados adicionais.

Filosofia

Um model é a única e definitiva fonte de dados sobre seus dados. Ele contém os campos essenciais e os comportamentos para os dados que você estiver armazenando. O Django segue o princípio DRY. O objetivo é definir seu modelo de dados em um único local e automaticamente derivar coisas a partir dele.

Em nossa simples aplicação de enquete, nós iremos criar dois models: polls e choices. Uma enquete (poll) tem uma pergunta e uma data de publicação. Uma escolha (choice) tem dois campos: o texto da escolha e um totalizador de votos. Cada escolha é associada a uma enquete.

Esses conceitos são representados por simples classes Python. Edite o arquivo polls/models.py de modo que fique assim:

from django.db import models

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

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()

Erros sobre max_length

Se o Django retornar para você uma mensagem de erro dizendo que o max_length não é um argumento válido, você provavelmente está usando uma versão antiga do Django. (Esta versão do tutorial foi escrita para a última versão de desenvolvimento do Django.) Se você estiver usando um checkout de Subversion da versão de desenvolvimento do Django (veja a documentação de instalação para mais informações), você não deveria estar tendo nenhum problema.

Se você quiser continuar com uma versão antiga do Django, você deverá mudar para o tutorial do Django 0.96, porque este tutorial cobre vários recursos que só existem na versão de desenvolvimento do Django.

O código é auto-explicativo. Cada model é representado por uma classe derivada da classe django.db.models.Model. Cada model possui um número de atributos de classe, as quais por sua vez representam campos de banco de dados no model.

Cada campo é representado por uma instância de uma classe Field – e.g., CharField para campos do tipo caractere e DateTimeField para data/hora. Isto diz ao Django qual tipo de dado cada campo contém.

O nome de cada instância Field (e.g. question ou pub_date) é o nome do campo, em formato amigável para a máquina. Você irá usar este valor no seu código Python, e seu banco de dados irá usá-lo como nome de coluna.

Você pode usar um argumento opcional na primeira posição de um Field para designar um nome legível por seres humanos o qual será usado em uma série de partes introspectivas do Django, e também servirá como documentação. Se esse argumento não for fornecido, o Django utilizará o nome legível pela máquina. Neste exemplo nós definimos um nome legível por humanos apenas para Poll.pub_date. Para todos os outros campos neste model, o nome legível pela máquina será utilizado como nome legível por humanos.

Algumas classes Field possuem elementos obrigatórios. O CharField, por exemplo, requer que você informe a ele um max_length que é usado não apenas no esquema do banco de dados, mas na validação, como nós veremos em breve.

Finalmente, note a definição de um relacionamento, usando ForeignKey, que diz ao Django que cada Choice (Escolha) está relacionada a uma única Poll (Enquete). O Django suporta todos os relacionamentos de banco de dados comuns: muitos-para-um, muitos-para-muitos e um-para-um.

Ativando os models

Aquela pequena parte do model fornece ao Django muita informação. Com ela o Django é capaz de:

  • Criar um esquema de banco de dados (instruções CREATE TABLE) para a aplicação.
  • Criar uma API de acesso a banco de dados para acessar objetos Poll e Choice.

Mas primeiro nós precisamos dizer ao nosso projeto que a aplicação polls está instalada.

Filosofia

Aplicações Django são “plugáveis”: Você pode usar uma aplicação em múltiplos projetos, e você pode distribuir aplicações, porque elas não precisam ser atreladas a uma determinada instalação do Django.

Edite o arquivo settings.py novamente e altere o valor de INSTALLED_APPS para incluir 'mysite.polls' de modo que se pareça com isso:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'mysite.polls'
)

Agora o Django sabe que o mysite inclui a aplicação polls. Vamos rodar outro comando:

python manage.py sql polls

Você deverá ver algo similar ao seguinte (as instruções SQL CREATE TABLE` para a aplicação de enquetes):

BEGIN;
CREATE TABLE "polls_poll" (
    "id" serial NOT NULL PRIMARY KEY,
    "question" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
    "choice" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
COMMIT;

Note o seguinte:

  • A saída exata irá variar dependendo do banco de dados que você está utilizando.
  • Os nomes das tabelas são gerados automaticamente combinando o nome da aplicação (polls) e o nome em minúsculas do model – poll e choice. (Você pode alterar esse comportamento.)
  • Chaves primárias (id’s) são adicionadas automaticamente. (Você também pode modificar isso.)
  • Por convenção, o Django adiciona "_id" ao nome do campo de uma chave estrangeira. Sim, você pode alterar isso, como quiser.
  • O relacionamento da chave estrangeira é feito explicitamente por uma instrução REFERENCES.
  • Isto é atrelado ao banco que você está usando, então a utilização de campos específicos do banco de dados como auto_increment (MySQL), serial (PostgreSQL), ou integer primary key (SQLite) é feita para você automaticamente. O mesmo ocorre com as aspas dos nomes de campos – e.g., usando aspas duplas ou aspas simples. O autor deste tutorial roda PostgreSQL, então a saída do exemplo está na sintaxe do PostgreSQL.
  • O comando sql na realidade não roda o SQL no seu banco de dados - ele apenas o exibe na tela para que você saiba qual SQL o Django acha que é necessário. Se você quiser, você pode copiar e colar esse SQL no prompt do seu banco de dados. Entretanto, como nós iremos ver em breve, o Django fornece uma maneira mais fácil de submeter o SQL ao banco de dados.

Se tiver interesse, rode também os seguintes comandos:

  • python manage.py validate – Verifica por quaisquer erros na construção dos seus models.
  • python manage.py sqlcustom polls – Mostra quaisquer instruções SQL personalizadas (como modificações em tabelas ou restricoes) que tenham sido definidas para a aplicação.
  • python manage.py sqlclear polls – Mostra as instruções DROP TABLE necessárias para a aplicação, de acordo com as tabelas que já existem no seu banco de dados (se houver alguma).
  • python manage.py sqlindexes polls – Mostra as instruções CREATE INDEX necessárias para a aplicação.
  • python manage.py sqlall polls – Uma combinação de todo SQL dos comandos sql, sqlcustom, e sqlindexes.

Olhar para a saída desses comandos irá ajudar a entender o que está acontecendo por baixo dos panos.

Agora rode o syncdb novamente para criar essas tabelas dos models no seu banco de dados:

python manage.py syncdb

O comando syncdb roda o SQL do ‘sqlall’ em seu banco de dados para todas as aplicações presentes no INSTALLED_APPS que ainda não existam em seu banco de dados. Isso criará todas as tabelas, dados iniciais e índices para quaisquer aplicações que você tenha adicionado ao seu projeto desde a última vez que você rodou o syncdb. O syncdb pode ser chamado sempre que você quiser, e ele irá apenas criar as tabelas que não existirem.

Leia a documentação do django-admin.py para informações completas sobre o que o utilitário manage.py pode fazer.

Brincando com a API

Agora vamos dar uma passada no shell interativo do Python e brincar um pouco com a API livre que o Django dá a você. Para invocar o shell do Python, use esse comando:

python manage.py shell

Nós usaremos isso em vez de simplesmente digitar “python”, porque o manage.py configura o ambiente de projeto para você. A “configuração do ambiente” envolve duas coisas:

  • Colocar o mysite no sys.path. Buscando flexibilidade, várias partes do Django referem-se aos projetos usando a notação de caminho pontuado (dotted-path) do Python (e.g. 'mysite.polls.models'). Para que isso funcione, o pacote mysite precisa estar no sys.path.

    Nós já vimos um exemplo disso: a configuração INSTALLED_APPS é uma lista de pacotes na notação de caminho pontuado.

  • Configurar a variável de ambiente DJANGO_SETTINGS_MODULE, que fornece ao Django o caminho para o seu arquivo settings.py.

Ignorando o manage.py

Se você optar por não usar o manage.py, não há problemas. Apenas certifique-se de que o mysite está no nível raíz do caminho do Python (i.e., import mysite funciona) e configure a variável de ambiente DJANGO_SETTINGS_MODULE para mysite.settings.

Para mais informações sobre isso tudo, veja a documentação do django-admin.py.

Assim que você estiver no shell, explore a API de banco de dados:

# Importe as classes de model que acabamos de criar.
>>> from mysite.polls.models import Poll, Choice

# Não há nenhuma enquete no sistema ainda.
>>> Poll.objects.all()
[]

# Crie uma nova enquete.
>>> import datetime
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())

# Salve o objeto na base de dados. Você tem que chamar o save() explicitamente.
>>> p.save()

# Agora ele tem uma ID. Note que ele irá mostrar "1L" em vez de "1",
# dependendo de qual banco de dados você está usando. Não é nada demais; isso
# apenas significa que o backend do seu banco de dados prefere retornar
# inteiros como objetos long integers do Python.
>>> p.id
1

# Acesse colunas do banco de dados via atributos do Python.
>>> p.question
"What's up?"
>>> p.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53)

# Modifique os valores alterando os atributos e depois chamando o save()..
>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
>>> p.save()

# objects.all() mostra todas as enquetes do banco de dados..
>>> Poll.objects.all()
[<Poll: Poll object>]

Espere um pouco. <Poll: Poll object> é uma representação totalmente inútil desse objeto. Vamos corrigir isso editando o model da enquete (no arquivo polls/models.py) e adicionando um método __unicode__() a ambos Poll e Choice:

class Poll(models.Model):
    # ...
    def __unicode__(self):
        return self.question

class Choice(models.Model):
    # ...
    def __unicode__(self):
        return self.choice

Se __unicode__() não parecer funcionar

Se você adicionar o método __unicode__() aos seus models e não observar nenhuma mudança na forma com que eles são representados, você deve estar usando uma versão antiga do Django (esta versão do tutorial foi escrita para a última versão de desenvolvimento do Django). Se você estiver usando um checkout do Subversion do Django (veja a documentação de instalação para mais informações), você não deveria estar tendo nenhum problema.

Se você quiser seguir com uma versão antiga do Django, você deverá mudar para o tutorial do Django 0.96, porque este tutorial cobre vários recursos que existem apenas na versão de desenvolvimento do Django.

É importante adicionar métodos __unicode__() aos seus models, não apenas para sua própria sanidade quando estiver lidando com o prompt interativo, mas também porque representações de objetos são usadas em toda a administração gerada automaticamente pelo Django.

Por que __unicode__() e não __str__()?

Se você está familiarizado com o Python, você deve ter o hábito de adicionar métodos __str__() às suas classes, não métodos __unicode__(). Nós usamos __unicode__() aqui porque os models do Django lidam com Unicode por padrão. Todos os dados armazenados nos seus bancos de dados são convertidos para Unicode quando são retornados.

Os models do Django têm um método padrão __str__() que chama o __unicode__() e converte os resultados para uma bytestring UTF-8. Isso significa que unicode(p) irá retornar uma string Unicode, e que str(p) irá retornar uma string normal, com caracteres codificados como UTF-8.

Se tudo isso é grego para você, apenas lembre-se de adicionar métodos __unicode__() aos seus models. Com alguma sorte, as coisas deverão simplesmente funcionar para você.

Note que esses são métodos Python normais. Vamos adicionar um método personalizado, apenas por demonstração:

import datetime
# ...
class Poll(models.Model):
    # ...
    def was_published_today(self):
        return self.pub_date.date() == datetime.date.today()

Note a adição de import datetime para referenciar o módulo padrão do Python datetime.

Salve essas mudanças e vamos iniciar uma nova sessão do shell interativo do Python rodando python manage.py shell novamente:

>>> from mysite.polls.models import Poll, Choice

# Certifique-se de que a sua adição do __unicode__() funcionou.
>>> Poll.objects.all()
[<Poll: What's up?>]

# O Django fornece uma rica API de procura em banco de dados inteiramente
# controlada por argumentos formados por palavras-chave.
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]

# Pegue a enquete cujo ano é 2007. Claro que se você estiver seguindo este
# tutorial em outro ano, altere como for apropriado.
>>> Poll.objects.get(pub_date__year=2007)
<Poll: What's up?>

>>> Poll.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Poll matching query does not exist.

# Buscar por uma chave primária é o caso mais comum, então o Django fornece
# um atalho para buscas por chaves primárias específicas.
# O que se segue é idêntido a Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
<Poll: What's up?>

# Certifique-se de que o método personalizado funcionou.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_today()
False

# Dê à Poll algumas Choices. A chamada create constrói um novo objeto
# choice, executa a instrução INSERT, adiciona a choice ao conjunto de
# choices disponíveis e retorna o novo objeto choice.
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.create(choice='Not much', votes=0)
<Choice: Not much>
>>> p.choice_set.create(choice='The sky', votes=0)
<Choice: The sky>
>>> c = p.choice_set.create(choice='Just hacking again', votes=0)

# Objetos Choice possuem acesso via API aos seus objetos Poll relacionados.
>>> c.poll
<Poll: What's up?>

# E vice-versa: Objetos Poll possuem acesso aos objetos Choice.
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3

# A API segue automaticamente os relacionamentos da forma como você precisa.
# Use underscores duplos para separar relacionamentos.
# Isso funciona a tantos níveis abaixo quanto precisar; não há limite.
# Encontre todas as opções para uma enquete cuja data de publicação for de
# 2007.
>>> Choice.objects.filter(poll__pub_date__year=2007)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Vamos apagar uma das escolhas. Use delete() para isso.
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()

Para um detalhamento completo da API de banco de dados, veja nossa referência à API de Banco de Dados.

Quando você se sentir confortável com a API, leia a parte 2 deste tutorial para colocar a administração automática do Django em funcionamento.