Django: Definir chave estrangeira usando inteiro?

104

Existe uma maneira de definir o relacionamento de chave estrangeira usando a id de inteiro de um modelo? Isso seria para fins de otimização.

Por exemplo, suponha que eu tenha um modelo de funcionário:

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

e

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

Quero a flexibilidade de ter tipos de funcionários ilimitados, mas no aplicativo implantado provavelmente haverá apenas um único tipo, então estou me perguntando se há uma maneira de codificar a id e definir o relacionamento dessa forma. Dessa forma, posso evitar uma chamada de banco de dados para obter o objeto EmployeeType primeiro.

Do utilizador
fonte

Respostas:

205

Sim:

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

ForeignKey campos armazenam seu valor em um atributo com _id no final, que você pode acessar diretamente para evitar visitar o banco de dados.

A _idversão de a ForeignKeyé um aspecto particularmente útil do Django, que todos devem conhecer e usar de vez em quando, quando apropriado.

embargo:

@RuneKaagaard aponta que isso employee.typenão é preciso posteriormente nas versões recentes do Django, mesmo após a chamada employee.save()(mantém seu valor antigo). É claro que usá-lo iria contra o propósito da otimização acima, mas eu preferiria uma consulta extra acidental a estar incorreta. Portanto, tome cuidado, use-o apenas quando terminar de trabalhar em sua instância (por exemplo employee).

Will Hardy
fonte
10
Isso está documentado?
Scott Stafford
8
Usando valores de chave estrangeira diretamente: docs.djangoproject.com/en/1.8/topics/db/optimization/…
Dan Oliphant
1
Eu testei isso no Django 1.7 hoje, e não é uma boa ideia lá. Embora funcione e o typecampo seja gravado no banco de dados, se você acessar a typepropriedade posteriormente, ela não refletirá a alteração. Dito em código, isso iria falhar assert(employe.type.id == 4).
Rune Kaagaard
3
@AmichaiSchreiber Acredito que o próximo lançamento do Django terá uma correção para este problema: code.djangoproject.com/ticket/27710
Will Hardy
2
Para qualquer um que vier aqui no futuro, esse problema foi corrigido no Django 2.1 .
humcat
45

Uma alternativa que usa criar para criar o objeto e salvá-lo no banco de dados em uma linha:

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