DRF: Отношение OneToOne с unique_together

Я пытаюсь понять, как использовать отношение OnetoOne с unique_together. В настоящее время я пытаюсь использовать их в сериализаторе и представлении, но безуспешно.

Модели:

class Employees(models.Model):
    name = models.CharField()
    position = models.CharField()
    phone = models.IntegerField()


class WorkSchedule(models.Model):
    employee = models.OneToOneField('Employees')
    workday = models.DateTimeField()

    class Meta:
        unique_together = (('employee', 'workday'),)

Первый вопрос: Поскольку отношение OneToOne, если бы у меня не было unique_together, то каждый сотрудник мог бы появиться в WorkSchedule один раз. Однако, поскольку у меня есть unique_together, это уже не так. Правильно?

Второй вопрос: Как я могу использовать такие модели для возврата всех сотрудников и их рабочих графиков, например, так

{
    "employees": [
        {
            "employee": "John",
            "workschedule": [
                {
                    workday: "2022-03-03"
                },
                {
                    workday: "2022-03-04"
                }
        },
        {
        
            "employee": "Tom",
            "workschedule": [
                {
                    workday: "2022-03-03"
                },
                {
                    workday: "2022-03-04"
                }
        }
}

Я смог сделать это с помощью ForeignKey (без unique_together) и вложенного сериализатора, однако я не смог сделать это с помощью двух моделей, как они указаны выше.

Первый вопрос: Поскольку отношение OneToOne, если бы у меня не было unique_together, то каждый сотрудник мог бы появиться в WorkSchedule один раз. Однако, поскольку у меня есть unique_together, это уже не так. Правильно?

Нет: OneToOneField - это ForeignKey с ограничением однократности. Тот факт, что вы позже определите дополнительное ограничение, не имеет значения. Это означает, что ваш unique_together не имеет никакого влияния: поскольку OneToOneField уже гарантирует, что employee уникален, это подразумевает, что комбинация с workday будет уникальной, даже без указания unique_together.

Таким образом, вы должны использовать ForeignKey, поэтому:

class WorkSchedule(models.Model):
    employee = models.ForeignKey('Employees', on_delete=models.CASCADE)
    workday = models.DateTimeField()

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['employee', 'workday'], name='unique_employee_workday')
        ]

Второй вопрос: Как я могу использовать такие модели для возврата всех сотрудников и их рабочих графиков, например, так.

Используя ForeignKey. Здесь нет смысла использовать OneToOneField: это имеет смысл, только если у каждого WorkSchedule есть ровно один Employee, а у каждого Employee есть максимум один WorkSchedule.


Примечание: Как говорится в документации по unique_together [Django-doc], ограничение unique_together, вероятно, станет устаревшим. Документация советует использовать UniqueConstraint [Django-doc] от Django constraint framework.

Пытаемся вместе понять уникальное -

Пример кода -

class WorkSchedule(models.Model):
    employee = models.CharField()
    workday = models.CharField()

    class Meta:
        unique_together = (('employee', 'workday'),)

Unique вместе здесь означает, что каждый объект WorkSchedule будет уникальным при сравнении двух полей за один раз.

Например, предположим, что первым объектом является

{
    "employee" : "A"
    "workday" : "A"
}

Теперь ни один другой объект не может иметь значения employee = A и workday = A объединенные.

Так что другие объекты могут иметь такие значения, как (2 случая) -

  1. Если значение employee является A в любом другом объекте, workday должен не быть A. В противном случае он потерпит неудачу при уникальном ограничении вместе.

  2. Также, если значение workday является A в любом другом объекте, то employee не может быть A, Иначе, это снова приведет к неудаче в unique together constrain.

Возвращаясь к вашему вопросу -

поскольку вы использовали OneToOneField для employee в WorkSchedule, то по умолчанию не будет двух одинаковых значений employee и вы можете пренебречь использованием unique_together.

Но опять же результат, который вы ожидаете, создаст два объекта WorkSchedule (из примера результата) с одинаковым сотрудником и разным рабочим днем. Поэтому вы не можете использовать OneToOneField, вам придется использовать ForeignKey для сотрудника и убедиться, что сотрудник и рабочий день уникальны вместе.

В документации также упоминается, что unique_together будет обесценен в будущем, поэтому вам придется кодировать так, как упомянул сэр @Willem Van Onsem.

Вернуться на верх