Tutoriel Python Django 4.2.5 : Types de champs et relations des modèles (un-à-un, plusieurs-à-un, plusieurs-à-plusieurs)

La chose la plus importante et la seule nécessaire dans le modèle sont les définitions de champs pour la base de données. Les champs sont définis dans les attributs de classe. Des précautions doivent être prises lors de la définition des noms de champs pour éviter d'utiliser des noms qui entrent en conflit avec l'API du modèle, tels que clean, saveou delete.

Par exemple:

from django.db import models

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, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

Type de champ

Chaque champ du modèle doit être Fieldune instance d'une certaine classe. Django utilise ces classes de champs pour implémenter les fonctions suivantes :

  • Le type de champ est utilisé pour spécifier le type de données de la base de données (tel que : INTEGER, VARCHAR, TEXT).
  • La vue HTML utilisée par défaut lors du rendu des champs de formulaire (ex : <input type="text">, <select>).
  • Fonctionnalité de validation de base pour le backend Django et les formulaires générés automatiquement.

Django possède des dizaines de types de champs intégrés. Si les types intégrés de Django ne peuvent pas répondre à vos besoins, vous pouvez facilement écrire des types de champs personnalisés.

Options de champ

Chaque type de champ nécessite la spécification de certains paramètres. Par exemple, CharField(et ses sous-classes) doivent recevoir un max_lengthparamètre qui spécifie VARCHARle nombre d'octets dans la base de données à utiliser pour stocker les données. Certains paramètres facultatifs sont universels et peuvent être utilisés pour n'importe quel type de champ. Voici quelques paramètres courants couramment utilisés :

  • null: Si défini sur True, Django définira le champ dans la base de données lorsque le champ est vide NULL. La valeur par défaut est False.
  • blank: S'il est défini sur True, ce champ peut être vide. La valeur par défaut est False. Notez que cette option est null différente de . null L'option est uniquement un paramètre au niveau de la base de données, blank mais implique une validation de formulaire. Si un champ est défini sur blank=True, lors de la validation du formulaire, la valeur du champ de données reçu peut être vide, et lorsqu'elle est définie sur blank=False, elle ne peut pas être vide.
  • choices: Une série de tuples utilisés comme options pour ce champ. Si un tuple est fourni, le widget de formulaire par défaut est une zone de sélection plutôt qu'un champ de texte standard et limitera les options proposées.

choicesdans une liste d'options :

YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]

Remarque : choicesUne nouvelle migration sera créée à chaque fois que l'ordre est modifié.

La première valeur de chaque tuple sera stockée dans la base de données, tandis que la deuxième valeur ne sera utilisée que pour l'affichage dans le formulaire. Pour une instance de modèle, pour obtenir la deuxième valeur correspondante dans un tuple de ce champ, utilisez get_FOO_display()la méthode. Par exemple:

from django.db import models

class Person(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
    
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'

Vous pouvez également utiliser une classe d'énumération pour le définir de manière concise choices:

from django.db import models

class Runner(models.Model):
    MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
    name = models.CharField(max_length=60)
    medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)
  • default: La valeur par défaut de ce champ. Il peut s'agir d'une valeur ou d'un objet appelable. S'il s'agit d'un objet appelable, il sera appelé à chaque instanciation du modèle.
  • help_text : Texte "d'aide" supplémentaire qui s'affiche avec le contrôle de formulaire. Même si votre champ n'est pas utilisé dans un formulaire, il peut être utile pour générer de la documentation.
  • primary_key: S'il est défini sur True, définit ce champ comme clé primaire pour ce modèle.

Dans un modèle, si vous ne définissez l'option sur aucun champ primary_key=True. Django ajoutera automatiquement un IntegerFieldchamp et le définira comme clé primaire, donc à moins que vous ne souhaitiez remplacer le comportement de configuration de clé primaire par défaut de Django, vous n'avez pas besoin de définir la clé primaire manuellement.

Le champ de clé primaire est en lecture seule. Si vous modifiez la clé primaire d'une instance de modèle et l'enregistrez, cela équivaut à créer une nouvelle instance de modèle. Par exemple:

from django.db import models

class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>

unique: Si la valeur est définie sur True, la valeur de ce champ doit rester unique dans la table.

Définir automatiquement la clé primaire

Par défaut, Django donne à chaque modèle une clé primaire auto-incrémentée dont le type est AppConfig.default_auto_fieldspécifié dans ou DEFAULT_AUTO_FIELDglobalement dans la configuration. Par exemple:

id = models.BigAutoField(primary_key=True)

Si vous souhaitez spécifier vous-même la clé primaire, définissez le paramètre sur le champ que vous souhaitez définir comme clé primaire primary_key=True. Field.primary_keyDjango n'ajoutera pas automatiquement la colonne à la table (modèle) s'il constate que vous la définissez explicitement id. Chaque modèle doit avoir un primary_key=Truechamp défini (soit explicitement, soit automatiquement par Django).

Dans les anciennes versions, le champ de clé primaire créé automatiquement était toujours AutoField.

Nom du commentaire du champ

À l'exception de ForeignKey, ManyToManyFieldet OneToOneField, tout type de champ reçoit un paramètre de position facultatif verbose_name. Si la valeur du paramètre n'est pas spécifiée, Django utilisera automatiquement le nom de l'attribut du champ comme valeur du paramètre et convertira les traits de soulignement en espaces.

Dans cet exemple : la note est nommée "person's first name":

first_name = models.CharField("person's first name", max_length=30)

Dans cet exemple : la note est nommée "first name":

first_name = models.CharField(max_length=30)

ForeignKey, ManyToManyFieldet OneToOneFieldle premier paramètre reçu est le nom de classe du modèle, et un verbose_nameparamètre peut être ajouté ultérieurement :

poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
    Place,
    on_delete=models.CASCADE,
    verbose_name="related place",
)

La convention est de ne pas verbose_namemettre la première lettre en majuscule. Djanog convertira automatiquement la première lettre en majuscule si nécessaire.

relation de connexion

Évidemment, la puissance d’une base de données relationnelle réside dans les relations entre les tables. Django fournit des moyens de définir les trois relations de base de données les plus courantes : plusieurs-à-un, plusieurs-à-plusieurs et un-à-un.

association plusieurs-à-un

Pour définir une relation plusieurs-à-un, utilisez django.db.models.ForeignKeyla classe. Tout comme les autres types de champs Field, ajoutez simplement un attribut avec une valeur de ce type à votre modèle. ForeignKeyLa classe doit ajouter un paramètre de position, qui est le nom de la classe de modèle que vous souhaitez associer. Par exemple, si un Carmodèle a un constructeur Manufacturer(c'est-à-dire un modèle Manufacturerqui construit de nombreuses voitures, mais que chaque voiture n'a qu'un seul constructeur), utilisez la méthode suivante pour définir la relation :

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    # ...

Vous pouvez également créer des relations entre soi (un modèle a une relation plusieurs-à-un avec lui-même) et des relations avec des modèles non définis. Il est recommandé de définir ForeignKeyle nom du champ (dans l'exemple ci-dessus manufacturer) sur le nom du modèle que vous souhaitez associer, mais vous pouvez également le définir sur le nom de votre choix, par exemple :

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(
        Manufacturer,
        on_delete=models.CASCADE,
    )
    # ...

association plusieurs-à-plusieurs

Définissez une relation plusieurs-à-plusieurs à l’aide django.db.models.ManyToManyFieldde classes. Tout comme les autres Fieldtypes de champs, ajoutez simplement une propriété avec une valeur de ce type à votre modèle. ManyToManyFieldLa classe doit ajouter un paramètre de position, qui est le nom de la classe de modèle que vous souhaitez associer. Par exemple : s'il Pizzay a plusieurs Topping(ingrédients) - c'est-à-dire qu'un seul Toppingpeut exister dans plusieurs Pizzaet que chacun Pizzaen contient plusieurs Topping- alors la relation peut être exprimée comme ceci :

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

Comme ForeignKeyles classes, vous pouvez également créer des relations entre soi (un objet a une relation plusieurs-à-plusieurs avec lui-même) et des relations avec des modèles non définis. Il est recommandé de définir ManyToManyFieldle nom du champ (dans l'exemple ci-dessus toppings) sur un nom pluriel, indiquant la collection d'objets modèles à associer. ManyToManyFieldPour deux modèles avec une relation plusieurs-à-plusieurs, vous pouvez ajouter un champ à l'un ou l'autre modèle , mais vous ne pouvez sélectionner qu'un seul modèle pour définir le champ, c'est-à-dire que vous ne pouvez pas ajouter le champ aux deux modèles en même temps. De manière générale, ManyToManyFieldles instances doivent être placées dans les objets qui doivent être modifiés dans le formulaire. Dans l'exemple précédent, toppingsest placé Pizzadans (plutôt que Toppingl'instance pointée vers pizzasl'in ManyToManyField) car il est plus logique d'avoir plusieurs garnitures sur une pizza que de placer les garnitures sur différentes pizzas. Comme mentionné précédemment, Pizzal'utilisateur peut sélectionner plusieurs ingrédients lors de la modification du formulaire.

Ajouter des champs d'attributs supplémentaires dans des relations plusieurs-à-plusieurs

Si vous souhaitez simplement une relation plusieurs-à-plusieurs similaire à l'enregistrement de mélanges et d'associations entre pizzas et garnitures, la relation standard ManyToManyFieldsuffira. Cependant, vous devrez parfois associer les données à une relation entre deux modèles. Par exemple, considérons une application qui doit suivre les groupes de musique auxquels appartient un musicien. Il existe une relation plusieurs-à-plusieurs entre les personnes et les groupes dans lesquels elles appartiennent, et vous pouvez ManyToManyFieldreprésenter cette relation à l'aide de . Cependant, vous souhaiterez peut-être enregistrer plus d'informations dans une telle association, par exemple lorsque quelqu'un rejoint un groupe. Pour ces cas, Django vous permet de spécifier un modèle qui contrôle la relation plusieurs-à-plusieurs. Vous pouvez ajouter des champs supplémentaires au modèle intermédiaire. ManyToManyFieldUtilisez des paramètres lors de l'instanciation throughpour spécifier le modèle intermédiaire à utiliser pour la relation plusieurs-à-plusieurs. Pour notre exemple de musicien, le code est le suivant :

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Vous devez spécifier explicitement les clés étrangères pour les modèles intermédiaires impliqués dans la relation plusieurs-à-plusieurs lors de la configuration des modèles intermédiaires. Cette déclaration explicite définit la relation entre les deux modèles.

Il existe certaines restrictions dans le modèle intermédiaire :

  • Votre modèle intermédiaire possède soit une et une seule clé étrangère au modèle source (dans notre cas Group), soit vous devez ManyToManyField.through_fieldssélectionner manuellement l'une des multiples clés étrangères via le paramètre, s'il existe plusieurs clés étrangères et qu'aucun through_fieldsparamètre n'est utilisé. Si vous sélectionnez un, une erreur de validation se produira. PersonLa même restriction s'applique aux clés étrangères pointant vers le modèle cible (dans notre cas ).
  • Dans un modèle intermédiaire utilisé pour décrire une relation plusieurs-à-plusieurs qui pointe vers elle-même dans le modèle, il peut y avoir deux clés étrangères pointant vers le même modèle, mais ces deux sous-tables de clés étrangères représentent deux (différentes) plusieurs-à-plusieurs. -de nombreuses relations. Si le nombre de clés externes dépasse deux, vous devez spécifier through_fieldsles paramètres comme ci-dessus, sinon une erreur de vérification se produira.

Maintenant que vous avez complété le vôtre ManyToManyField(dans l'exemple Membership) avec le modèle intermédiaire, vous pouvez commencer à créer des relations plusieurs-à-plusieurs. Vous créez des relations en instanciant des modèles intermédiaires :

>>> 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()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<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()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>

Vous pouvez également créer des relations à l'aide de add(), create()ou set()à condition de spécifier les champs obligatoires.through_defaults

>>> beatles.members.add(john, through_defaults={
    
    'date_joined': date(1960, 8, 1)})
>>> beatles.members.create(name="George Harrison", through_defaults={
    
    'date_joined': date(1960, 8, 1)})
>>> beatles.members.set([john, paul, ringo, george], through_defaults={
    
    'date_joined': date(1960, 8, 1)})

Vous préférerez peut-être créer directement le modèle intermédiaire. Si le modèle intermédiaire personnalisé n'applique pas (model1, model2)l'unicité à la paire, l'appel remove()de la méthode supprimera toutes les instances du modèle intermédiaire :

>>> Membership.objects.create(person=ringo, group=beatles,
...     date_joined=date(1968, 9, 4),
...     invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>

Méthode clear()pour toutes les relations plusieurs-à-plusieurs d’instances :

>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>

Une fois que vous avez établi une relation plusieurs-à-plusieurs personnalisée, vous pouvez effectuer des opérations de requête. Comme pour une relation plusieurs-à-plusieurs générale, vous pouvez utiliser les propriétés du modèle de relation plusieurs-à-plusieurs pour interroger :

# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>

Lorsque vous utilisez un modèle intermédiaire, vous pouvez également interroger ses propriétés :

# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
...     group__name='The Beatles',
...     membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>

Si vous souhaitez accéder aux informations sur une relation, vous pouvez interroger Membershipdirectement le modèle :

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

Une autre façon d'accéder aux mêmes informations consiste Personà interroger la relation récursive plusieurs-à-plusieurs via l'objet :

>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

association individuelle

Utilisez OneToOneFieldpour définir une relation un-à-un. Comme avec les autres typesField : incluez-le dans les propriétés du modèle. Ceci est utile lorsqu'un objet "hérite" d'un autre objet d'une manière ou d'une autre, qui est la clé primaire de cet objet. OneToOneFieldNécessite un argument de position : la classe associée au modèle. Par exemple, lorsque vous créez une base de données sur les informations de « localisation », vous pouvez inclure les champs habituels d'adresse, de téléphone, etc. Ensuite, si vous souhaitez construire une base de données sur les restaurants, en plus de copier les champs de la base de données de localisation dans le Restaurantmodèle, vous pouvez également Place OneToOneFieldy placer un pointeur Restaurant(car le restaurant "est" un emplacement) ; en effet, lorsque vous traitez avec ça Dans ce cas, il est préférable d'utiliser l'héritage de modèle, qui inclut implicitement une relation un-à-un. Comme ForeignKeyavec , vous pouvez créer des relations avec vous-même ou avec des modèles qui n'ont pas encore été définis.

OneToOneFieldLe champ accepte également un parent_linkparamètre facultatif. OneToOneFieldLa classe devient généralement automatiquement la clé primaire du modèle, cette règle n'est plus utilisée (vous pouvez cependant spécifier primary_keyles paramètres manuellement). Il est donc désormais possible de spécifier plusieurs champs au sein d'un même modèle OneToOneField.

Modèle multi-fichiers

Il est certes possible d'associer un modèle provenant d'une autre application. Pour cela, importez le modèle qui doit être associé au début du fichier qui définit le modèle. Vous pouvez ensuite l'associer à d'autres classes de modèles selon vos besoins. Par exemple:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(
        ZipCode,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

Restrictions de dénomination des champs

Django a certaines restrictions sur les noms de champs de modèle :

1. Le nom d'un champ ne peut pas être un mot réservé Python, car cela entraînerait des erreurs de syntaxe Python. Par exemple:

class Example(models.Model):
    pass = models.IntegerField() # 'pass' is a reserved word!

2. Un nom de champ ne peut pas contenir plusieurs traits de soulignement consécutifs. Cela est dû au fonctionnement de la syntaxe de requête Django. Par exemple:

class Example(models.Model):
    foo__bar = models.IntegerField() # 'foo__bar' has two underscores!

3. Le nom du champ ne peut pas se terminer par un trait de soulignement pour la même raison que ci-dessus.

Toutefois, ces limitations peuvent être contournées car il n'est pas nécessaire que les noms de champs soient identiques aux noms de colonnes de la base de données.

Les mots réservés SQL, tels que joinou , peuvent être utilisés dans les noms de champs de modèle car Django nettoie tous les noms de tables et de champs de base de données dans la requête SQL sous-jacente en utilisant la syntaxe de citation spécifique au moteur de base de données where.select

Type de champ personnalisé

Si les champs du modèle existant ne répondent pas à vos besoins ou si vous souhaitez prendre en charge certains types de colonnes de base de données moins courants, vous pouvez créer votre propre classe de champs.


liens:

https://docs.djangoproject.com/zh-hans/4.2

https://www.w3cschool.cn/django4/django4-h7o33lzo.html

おすすめ

転載: blog.csdn.net/a772304419/article/details/133563436