Je définis actuellement mes modèles Django et je me suis rendu compte qu'il n'y avait pas de OneToManyField
dans les types de champ de modèle. Je suis sûr qu'il existe un moyen de faire cela, donc je ne suis pas sûr de ce qu'il me manque. J'ai essentiellement quelque chose comme ça:
class Dude(models.Model):
numbers = models.OneToManyField('PhoneNumber')
class PhoneNumber(models.Model):
number = models.CharField()
Dans ce cas, chaque Dude
peut avoir plusieurs PhoneNumber
s, mais la relation doit être unidirectionnelle, en ce sens que je n'ai pas besoin de savoir à partir de PhoneNumber
laquelle Dude
le possède , comme tel, j’aurais peut-être beaucoup d’objets différents qui possèdent des instances de PhoneNumber
, comme un Business
, par exemple:
class Business(models.Model):
numbers = models.OneToManyField('PhoneNumber')
Avec quoi je remplacerais OneToManyField
(qui n'existe pas) dans le modèle pour représenter ce type de relation? Je viens d'Hibernate/JPA, où déclarer une relation un à plusieurs était aussi simple que:
@OneToMany
private List<PhoneNumber> phoneNumbers;
Comment puis-je exprimer cela dans Django?
Pour gérer les relations un-à-plusieurs dans Django, vous devez utiliser ForeignKey
.
La documentation sur ForeignKey est très complète et devrait répondre à toutes les questions que vous vous posez:
https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey
La structure actuelle de votre exemple autorise chaque Dude à avoir un numéro et chaque numéro à appartenir à plusieurs Dudes (identique à Business).
Si vous voulez la relation inverse, vous devez ajouter deux champs ForeignKey à votre modèle PhoneNumber, un à Dude et un à Business. Cela permettrait à chaque numéro d'appartenir à un type ou à une entreprise et d'avoir des types et des entreprises capables de posséder plusieurs numéros. Je pense que cela pourrait être ce que vous recherchez.
class Business(models.Model):
...
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
business = models.ForeignKey(Business)
Dans Django, une relation un-à-plusieurs est appelée ForeignKey. Cependant, cela ne fonctionne que dans un sens. Ainsi, plutôt que d'avoir un attribut number
de classe Dude
, vous aurez besoin de
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
De nombreux modèles peuvent avoir un ForeignKey
à un autre modèle, il serait donc valide d'avoir un deuxième attribut de PhoneNumber
tel que
class Business(models.Model):
...
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
business = models.ForeignKey(Business)
Vous pouvez accéder à PhoneNumber
s pour un objet Dude
d
avec d.phonenumber_set.objects.all()
, puis procéder de la même manière pour un objet Business
.
Vous pouvez utiliser la clé étrangère de nombreux côtés de la relation OneToMany
(c'est-à-dire ManyToOne
relation) ou utiliser ManyToMany
(de n'importe quel côté) avec une contrainte unique.
Pour être plus clair - il n'y a pas de OneToMany dans Django, mais de ManyToOne - qui est la clé Foreignkey décrite ci-dessus. Vous pouvez décrire la relation OneToMany à l’aide de Foreignkey, mais c’est très inexpressif.
Un bon article à ce sujet: https://amir.rachum.com/blog/2013/06/15/a-case-for-a-onetomany-relationship-in-Django/
Django
est assez intelligent. En réalité, nous n'avons pas besoin de définir le champ oneToMany
. Il sera généré automatiquement par Django
pour vous :-). Nous avons seulement besoin de définir foreignKey
dans la table liée. En d'autres termes, il suffit de définir la relation ManyToOne
à l'aide de foreignKey
.
class Car(models.Model):
// wheels = models.oneToMany() to get wheels of this car [**it is not required to define**].
class Wheel(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE)
si nous voulons obtenir la liste des roues d'une voiture particulière. nous allons utiliser python's
objet généré automatiquement wheel_set
. Pour voiture c
vous utiliserez c.wheel_set.all()
Si le modèle "many" ne justifie pas la création d'un modèle en soi (ce qui n'est pas le cas ici, mais cela pourrait profiter à d'autres personnes), une autre alternative serait de s'appuyer sur des types de données PostgreSQL spécifiques, via le package Django Contrib
Postgres peut traiter les types de données Array ou JSON , ce qui peut constituer une solution de contournement intéressante pour la gestion de One-To-Many lorsque les plusieurs-fichiers ne peuvent être liés une seule entité du un.
Postgres vous permet d'accéder à des éléments uniques du tableau, ce qui signifie que les requêtes peuvent être très rapides et éviter les frais généraux au niveau de l'application. Et bien sûr, Django implémente une API géniale pour exploiter cette fonctionnalité.
Il a évidemment l’inconvénient de ne pas être portable sur d’autres bases de données, mais j’estime que cela mérite d’être mentionné.
J'espère que cela aidera certaines personnes à la recherche d'idées.
Bien que la réponse de rolling stone soit bonne, simple et fonctionnelle, je pense qu'il y a deux choses que cela ne résout pas.
Introduisez le framework de types de conten , qui expose certains objets nous permettant de créer une "clé étrangère générique" sur le modèle PhoneNumber. Ensuite, nous pouvons définir la relation inverse sur Dude and Business
from Django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from Django.contrib.contenttypes.models import ContentType
from Django.db import models
class PhoneNumber(models.Model):
number = models.CharField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
owner = GenericForeignKey()
class Dude(models.Model):
numbers = GenericRelation(PhoneNumber)
class Business(models.Model):
numbers = GenericRelation(PhoneNumber)
Voir le docs pour plus de détails, et peut-être consulter cet article pour un tutoriel rapide.
En outre, voici n article qui défend contre l'utilisation de FK génériques.