web-dev-qa-db-fra.com

Définition de la valeur par défaut pour l'attribut de clé étrangère

Quelle est la meilleure façon de définir une valeur par défaut pour un champ de clé étrangère dans un modèle? Supposons que j'ai deux modèles, Student et Exam, avec student ayant exam_taken comme clé étrangère. Comment pourrais-je idéalement définir une valeur par défaut pour cela? Voici un journal de mes efforts

class Student(models.Model):
   ....
   .....
   exam_taken = models.ForeignKey("Exam", default=1)

Fonctionne, mais pensez qu'il y a une meilleure façon.

def get_exam():
    return Exam.objects.get(id=1)

class Student(models.Model):
    ....
    .....
    exam_taken = models.ForeignKey("Exam", default=get_exam)

De ici , mais échoue avec les tables n'existe pas d'erreur lors de la synchronisation.

Toute aide serait appréciée.

53
Primal Pappachan

Dans vos deux exemples, vous codez en dur l'ID de l'instance par défaut. Si c'est inévitable, je définirais simplement une constante.

DEFAULT_EXAM_ID = 1
class Student(models.Model):
    ...
    exam_taken = models.ForeignKey("Exam", default=DEFAULT_EXAM_ID)

Moins de code et le fait de nommer la constante la rendent plus lisible.

32
Gareth

J'utilise des clés naturelles pour adopter une approche plus naturelle:

<app>/models.py

from Django.db import models

class CountryManager(models.Manager):
    """Enable fixtures using self.sigla instead of `id`"""

    def get_by_natural_key(self, sigla):
        return self.get(sigla=sigla)

class Country(models.Model):
    objects = CountryManager()
    sigla   = models.CharField(max_length=5, unique=True)

    def __unicode__(self):
        return u'%s' % self.sigla

class City(models.Model):
    nome   = models.CharField(max_length=64, unique=True)
    nation = models.ForeignKey(Country, default='IT')
10
vault

Je modifierais légèrement la réponse de @ vault ci-dessus (cela peut être une nouvelle fonctionnalité). Il est certainement souhaitable de se référer au domaine par un nom naturel. Cependant, au lieu de remplacer le Manager j'utiliserais simplement le to_field param of ForeignKey:

class Country(models.Model):
    sigla   = models.CharField(max_length=5, unique=True)

    def __unicode__(self):
        return u'%s' % self.sigla

class City(models.Model):
    nome   = models.CharField(max_length=64, unique=True)
    nation = models.ForeignKey(Country, to_field='sigla', default='IT')
7
Carson McNeil

Dans mon cas, je voulais définir la valeur par défaut sur n'importe quelle instance existante du modèle associé. Parce qu'il est possible que Exam avec id 1 a été supprimé, j'ai fait ce qui suit:

class Student(models.Model):
    exam_taken = models.ForeignKey("Exam", blank=True)

    def save(self, *args, **kwargs):
        try:
            self.exam_taken
        except:
            self.exam_taken = Exam.objects.first()
        super().save(*args, **kwargs)

Si exam_taken n'existe pas, Django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist sera levé lors d'une tentative d'accès.

6
connorbode

Vous pouvez utiliser ce modèle:

class Other(models.Model):
    DEFAULT_PK=1
    name=models.CharField(max_length=1024)

class FooModel(models.Model):
    other=models.ForeignKey(Other, default=Other.DEFAULT_PK)

Bien sûr, vous devez vous assurer qu'il y a une ligne dans le tableau de Other. Vous devez utiliser une migration de données pour vous assurer qu'elle existe.

4
guettli