Je cherche à faire ceci:
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)
C'est la version que j'aimerais utiliser (bien que je sois ouvert à toute suggestion): http://docs.djangoproject.com/en/dev/topics/db/models/#id7
Est-ce pris en charge dans Django? Sinon, existe-t-il un moyen d'obtenir des résultats similaires?
python
django
django-inheritance
Johnny 5
la source
la source
Réponses:
Réponse mise à jour: comme les gens l'ont noté dans les commentaires, la réponse originale ne répondait pas correctement à la question. En effet, seul le
LongNamedRestaurant
modèle a été créé en base de données,Place
ne l'était pas.Une solution consiste à créer un modèle abstrait représentant un «lieu», par exemple.
AbstractPlace
, et en hériter:Veuillez également lire la réponse @Mark , il explique pourquoi vous ne pouvez pas modifier les attributs hérités d'une classe non abstraite.
(Notez que cela n'est possible que depuis Django 1.10: avant Django 1.10, modifier un attribut hérité d'une classe abstraite n'était pas possible.)
la source
Place
était abstrait, donc il n'a pas été créé dans la base de données. Mais OP voulait les deuxPlace
etLongNamedRestaurant
être créé dans une base de données. Par conséquent, j'ai mis à jour ma réponse pour ajouter leAbstractPlace
modèle, qui est le modèle «de base» (c'est-à-dire abstrait)Place
et dont ilLongNamedRestaurant
hérite. Maintenant, les deuxPlace
etLongNamedRestaurant
sont créés dans la base de données, comme OP l'a demandé.Non, ce n'est pas :
la source
User._meta.get_field('email').required = True
pourrait fonctionner, je ne suis pas sûr de penser._meta
de la classe parent, par exempleMyParentClass._meta.get_field('email').blank = False
(pour rendre unemail
champ hérité obligatoire dans l'Admin)Cela n'est possible que si abstrait, et voici pourquoi:
LongNamedRestaurant
est également aPlace
, non seulement en tant que classe mais aussi dans la base de données. La table de place contient une entrée pour chaque purPlace
et pour chaqueLongNamedRestaurant
.LongNamedRestaurant
crée simplement une table supplémentaire avecfood_type
et une référence à la table d'espace.Si vous le faites
Place.objects.all()
, vous obtenez également chaque place qui est aLongNamedRestaurant
, et ce sera une instance dePlace
(sans lefood_type
). DoncPlace.name
etLongNamedRestaurant.name
partager la même colonne de base de données, et doit donc être du même type.Je pense que cela a du sens pour les modèles normaux: chaque restaurant est un endroit et devrait au moins avoir tout ce que cet endroit a. Peut-être que cette cohérence est aussi la raison pour laquelle ce n'était pas possible pour les modèles abstraits avant la 1.10, même si cela ne poserait pas de problèmes de base de données. Comme le remarque @lampslave, cela a été rendu possible en 1.10. Je recommanderais personnellement de faire attention: si Sub.x remplace Super.x, assurez-vous que Sub.x est une sous-classe de Super.x, sinon Sub ne peut pas être utilisé à la place de Super.
Solutions de contournement : vous pouvez créer un modèle utilisateur personnalisé (
AUTH_USER_MODEL
) qui implique un peu de duplication de code si vous devez uniquement modifier le champ de messagerie. Vous pouvez également laisser le courrier électronique tel quel et vous assurer qu'il est requis dans tous les formulaires. Cela ne garantit pas l'intégrité de la base de données si d'autres applications l'utilisent et ne fonctionne pas dans l'autre sens (si vous souhaitez rendre le nom d'utilisateur non requis).la source
Voir https://stackoverflow.com/a/6379556/15690 :
la source
Vous avez collé votre code dans une nouvelle application, ajouté une application à INSTALLED_APPS et exécuté syncdb:
On dirait que Django ne prend pas en charge cela.
la source
Ce morceau de code super cool vous permet de «remplacer» les champs dans les classes parents abstraites.
Lorsque les champs ont été supprimés de la classe parent abstraite, vous êtes libre de les redéfinir selon vos besoins.
Ce n'est pas mon propre travail. Code d'origine d'ici: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
la source
Vous pourriez peut-être vous occuper de contrib_to_class:
Syncdb fonctionne très bien. Je n'ai pas essayé cet exemple, dans mon cas, je remplace simplement un paramètre de contrainte alors ... attendez et voyez!
la source
Place._meta.get_field('name').max_length = 255
dans le corps de la classe devrait faire l'affaire, sans surcharger__init__()
. Serait aussi plus concis.Je sais que c'est une vieille question, mais j'ai eu un problème similaire et j'ai trouvé une solution de contournement:
J'ai eu les cours suivants:
Mais je voulais que le champ image hérité de Year soit requis tout en gardant le champ image de la superclasse nullable. En fin de compte, j'ai utilisé ModelForms pour appliquer l'image au stade de la validation:
admin.py:
Il semble que cela ne s'applique que dans certaines situations (certainement où vous devez appliquer des règles plus strictes sur le champ de sous-classe).
Vous pouvez également utiliser la
clean_<fieldname>()
méthode à la place declean()
, par exemple, si un champtown
doit être rempli:la source
Vous ne pouvez pas remplacer les champs de modèle, mais c'est facilement réalisé en remplaçant / en spécifiant la méthode clean (). J'ai eu le problème avec le champ de courrier électronique et je voulais le rendre unique au niveau du modèle et je l'ai fait comme ceci:
Le message d'erreur est ensuite capturé par le champ Formulaire avec le nom "email"
la source
Ma solution est aussi simple que la suivante
monkey patching
, remarquez comment j'ai changé le champmax_length
attribut foname
dans leLongNamedRestaurant
modèle:la source