Search code examples
pythondjangodjango-modelsdjango-rest-frameworkdjango-serializer

DRF: OneToOne relation with unique_together


I am trying to understand how to use a OnetoOne relation with unique_together. Currently trying to make use of them in my serializer and view with no success.

Models:

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'),)

First question: Since the relation is OneToOne if i didn't have unique_together then each employee could appear in WorkSchedule once. However since i have unique_together this is not the case anymore. Correct?

Second Question: How would i use such models to return all employees and their workschedules like this

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

I was able to do this with using a ForeignKey(no unique_together) and a Nested Serializer however i wasn't able to do it with using the two models as they are above.


Solution

  • First question: Since the relation is OneToOne if i didn't have unique_together then each employee could appear in WorkSchedule once. However since i have unique_together this is not the case anymore. Correct?

    No: a OneToOneField is a ForeignKey with a uniqness constraint. The fact that you later define an extra constraint does not matter. This thus means that your unique_together has no impact: since the OneToOneField already guarantees that the employee is unique, this implies that the combination with the workday will be unique, even without specifying a unique_together.

    You thus should thus use a ForeignKey, so:

    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')
            ]

    Second Question: How would i use such models to return all employees and their workschedules like this.

    By using a ForeignKey. It make no sense here to use a OneToOneField: this only makes sense if each WorkSchedule has exactly one Employee, and each Employee has at most one WorkSchedule.


    Note: As the documentation on unique_together [Django-doc] says, the unique_together constraint will likely become deprecated. The documentation advises to use the UniqueConstraint [Django-doc] from Django's constraint framework.