Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#31104 closed Bug (duplicate)

OneToOneField strange behavior when saving reference.

Reported by: Enrico Owned by: nobody
Component: Database layer (models, ORM) Version: 2.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have a model:

class LinePassenger(models.Model):
    user = models.ForeignKey(User, related_name='lines', on_delete=models.CASCADE)
    line = models.ForeignKey(Line, related_name='passengers', on_delete=models.CASCADE)

    home = models.OneToOneField(StopPoint, related_name='passenger_home', on_delete=models.SET_NULL, null=True)
    work = models.OneToOneField(StopPoint, related_name='passenger_work', on_delete=models.SET_NULL, null=True)

other fields...

The class has two methods, among others:

    def replace(self, line, point_payload):
        new_passenger = LinePassenger(user=self.user, line=line)
        new_passenger.home = StopPoint(
            address=self.home.address,
            coords=self.work.coords
        )
        new_passenger.work =  StopPoint(
            address=self.work.address,
            coords=self.work.coords
        )
        #this method already saves the stop points
        new_passenger.update_points_times(point_payload)

        new_passenger.save()
        self.save()

        return new_passenger


and:

    def update_points_times(self, payload):
        self.home.pickup_time = payload['pickup_time']
        self.work.dropoff_time = payload['dropoff_time']
        if 'return_route' in payload:
            self.home.dropoff_time = payload['return_route']['dropoff_time']
            self.work.pickup_time = payload['return_route']['pickup_time']
        self.home.save()
        self.work.save()

Now, when I call the first one (replace), it doen't record the OneToOne relation on the LinePassenger model.

I have fixed it with something rather strange:

    def replace(self, line, point_payload):
        new_passenger = LinePassenger(user=self.user, line=line)
        new_passenger.home = StopPoint(
            address=self.home.address,
            coords=self.work.coords
        )
        new_passenger.work =  StopPoint(
            address=self.work.address,
            coords=self.work.coords
        )
        #this method already saves the stop points
        new_passenger.update_points_times(point_payload)

        #don't ask, this seems to be a bug of django's OneToOneField
        new_passenger.home = new_passenger.home
        new_passenger.work = new_passenger.work
        new_passenger.save()

        self.save()

        return new_passenger

How does this even worked?

        new_passenger.home = new_passenger.home
        new_passenger.work = new_passenger.work

Seems to be related with https://stackoverflow.com/questions/21675461/django-onetoonefield-not-saving-instance

Sorry if this is not a bug.

Change History (4)

comment:1 by Mariusz Felisiak, 4 years ago

Resolution: duplicate
Status: newclosed
Summary: OneToOneField strange behavior when saving referenceOneToOneField strange behavior when saving reference.

Duplicate of #28147. This is related with the fact that you save child after already assigned parent.

comment:2 by Enrico, 4 years ago

So they say its fixed and the duplicated is closed, but it is not fixed. Way to go!

comment:3 by Mariusz Felisiak, 4 years ago

Enrico, it's fixed in Django 3.0. Django 2.1 is not supported anymore and this patch doesn't qualify for a backport to the Django 2.2.

comment:4 by Enrico, 4 years ago

Alright, thanks felixxm! Will consider moving to Django 3.0.

Note: See TracTickets for help on using tickets.
Back to Top