Django: définir la clé étrangère en utilisant un entier?

104

Existe-t-il un moyen de définir une relation de clé étrangère à l'aide de l'ID entier d'un modèle? Ce serait à des fins d'optimisation.

Par exemple, supposons que j'ai un modèle Employee:

class Employee(models.Model):
  first_name = models.CharField(max_length=100)
  last_name = models.CharField(max_length=100)
  type = models.ForeignKey('EmployeeType')

et

EmployeeType(models.Model):
  type = models.CharField(max_length=100)

Je veux la flexibilité d'avoir des types d'employés illimités, mais dans l'application déployée, il n'y aura probablement qu'un seul type, donc je me demande s'il existe un moyen de coder en dur l'id et de définir la relation de cette façon. De cette façon, je peux éviter un appel db pour obtenir d'abord l'objet EmployeeType.

Utilisateur
la source

Réponses:

206

Oui:

employee = Employee(first_name="Name", last_name="Name")
employee.type_id = 4
employee.save()

ForeignKeyles champs stockent leur valeur dans un attribut avec _idà la fin, auquel vous pouvez accéder directement pour éviter de visiter la base de données.

La _idversion de a ForeignKeyest un aspect particulièrement utile de Django, un aspect que tout le monde devrait connaître et utiliser de temps en temps le cas échéant.

caveat:

@RuneKaagaard souligne que ce employee.typen'est pas exact par la suite dans les versions récentes de Django, même après avoir appelé employee.save()(il conserve son ancienne valeur). Son utilisation irait bien sûr à l'encontre de l'objectif de l'optimisation ci-dessus, mais je préférerais qu'une requête supplémentaire accidentelle soit incorrecte. Soyez donc prudent, n'utilisez ceci que lorsque vous avez fini de travailler sur votre instance (par exemple employee).

Will Hardy
la source
10
Est-ce documenté?
Scott Stafford
8
Utilisation directe de valeurs de clé étrangère: docs.djangoproject.com/en/1.8/topics/db/optimization/…
Dan Oliphant
1
J'ai testé cela sur Django 1.7 aujourd'hui, et ce n'est pas une bonne idée là-bas. Tant que cela fonctionne et que le typechamp est écrit dans la base de données, si vous accédez à la typepropriété par la suite, cela ne reflète pas la modification. Dit dans le code, cela échouerait assert(employe.type.id == 4).
Rune Kaagaard
3
@AmichaiSchreiber Je crois que la prochaine version de Django aura un correctif pour ce problème: code.djangoproject.com/ticket/27710
Will Hardy
2
Pour toute personne venant ici à l'avenir, ce problème est résolu dans Django 2.1 .
humcat
45

Une alternative qui utilise create pour créer l'objet et l'enregistrer dans la base de données en une seule ligne:

employee = Employee.objects.create(first_name='first', last_name='last', type_id=4)
Jacinda
la source