Estou tentando fazer isso:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
Esta é a versão que gostaria de usar (embora esteja aberto a qualquer sugestão): http://docs.djangoproject.com/en/dev/topics/db/models/#id7
Isso é compatível com Django? Se não, existe uma maneira de obter resultados semelhantes?
python
django
django-inheritance
Johnny 5
fonte
fonte
Respostas:
Resposta atualizada: como as pessoas notaram nos comentários, a resposta original não respondia adequadamente à pergunta. Na verdade, apenas o
LongNamedRestaurant
modelo foi criado em banco de dados,Place
não foi.Uma solução é criar um modelo abstrato representando um "Local", por exemplo.
AbstractPlace
, e herdar dele:Leia também a resposta @Mark , ele dá uma ótima explicação de porque você não pode alterar atributos herdados de uma classe não abstrata.
(Observe que isso só é possível desde o Django 1.10: antes do Django 1.10, modificar um atributo herdado de uma classe abstrata não era possível.)
fonte
Place
era abstrato, portanto, foi não criado no banco de dados. Mas o OP queria que ambosPlace
eLongNamedRestaurant
fossem criados no banco de dados. Portanto, atualizei minha resposta para adicionar oAbstractPlace
modelo, que é o modelo “base” (isto é, abstrato)Place
e do qualLongNamedRestaurant
herda. Agora ambosPlace
eLongNamedRestaurant
são criados no banco de dados, como OP pediu.Não, não é :
fonte
User._meta.get_field('email').required = True
poderia funcionar, não tenho certeza._meta
da classe pai, por exemploMyParentClass._meta.get_field('email').blank = False
(para tornar umemail
campo herdado obrigatório no Admin)Isso não é possível a menos que abstrato, e aqui está o motivo:
LongNamedRestaurant
também é umPlace
, não apenas como uma classe, mas também no banco de dados. A tabela de locais contém uma entrada para cada puroPlace
e para cadaLongNamedRestaurant
.LongNamedRestaurant
apenas cria uma mesa extra comfood_type
e uma referência à mesa local.Se você fizer isso
Place.objects.all()
, também obterá todos os lugares que são aLongNamedRestaurant
e será uma instância dePlace
(semfood_type
). Assim,Place.name
eLongNamedRestaurant.name
compartilhar a mesma coluna de banco de dados, e deve, portanto, ser do mesmo tipo.Acho que isso faz sentido para modelos normais: todo restaurante é um lugar, e deve ter pelo menos tudo que esse lugar tem. Talvez essa consistência também seja o motivo pelo qual não era possível para modelos abstratos antes de 1.10, embora não desse problemas de banco de dados lá. Como observou @lampslave, isso foi possível em 1.10. Eu pessoalmente recomendaria cuidado: se Sub.x substituir Super.x, certifique-se de que Sub.x seja uma subclasse de Super.x, caso contrário, Sub não pode ser usado no lugar de Super.
Soluções alternativas : Você pode criar um modelo de usuário personalizado (
AUTH_USER_MODEL
) que envolve bastante duplicação de código se precisar apenas alterar o campo de e-mail. Como alternativa, você pode deixar o e-mail como está e verificar se é obrigatório em todos os formulários. Isso não garante a integridade do banco de dados se outros aplicativos o usarem e não funciona ao contrário (se você quiser tornar o nome de usuário não obrigatório).fonte
Consulte https://stackoverflow.com/a/6379556/15690 :
fonte
Colou seu código em um aplicativo novo, adicionou o aplicativo ao INSTALLED_APPS e executou o syncdb:
Parece que o Django não suporta isso.
fonte
Este código super-cool permite que você 'substitua' campos em classes pai abstratas.
Quando os campos forem removidos da classe pai abstrata, você estará livre para redefini-los conforme necessário.
Este não é meu próprio trabalho. Código original aqui: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
fonte
Talvez você possa lidar com contrib_to_class:
Syncdb funciona bem. Eu não tentei este exemplo, no meu caso eu apenas substituí um parâmetro de restrição então ... espere e veja!
fonte
Place._meta.get_field('name').max_length = 255
no corpo da classe deve fazer o truque, sem substituir__init__()
. Seria mais conciso também.Eu sei que é uma pergunta antiga, mas tive um problema semelhante e encontrei uma solução alternativa:
Tive as seguintes aulas:
Mas eu queria que o campo de imagem herdado de Year fosse necessário, mantendo o campo de imagem da superclasse anulável. No final, usei ModelForms para impor a imagem na fase de validação:
admin.py:
Parece que isso só se aplica a algumas situações (certamente onde você precisa impor regras mais rígidas no campo da subclasse).
Como alternativa, você pode usar o
clean_<fieldname>()
método em vez declean()
, por exemplo, se um campo tivertown
que ser preenchido:fonte
Você não pode substituir os campos do modelo, mas é facilmente obtido substituindo / especificando o método clean (). Eu tive o problema com o campo de e-mail e queria torná-lo único no nível do modelo e fiz assim:
A mensagem de erro é então capturada pelo campo do formulário com o nome "email"
fonte
Minha solução é tão simples quanto a seguir
monkey patching
, observe como mudei omax_length
atributo para oname
campo noLongNamedRestaurant
modelo:fonte