Home > Enterprise >  DRF: OneToOne relation with unique_together
DRF: OneToOne relation with unique_together

Time:03-04

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.

CodePudding user response:

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.

CodePudding user response:

Trying to understand unique together -

Code example -

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

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

Unique together here means every object of WorkSchedule will be unique when you compare considering two fields at a time.

Eg.- suppose first object is

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

Now no other object can have values employee = A and workday = A combined.

So other objects can have values such as (2 cases) -

  1. If employee value is A in any other object, workday must not be A. Otherwise, it will fail at unique together constrain.

  2. Same, if the workday value is A in any other object, the employee can not be A, Otherwise, it will again fail at unique together constrain.

Coming back to your question -

since you have used OneToOneField for employee in WorkSchedule, so by default there will be no two same values of employee and you can neglect using unique_together.

But again the result which you are expecting, will create two objects of WorkSchedule (from the result example) with the same employee and different workday. So you can not use OneToOneField, you will have to use ForeignKey for employee and make sure employee and workday are unique together.

It is also mentioned in the documentation that unique_together will be depreciated in the future, so you will have to code as mentioned by sir @Willem Van Onsem.

  • Related