Django: ¿Establecer clave externa usando un entero?

104

¿Hay alguna forma de establecer la relación de clave externa utilizando el ID de número entero de un modelo? Esto sería con fines de optimización.

Por ejemplo, supongamos que tengo un modelo de empleado:

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

y

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

Quiero la flexibilidad de tener tipos de empleados ilimitados, pero en la aplicación implementada probablemente habrá solo un tipo, así que me pregunto si hay una manera de codificar la identificación y establecer la relación de esta manera. De esta manera puedo evitar una llamada a la base de datos para obtener primero el objeto EmployeeType.

Usuario
fuente

Respuestas:

205

Sí:

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

ForeignKeyLos campos almacenan su valor en un atributo con _idal final, al que puede acceder directamente para evitar visitar la base de datos.

La _idversión de a ForeignKeyes un aspecto particularmente útil de Django, uno que todos deberían conocer y utilizar de vez en cuando cuando sea apropiado.

consideración:

@RuneKaagaard señala que employee.typeno es preciso después en las versiones recientes de Django, incluso después de llamar employee.save()(mantiene su valor anterior). Usarlo, por supuesto, anularía el propósito de la optimización anterior, pero preferiría una consulta adicional accidental a ser incorrecta. Así que tenga cuidado, use esto solo cuando haya terminado de trabajar en su instancia (por ejemplo employee).

Will Hardy
fuente
10
¿Está esto documentado?
Scott Stafford
8
Uso directo de valores de clave externa: docs.djangoproject.com/en/1.8/topics/db/optimization/…
Dan Oliphant
1
Probé esto en Django 1.7 hoy, y no es una buena idea allí. Mientras funciona y el typecampo se escribe en la base de datos, si accede a la typepropiedad posteriormente, no refleja el cambio. Dicho en código, esto fallaría assert(employe.type.id == 4).
Rune Kaagaard
3
@AmichaiSchreiber Creo que la próxima versión de Django tendrá una solución para este problema: code.djangoproject.com/ticket/27710
Will Hardy
2
Para cualquiera que venga aquí en el futuro, este problema está solucionado en Django 2.1 .
humcat
45

Una alternativa que usa create para crear el objeto y guardarlo en la base de datos en una línea:

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