Django: Czy ustawić klucz obcy za pomocą liczby całkowitej?

104

Czy istnieje sposób na ustawienie relacji klucza obcego przy użyciu identyfikatora całkowitego modelu? Byłoby to dla celów optymalizacji.

Załóżmy na przykład, że mam model pracownika:

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

i

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

Chcę elastyczności związanej z nieograniczoną liczbą typów pracowników, ale we wdrożonej aplikacji prawdopodobnie będzie tylko jeden typ, więc zastanawiam się, czy istnieje sposób na zakodowanie identyfikatora i ustawienie relacji w ten sposób. W ten sposób mogę uniknąć wywołania db, aby najpierw pobrać obiekt EmployeeType.

Użytkownik
źródło

Odpowiedzi:

206

Tak:

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

ForeignKeypola przechowują swoją wartość w atrybucie z _idna końcu, do którego można uzyskać bezpośredni dostęp, aby uniknąć odwiedzania bazy danych.

_idWersja ForeignKeyjest szczególnie użyteczny aspekt Django, jeden, że każdy powinien wiedzieć i używanie od czasu do czasu, gdy właściwe.

zastrzeżenie:

@RuneKaagaard wskazuje, że employee.typenie jest to później poprawne w ostatnich wersjach Django, nawet po wywołaniu employee.save()(zachowuje swoją starą wartość). Użycie go oczywiście zniweczyłoby cel powyższej optymalizacji, ale wolałbym przypadkowe dodatkowe zapytanie niż nieprawidłowe. Więc bądź ostrożny, używaj tego tylko po zakończeniu pracy nad swoją instancją (np employee.).

Will Hardy
źródło
10
Czy to jest udokumentowane?
Scott Stafford
8
Bezpośrednie używanie
Dan Oliphant
1
Przetestowałem to dzisiaj na Django 1.7 i nie jest to dobry pomysł. Chociaż to działa, a typepole jest zapisywane w bazie danych, jeśli typepóźniej uzyskasz dostęp do właściwości, nie odzwierciedla to zmiany. Powiedział w kodzie, że to się nie powiedzie assert(employe.type.id == 4).
Rune Kaagaard
3
@AmichaiSchreiber Wierzę, że następne wydanie Django będzie miało poprawkę dla tego problemu: code.djangoproject.com/ticket/27710
Will Hardy,
2
Dla każdego, kto przyjedzie tutaj w przyszłości, ten problem został rozwiązany w Django 2.1 .
humcat
45

Alternatywa wykorzystująca create do stworzenia obiektu i zapisania go w bazie danych w jednej linii:

employee = Employee.objects.create(first_name='first', last_name='last', type_id=4)
Jacinda
źródło