Models¶
Um modelo é a fonte única e definitiva de dados sobre os seus dados. Ele contém os campos e comportamentos essenciais dos dados que você está gravando. Geralmente, cada modelo mapeia para uma única tabela no banco de dados.
O básico:
- Cada modelo é uma classe Python que extende
django.db.models.Model
. - Cada atributo do modelo representa uma coluna do banco de dados.
- Com tudo isso, o Django lhe dá uma API de acesso a banco de dados gerada automaticamente, o que é explicado em Fazendo consultas.
See also
Um companheiro para esse documento é o repositório oficial de exemplos de
modelo. (Na distribuição do fonte do Django, esses exemplos estão no
diretório tests/modeltests
.)
Exemplo rápido¶
Esse modelo de exemplo define uma Person
, que tem um first_name
e um
last_name
:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name
e last_name
são campos do modelo. Cada campo é especificado
como um atributo de classe, e cada atributo é mapeado para uma coluna no banco
de dados.
O modelo Person
acima criaria uma tabela assim:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
Algumas notas técnicas:
- O nome da tabela,
myapp_person
, é automaticamente derivado de alguns metadados do modelo, no entanto isto pode ser sobrescrito. Veja Nomes de tabelas abaixo. - Um campo
id
é adicionado automaticamente, mas esse comportamento também pode ser alterado. Veja Campos de chave primária automáticos abaixo. - O comando SQL
CREATE TABLE
nesse exemplo é formatado usando a sintaxe do PostgreSQL, mas é digno de nota que o Django usa o SQL adaptado ao banco de dados especificado no seu arquivo de configurações.
Usando models¶
Uma vez que já tenha criado seus modelos, o passo final é dizer ao Django para
usar estes modelos. Para isto, basta editar seu arquivo settings.py e mudar o
INSTALLED_APPS
adicionando o nome do módulo que contém seu
models.py
.
Por exemplo, se os modelos de sua aplicação ficam no módulo
mysite.myapp.models
(a estrutura de pacote que é criada para uma aplicação
pelo script manage.py startapp
), o
INSTALLED_APPS
deve ler, em parte:
INSTALLED_APPS = (
#...
'mysite.myapp',
#...
)
Quando você adicionar novas aplicações ao INSTALLED_APPS
, assegure-se
de rodar o manage.py syncdb
.
Campos¶
A parte mais importante do modelo – e a única obrigatória – é a lista de campos do banco de dados que ele define. Campos são especificados por meio de atributos de classe.
Exemplo:
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
Tipos de campos¶
Cada campo no seu modelo deve ser uma instância da classe
Field
apropriada. O Django usa os tipos das classes
para determinar algumas coisas:
- O tipo de coluna no banco de dados (ex:
INTEGER
,VARCHAR
). - O widget a ser usado na interface administrativa do Django, se você a
utilizar (ex:
<input type="text">
,<select>
). - Os requisitos mínimos para validação, usados no site de administração do Django e nos formulários automaticamente gerados.
O Django é disponibilizado com dezenas de tipos de campos embutidos; você pode encontrar a lista completa em referência de campos do model. Você também pode facilmente escrever seus próprios tipos de campos se os que acompanham o Django não lhe servirem; veja Writing custom model fields.
Field options¶
Cada tipo de campo recebe um certo conjunto de argumentos específicos
(documentados na referência de campos de model). Por
exemplo, CharField
(e suas subclasses) requerem um
argumento max_length
que especifica o
tamanho do campos VARCHAR
que será usado para armazenar os dados.
Também há um conjunto de argumentos comuns disponíveis para todos os tipos de campos. todos são opicionais. Eles são totalmente explicados na refeência, mas aqui há um pequeno sumário dos mais frequentemente usados:
null
- Se
True
, o Django irá gravar valores vazios comoNULL
no banco de dados. O padrão éFalse
. blank
Se
True
, o campo pode ser vazio. o padrão éFalse
.Note que isso é diferente de
null
.null
é puramente relacionado ao banco de dados, eblank
é relacionado com validação. Se um campo temblank=True
, a validação na administração do Django irá permitir a entrada de um valor vazio. Se um campo temblank=False
, o campo será obrigatório.choices
Um iterável(e.g., uma lista ou tupla) de tupla duplas para usar como escolhas para esse campo. Se fornecido, a administração do Django usará uma caixa de seleção no lugar de um campo de texto padrão e irá limitar as escolhas as opções dadas.
Uma lista de opções é parece com isso:
YEAR_IN_SCHOOL_CHOICES = ( (u'FR', u'Freshman'), (u'SO', u'Sophomore'), (u'JR', u'Junior'), (u'SR', u'Senior'), (u'GR', u'Graduate'), )
O primeiro elemeno de cada tupla é o verdadeiro valor a ser gravado. O segundo elemento será mostrado pela interface de adminsitração, ou em um ModelChoiceField. Dada uma instância de um objeto de model, o valor mostrado pelo campo choices pode ser acessado usando o método
get_FOO_display
. Por exemplo:from django.db import models class Person(models.Model): GENDER_CHOICES = ( (u'M', u'Male'), (u'F', u'Female'), ) name = models.CharField(max_length=60) gender = models.CharField(max_length=2, choices=GENDER_CHOICES)
>>> p = Person(name="Fred Flinstone", gender="M") >>> p.save() >>> p.gender u'M' >>> p.get_gender_display() u'Male'
default
- O valor padrão para o campo. Pode ser também um objeto chamável. Se for um chamável, será chamado a cada vez que um novo objeto for criado.
help_text
- Um texto de “ajuda” extra para ser mostrado sob o campo no formulário de objetos do admin. É útil para documentação, mesmo que seu objeto não tenha um formulário administrativo.
primary_key
Se
True
, esse campo será a chave primária para o modelo.Se você não especificar
primary_key=True <Field.primary_key>`
para nenhum campo no seu modelo, o Django adicionará automaticamente um campoIntegerField
para ser a chave primária, desta forma, você não precisa configurar oprimary_key=True <Field.primary_key>`
em qualquer um dos seus campos a menos que você queira sobrescrever o comportamento padrão de chaves primárias. Para saber mais, Campos de chave primária automáticos.unique
- Se
True
, esse campo deve ser único na tabela.
Novamente, estes são somente descrições curtas das opções mais comuns dos campos. Detalhes completos podem ser encontrados na referência de opções dos campos comuns do model.
Campos de chave primária automáticos¶
Por padrão, o Django dá a cada model o seguinte campo:
id = models.AutoField(primary_key=True)
Esta é uma chave primária auto incremental.
Se você gostaria de especificar uma chave primária customizada, somente
especifique primary_key=True
em um dos seus campos.
Se o Django ver que você especificou uma :attr:Field.primary_key`, ele não
adicionará a coluna id
automaticamente.
Cada model requer que exatamente um campo tenha primary_key=True
.
Nomes de campos por extenso¶
Cada tipo de campo, exceto ForeignKey
,
ManyToManyField
e
OneToOneField
, recebem um primeiro argumento
opcional – um nome por extenso. Se o nome por extenso não é informado, o Django
criará automaticamente a partir do atributo name do campo, convertendo
underscores em espaços.
Nesse exemplo, o nome por extenso é "Person's first name"
:
first_name = models.CharField("Person's first name", max_length=30)
Nesse exemplo, o nome por extenso é "first name"
:
first_name = models.CharField(max_length=30)
ForeignKey
,
ManyToManyField
e
OneToOneField
requerem que o primeiro argumento
seja uma classe do modelo, assim usa o argumento verbose_name
como um argumento nomeado:
poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")
A convenção é não colocar em caixa alta a primeira letra do
verbose_name
. O Django irá automaticamente capitalizar a primeira
letra quando for necessário.
Relacionamentos¶
Claramente, o poder dos bancos relacionais reside na capacidade de relacionar tabelas umas as outroas. O Django oferece formas de definir os três tipos de relacionamento mais comuns: muitos-para-um, muitos-para-muitos e um-para-um.
Relacionamentos muitos-para-um¶
Para definir um relacionamento muitos para um, use
ForeignKey
. Você o usa como qualquer outro
Field`
: incluindo-o como um atributo de classe no seu
modelo.
O ForeignKey
requer um argumento posicional: a classe
a qual esse modelo é relacionado.
Por exemplo, se um modelo Car
tem um Manufacturer
– isso é, um
Manufacturer
faz múltiplos carros, mas cada Car
somente tem um
Manufacturer
– use as seguintes definições:
class Manufacturer(models.Model):
# ...
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
# ...
Para criar um relacionamento recursivo – (um objeto que tem um relacionamento muitos para um consigo mesmo) e relacionamentos com models que ainda não foram definidos; veja a referêcia de campos do model para mais detalhes.
É sugerido, mas não obrigatório, que o nome de um campo
ForeignKey
(manufacturer
do exemplo acima) seja o
nome do model, em minúsculo. Você pode, é claro, chamar o campo como você
quiser. Por exemplo:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(Manufacturer)
# ...
See also
Veja o exemplo de relacionamento Muitos-para-um para um exemplo completo.
Os campos ForeignKey
também aceitam um número extra
de argumentos que são explicados na referência de campos do model. Estas opções ajudam a definir como o relacionamento
deve funcionar; todos são opicionais.
Relacionamentos muitos-para-muitos¶
Para definir um relacionamento muitos-para-muitos, use o
ManyToManyField
. Você o utiliza como qualquer outro
tipo de Field
: incluíndo ele como um atributo de
classe do seu model.
O ManyToManyField
requer um argumento posicional: a
classe à qual esse modelo está relacionado.
Por exemplo, se uma Pizza
tem múltiplos objetos Topping
– isto é, um
Topping
pode estar em multiplas pizzas e cada Pizza
tem várias
sobremesas – aqui está como representar isso:
class Topping(models.Model):
# ...
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
Como com ForeignKey
, você pode também criar
relacionamentos recursivos (um objeto com um
relacionamento muitos-para-um para si mesmo) e relacionamentos para models
ainda não definidos; veja a referência de campos do
model para mais detalhes.
É sugerido, mas não obrigatório, que o nome de um
ManyToManyField
(toppigns
no exemplo acima) esteja
no plural, descrevendo o conjunto de objetos model relacionados.
Não importa qual model recebe o ManyToManyField
, mas
você somente precisa dele em um dos models – não em ambos.
Geralmente, instâncias de ManyToManyField
devem ir no
objeto que sera editado na internface do admin, se você estiver usando o admin
do Django. No exemplo acima, toppings
está em Pizza
(ao invés de
Topping
ter um ManyToManyField
pizzas
) porque
é mais natural pensar sobre pizzas tendo sobremesas do que sobremesas tendo
várias pizzas. A forma que é mostrada acima, o formulário de Pizza
no admin,
deixaria os usuários selecionar sobremesas.
See also
Veja o exemplo de relacionamento de model Muitos-para-muitos para um exemplo completo.
Os campos ManyToManyField
também aceitam um número
extra de argumentos que são explicados na referêcia de campos do model; Estas opções ajudam a definir como o relacionamento
deve funcionar; todos são opcionais.
Campos extra sobre relacionamentos muitos-para-muitos¶
Quando você está somente lidando com relacionamentos muitos-para-muitos simples
assim como misturando ou combinando pizzas e sobremesas, um
ManyToManyField
padrão é tudo que você precisa.
Entretanto, algumas vezes você pode precisar associar dados com o relacionamento
entre dois models.
Por exemplo, considere o caso de uma aplicação que monitora grupos musicais dos
quais músicos pertencem. Há um relacionamento muitos-para-muitos entre uma
pessoa e os grupos dos quais ela é um membro, então você poder usar um
ManyToManyField
para representar este relacionamento.
No entanto, há um monte de detalhes sobre a filiação que você pode querer
coletar, como a data em que a pessoa se juntou a um grupo.
Para estas situações, o Django permite você especificar o model que será usado
para governar o relacionamento muitos-para-muitos. Você pode então colocar
campos extra sobre o model intermediário. O model mediador é associado com o
ManyToManyField
usando o argumento through
para apontar o model que agirá como um mediador. Para
o nosso exemplo dos músicos, o código pareceria com algo assim:
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Quando você configura o model intermediário, você explicitamente especifica as chaves extrangeiras para o models que estão envolvidos no relacionamento ManyToMany. Esta declaração explicita define como os dois models serão relacionados.
Há umas poucas restrições no model intermediário:
- Seu model mediador deve conter uma - e somente uma - chave estrangeira
para o model alvo (este seria o
Person
em nosso exemplo). Se você tiver mais de uma chave estrangeira, um erro de validação será gerado. - Seu model mediador deve conter uma - e somente uma - chave estrangeira
para o model fonte (este seria o
Group
no nosso exemplo). Se você tiver mais de uma chave estrangeira, um erro de validação será gerado. - A única exceção para isto é o model que term relacionamento muitos-para-muitos, consigo mesmo através de um model intermediário. Neste caso, duas chaves extrangeiras para o mesmo model é permitida, mas elas serão tratadas como dois (diferentes) lados do muitos-para-muitos.
- Quando se define um relacionamento muitos-para-muitos de u model para ele
mesmo, usando um model intermediário, você deve usar
symmetrical=False
(veja referencia de campos do model).
Agora que você tem configurado seu ManyToManyField
para usar seu model mediador (Membership`, neste caso), você está pronto para
começar a criar alguns relacionamentos muitos-para-muitos. Você faz isto criando
instâncias do model intermediário:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason= "Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<Group: The Beatles>]
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason= "Wanted to form a band.")
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]
Diferentemente de campos muitos-para-muitos normais, você não pode usar
add
, create
, ou atribuição (i.e.,``beatles.members = [...]``) para criar
relacionamentos:
# ISTO NÃO FUNCIONARÁ
>>> beatles.members.add(john)
# NEM ISSO IRÁ
>>> beatles.members.create(name="George Harrison")
# E NEM MESMO ISSO
>>> beatles.members = [john, paul, ringo, george]
Porquê? você não pode simplesmente criar um relacionamento entre um
Person
e um Group
- você precisa especificar todos os detalhes para o
relacionamento requerido pelo model Membership
. As chamadas simples add
,
create
e atribuição não provem uma forma de especificar estes detalhes a
mais. Como um resultado, eles são desabilitados pelos relacionamentos
muitos-para-muitos que usam um model mediador.
A única forma de criar este tipo de relacionamento é criando instâncias do model
intermediário.
O método remove
é desabilitado por razões similares. No entanto, o método
clear()
pode ser usado para remover todo relacionamento muitos-para-muitos
para uma instância:
# Beatles have broken up
>>> beatles.members.clear()
Uma vez que você estabeleça o relacionamento muitos-para-muitos criando instâncias de seus models intermediários, você pode emitir consultas. Só que como um relacionamento muitos-para-muitos normal, você pode consultar usando os atributos do model relacionado com o muitos-para-muitos:
# Encontra todos os grupos com o membro cujo nome começa com 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
[<Group: The Beatles>]
Como você está usando um model intermediário, você pode também consultar seus atributos:
# Encontre todos os membro do Beatles que entraram depois de 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
[<Person: Ringo Starr]
Relacionamentos um-para-um¶
Para definir um relacionamento um-para-um, use o
OneToOneField
. Você deve utilizá-lo
como qualquer outro Field
: incluindo-o como um
atributo de classe em seu model.
Este é mais útil sobre a chave primária de um objeto, quando este objeto “extende” outro objeto de alguma forma.
O OneToOneField
requer um argumento posicional: a
classe para qual o model está relacionado.
Por exemplo, se você construiu um banco de dados de “lugares”, você iria
construir um belo padrão, com coisas tipo endereço, telefone, etc. no banco de
dados. Então se você esperava construir um banco de dados de restaurantes sobre
os lugares, ao invés de repetir e replicar todos esses campos no model
Restaurant
, você poderia fazer Restaurant
ter um
OneToOneField
para Place
(porque um restaurante
“é um” lugar; em fato, para manipular isto você normalmente usaria
herança, que envolve uma relação um-para-um
implícita.)
Como com ForeignKey
, um
relacionamento recursivo pode ser definido e
referenciar models ainda indefinidos; veja a
referência de campos do model para mais detalhes.
See also
Veja o exemplo de relacionamento de model um-para-um para um exemplo completo.
Os campos OneToOneField
também aceitam um argumento
opcional descrito na referência de campos do model.
OneToOneField
classes used to automatically become
the primary key on a model. This is no longer true (although you can manually
pass in the primary_key
argument if you like).
Thus, it’s now possible to have multiple fields of type
OneToOneField
on a single model.
As classes OneToOneField
são usadas para
automaticamente tornar-se a chave primária de um model. Isto já não é verdade (
embora você possa manualmente passar em um argumento
primary_key
se você quiser). Assim, agora é
possível ter vários campos do tipo OneToOneField
em
um único model.
Models em todos os arquivos¶
É perfeitamente normal relacionar um model com um de outra aplicação. Para fazer isto, importe o model relacionado no topo do arquivo que contém seu model. Então, é só referenciar para a outra classe model onde você quiser. Por exemplo:
from mysite.geography.models import ZipCode
class Restaurant(models.Model):
# ...
zip_code = models.ForeignKey(ZipCode)
Restrições de nome de campos¶
O Django impõe apenas duas restrições aos nomes de campos do modelo:
Um nome de campo não pode ser uma palavra reservada do Python, porque isso resultaria num erro de sintaxe do Python. Por exemplo:
class Example(models.Model): pass = models.IntegerField() # 'pass' é uma palavra reservada!
Um nome de campo não pode conter mais de um underscore em uma linha, devido à forma que a sintaxe de busca de consultas do Django funciona. Por exemplo:
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' tem dois underscores!
Essas limitações podem ser trabalhadas, já que o nome do seu campo não precisa
necessariamente ser igual ao nome da coluna no seu banco de dados. Veja a opção
db_column
.
Palavras reservadas do SQL, como join
, where
ou select
, são
permitidas como nomes de campos no modelo, porque o Django escapa todos os
nomes de tabelas e colunas em cada consulta SQL. Ele usa a sintaxe de quoting
do seu banco de dados em particular.
Tipos de campos customizados¶
Se um dos campos existentes no model não pode ser usado para o que você propõe, ou se você deseja ter vantagem sobre alguma coluna de banco de dados menos comum, você pode criar suas próprias classes de campos. A cobertura total da criação de seus próprios campos é fornecida em Writing custom model fields.
Opções Meta¶
Forneca seus metadados de model usando uma classe interna class meta
, desta
forma:
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
O metadado do model é “qualquer coisa que não seja um campo”, assim como opções
de ordenamento (attr:~Options.ordering), nome de tabelas do banco de dados
(db_table
), ou nomes legíveis-por-humanos no singular ou plural
(verbose_name_plural
). Nenhum é
obrigatório, e adicionar class Meta
ao model é completamente opcional.
Uma lista completa de todas as opções possíveis do Meta podem ser encontradas na referência e opções de model.
Métodos do model¶
Define métodos customizados sobre um model para adicionar funcionalidades a
“nível de linha” para seus objetos. Considerando que os métodos
Manager
são destinados para fazer coisas
“table-wide”, os métodos de model devem agir sobre uma instância particular de
model.
Esta é uma técnica valiosa para manter a lógica de negócio em um só lugar – o model.
Por exemplo, este model tem uns poucos métodos customizados:
from django.contrib.localflavor.us.models import USStateField
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
state = USStateField() # Yes, this is America-centric...
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
return "Baby boomer"
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
return "Post-boomer"
def is_midwestern(self):
"Returns True if this person is from the Midwest."
return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')
def _get_full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
full_name = property(_get_full_name)
O último método deste exemplo é um property. Leia mais sobre propriedades.
A referência de instância de model tem uma lista completa de métodos automaticamente dados para cada model. Você pode sobrescrever quase todos eles – veja sobrescrevendo métodos de model predefinidos, abaixo – mas há alguns que você irá quase sempre querer definir:
__unicode__()
Um “método mágico” do Python que retorna uma “representação” unicode de qualquer objeto. Isto é o que o Python e o Django irá usar sempre que uma instância de model precisar ser mostrada como uma string. Mais notavelmente, isto acontece quando você mostra um objeto em um um console interativo ou no admin.
Você sempre irá querer definir este método; o padrão não é muito útil.
get_absolute_url()
Este diz ao Django como calcular a URL para um objeto. O Django o usa na sua interface de administraçaõ, e toda vez que precisa descobrir a URL de um objeto.
Qualquer objeto que tem uma URL que o identifica exclusivamente, deve definir este método.
Sobrescrevendo métodos de model predefinidos¶
Há outro conjunto de métodos do model que
encapsulmam um monte de comportamentos de banco de dados que você deseja
customizar. Em particular você frequentemente vai querer mudar a forma de
funcionamento do save()
e delete()
.
Você é livre para sobrescrever estes métodos (e qualquer outro método do model) para alterar comportamento.
Um caso de uso clássico para sobrecarga de métodos embutidos é se você deseja
que algo aconteça sempre que você salva o objeto. Por exemplo (veja
save()
para documentação e paramêtros aceitos):
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, force_insert=False, force_update=False):
do_something()
super(Blog, self).save(force_insert, force_update) # Call the "real" save() method.
do_something_else()
Você pode também previnir o salvamento:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, force_insert=False, force_update=False):
if self.name == "Yoko Ono's blog":
return # Yoko não deve nunca ter seu próprio blog!
else:
super(Blog, self).save(force_insert, force_update) # Chama o método save() "real".
É imporante lembrar de chamar o método da superclasse – esse é que é o negócio
super(Blog, self).save()
– para assegurar que o objeto ainda será salvo no
banco de dados. Se você esquecer de chamar o método da superclasse, o
comportamento padrão não acontecerá e o banco de dados não será tocado.
Executando SQL customizado¶
Outra prática comum é escrever consultas SQL personalizadas em métodos do model a nível módulo. Para mais detalhe sobre como usar SQL puro, veja a documentação em usando SQL puro.
Herança de modelos¶
Herança de models no Django funciona quase igual à forma normal de herança entre classes do Python. A única decisão que você tem de tomar é se você quer que os modelos pai sejam modelos no seu próprio contexto (com suas próprias tabelas de banco de dados), ou se os pais são somente mantenedores de informações comuns que somente serão visíveis através da herança entre modelos.
Freqüentemente, você só quer usar a classe pai para manter informações que você não deseja escrever para cada modelo filho. Esta classe nunca será usada de forma isolada, então classes abstratas de base são o que estiver depois. Entretanto, se você está extendendo uma subclasse de modelo existente (talvez algo de outra aplicação), ou quer que cada modelo tenha sua própria tabela no banco de dados, herança com multi-tabelas é o caminho a seguir.
Classes Abstratas de Base¶
Uma classe abstrata de base é útil quando você quer colocar alguma informação
comum à disposição de vários modelos. Você escreve sua classe de base e coloca
abstract=True
dentro da classe Meta. Este modelo não
será usado para criar qualquer tabela no banco de dados. Em vez disso, quando
ele for usado como uma classe abstrata de base por outro modelo, seus campos
serão adicionados aos seus modelos filho. É um erro ter campos na classe
abstrata de base com o mesmo nome daqueles que a herda (o Django irá lançar uma
exceção).
Um exemplo:
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
O modelo Student
possuirá três campos: name
, age
e home_group
.
O modelo CommonInfo
não pode ser usado como um modelo normal do Django, já
que ele é uma classe abstrata de base. CommonInfo
não gera uma tabela no
banco de dados e nem pode ser instanciado ou salvo diretamente.
Para muitos usos, este tipo de herança de modelo será exatamente o que você quer. Ele fornece uma maneira de fatorar informações comuns ao nível do Python, enquanto ao nível do banco de dados só serão criadas tabelas para os modelos filhos.
Herança de Meta¶
Quando uma classe abstrata de base é criada, o Django torna qualquer Meta interno da classe que você criou, disponível como um atributo a classe de base. Se uma classe filha não declara sua própria classe Meta, ela irá herdar de seu pai. Se a classe filha quer extender a classe Meta do pai, ela pode. Por exemplo:
- class CommonInfo(models.Model):
...
- class Meta:
- abstract = True ordering = [‘name’]
- class Student(CommonInfo):
...
- class Meta(CommonInfo.Meta):
- db_table = ‘student_info’
O Django faz um ajuste para a classe Meta de uma classe
abstrata de base: antes instalando o atributo Meta, e
configurando abstract=False
. Isto significa que os filhos da classe abstrata
de base não se tornam automaticamente classes abstratas. É claro, você pode
fazer uma classe abstrata de base que herda outra classe abstrata de base. Você
só precisa lembrar de setar explicitamente abstract=True
toda vez.
Alguns atributos não fazem sentido serem incluídos na classe
Meta de uma classe abstrata de base. Por exemplo,
incluindo db_table
poderia significar que todos os filhos (que não
especificarem seus próprios Meta) poderiam usar a mesma
tabela no banco de dados, que é provavelmente o que você não quer.
Herança com Multi-Tabelas¶
O segundo tipo de herança de modelos suportado pelo Django é quando cada modelo
na hierarquia é um modelo em si mesmo. Cada modelo corresponde a sua própria
tabela no banco de dados e pode ser consultado e criado individualmente. A
relação de herança introduz links entre o modelo filho e cada um de seus pais
(por meio de um campo OneToOneField
criado automaticamente). Por exemplo:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
Todos os campos de Place
também estarão disponíveis no Restaurant
,
apesar de o dado residir em uma tabela diferente no banco de dados. Então ambos
são possíveis:
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
Se você tem um Place
que também é um Restaurant
, você pode obter do
objeto Place
o objeto Restaurant
usando a versão minúscula do nome do
model:
>>> p = Place.objects.filter(name="Bob's Cafe")
# Se "Bob's Cafe" é um objeto Restaurant, isto irá retornar uma classe filho:
>>> p.restaurant
<Restaurant: ...>
Entretanto, se p
no exemplo acima não for um Restaurant
(que havia
sido criado diretamente como um objeto Place
ou foi pai de alguma outra
classe), referir-se a p.restaurant
poderia gerar um erro.
Meta e herança com multi-tabelas¶
Nesta situação de herança com multi-tabelas, não faz sentido a classe filha herdar a classe Meta de seus pais. Todas as opções em Meta já teriam sido aplicadas para a classe e aplicá-las de novo normalmente levaria a um comportamento contraditório (isto está em contraste com o caso da classe abstrata de base, onde a classe de base não existe em seu próprio direito).
Então o modelo filho não tem acesso às classes Meta de seus pais.
Entretanto, existem uns poucos casos limitados onde o filho herda o
comportamento do pai: se o filho não especificar um atributo
django.db.models.Options.ordering
ou um atributo
django.db.models.Options.get_latest_by
, ele os herdará de seus pais.
Se o pai tem um ordenamento e você não quer que o filho o tenha, você pode explicitar com uma lista vazia:
class ChildModel(ParentModel):
...
class Meta:
# Remove o ordenamento dos pais
ordering = []
Herança e relações reversas¶
Porque a herança com multi-tabelas usa um campo implícito
OneToOneField
para ligar o filho ao pai, é possível mover propriedades do pai para o filho,
como no exemplo acima. Entretanto, isso usa o nome que é o valor padrão
related_name
para relações
django.db.models.fields.ForeignKey
e
django.db.models.fields.ManyToManyField
. Se você está
colocando estes tipos de relações sobre uma subclasse de outro modelo, você
deve especificar o atributo
related_name
em cada campo. Se você
esquecer, o Django gerará um erro quando você rodar o validate
ou
syncdb
.
Por exemplo, usando a classe Place
novamente, vamos criar outra subclasse
com um ManyToManyField
:
class Supplier(Place):
# Você deve especificar o related_name em todas as relações.
customers = models.ManyToManyField(Restaurant,
related_name='provider')
Especificando o campo parent_link¶
Como mencionado, o Django criará automaticamente um
OneToOneField
ligando
sua classe filha com qualquer modelo pai não-abstrato. Se você deseja controlar
o nome dos atributos de ligação, você pode criar sei próprio
OneToOneField
e setar
parent_link=True
.
para indicar que seu campo é o link para a classe pai.
Herança múltipla¶
Da mesma forma que as subclasses do Python, é possível para um modelo do Django ter herança de múltiplos modelos pais. Mantenha em mente a aplicação da resolução normal de nomes do Python. A primeira classe de base em que um nome particular aparece (ex: Meta) será utilizada. Nós paramos de procurar assim que encontramos um nome. Isso significa que se os múltiplos pais possuem uma classe Meta, somente o primeiro será usado. Todos os outros serão ignorados.
Geralmente você não necessita de herança múltipla. O principal caso de uso onde isso se torna comum é para classes ‘’mix-in’‘: adicionando um campo ou método extra em particular para cada classe que herdar do mix-in. Tente manter suas hierarquias o mais simples possível, para que você não trave batalhas para descobrir de onde vem uma certa informação.
“Esconder” nomes de campos não é permitido¶
Numa classe normal do Python, é admissível para uma classe filha sobrescrever
qualquer atributo de sua classe pai. No Django, isto não é permitido para
atributos que são instâncias de Field
(pelo
menos, não neste momento). Se a classe base tem um filho chamado author
,
você não pode criar outro campo para o model chamado author
em qualquer
classse que herde da classe base.
Sobrescrever campos no model pai conduz a dificuldade em áreas como
inicialização de novas instâncias (especificando que os campos são inicializados
no Model.__init__
) e serialização. Estas são funcionalidades que a herança
de classes normal do Python não consegue lidar da mesma forma, então a diferença
entre a herança de model do Django e herança de classes do Python não é
meramente arbitrária.
Esta restrição somente se aplica aos atributos que são instâncias do
Field
. Atributos normais do Python podem ser
sobrescritos se você desejar. Ele também se aplita apenas ao nome do atributo
como Python o vê: se você está manualmente especificando o nome da coluna do
banco de dados, você pode ter o nome da coluna aparecendo em ambas uma filha e
um model antecessor para herança muiti-tabela (elas são colunas em duas tabelas
diferentes no banco de dados).
Django will raise a FieldError
exception if you override any model field
in any ancestor model.
O Django irá lançar uma exceção FieldError
se você sobrescrever qualquer
campo em qualquer model antecessor.