Модели Django: выбор по умолчанию для выбора внешнего ключа - PullRequest
1 голос
/ 20 октября 2019

У меня есть класс модели Type следующим образом:

class Type(models.Model):
    ENVIRONMENT = 'A'
    HUMANENV = 'B'
    HUMAN = 'C'
    ANIMAL = 'D'
    UNKNOWN = 'H'
    TYPE_CHOICES = [
        (ENVIRONMENT, 'Environment'),
        (HUMANENV, "Human-related Environment"),
        (HUMAN, 'Human'),
        (ANIMAL, 'Animal'),
        (UNKNOWN, 'Unknown'),
    ]
    code = models.CharField(max_length=1, choices=TYPE_CHOICES, unique=True)

    class Meta:
        ordering = ['code']

    def __str__(self):
        return self.get_code_display()

И еще один пример модели, где одно из полей является внешним ключом для модели типа следующим образом:

class Sample(models.Model):
    sample_id = models.CharField(max_length=20, unique=True)
    type = models.ForeignKey("Type", on_delete=models.CASCADE, blank=True, default=get_default_type())

    class Meta:
        ordering = ["sample_id"]

    def __str__(self):
        return self.sample_id

где get_default_type - это функция, которая возвращает pk для экземпляра модели типа по умолчанию:

def get_default_type():
    return Type.objects.get(code="H").id

Проблема в том, что когда я запускаю Sample.objects.create (sample_id = "some_id"), она выдает мне ошибку

IntegrityError: null value in column "type_id" violates not-null constraint
DETAIL:  Failing row contains (28113, some_id, null).

Как вы можете видеть во второй строке сообщения об ошибке, type_id имеет значение null вместо pk, как возвращено функцией get_default_type.

Я попытался установить null = True для внешнего ключа, и когда я это сделаю, я смогу создать экземпляр модели Sample, но с типом None вместо типа Unknown, как я хотел. Как я могу это исправить?

1 Ответ

0 голосов
/ 20 октября 2019

Два решения:

Переопределить менеджера

Из этого ответа вы можете использовать get_by_natural_key в вашем менеджере.

В managers.py

from django.db import models
class TypeManager(models.Manager):
    """Enable fixtures using self.sigla instead of `id`"""

    def get_by_natural_key(self, code):
        return self.get(code=code)
class Type(models.Model):
    #.... Declare your model here
    objects = Type()

или ...

Измените свой pk!

class Type(models.Model):
    #.... Declare your model here
    code = models.CharField(max_length=1, choices=TYPE_CHOICES, unique=True, primary_key=True)

В любом случае, в объявлении связанной модели:

class Sample(models.Model):
    type = models.ForeignKey("Type", on_delete=models.CASCADE, blank=True, default='H')

    class Meta:
        ordering = ["sample_id"]

    def __str__(self):
        return self.sample_id

Примечание: пожалуйста, позаботьтесь о type. Это защищенное ключевое слово и не должно использоваться.

...