Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically create One-To-One relation when using reverse field

When creating two instances of a model and connecting them using a OneToOneField, the connection gets created and saved automatically at object creation:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(primary_key=True, max_length=255)
    next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)

>>> m2 = MyModel.objects.create(name="2")
>>> m1 = MyModel.objects.create(name="1", next=m2)
>>> m2.prev
<MyModel: 1>
>>> m2.refresh_from_db()
>>> m2.prev
<MyModel: 2>

However, when creating the same connection but using the reverse field, the creation is also done automatically but not the save.

>>> m1 = MyModel.objects.create(name="1")
>>> m2 = MyModel.objects.create(name="2", prev=m1)
>>> m1.next
<MyModel: 2>
>>> m1.refresh_from_db()
>>> m1.next

Note that the last statement doesn't print anything since it returns None


How can I have it always save the relation when created using the reverse field without having to manually use .save() each time?

like image 755
Oskar Persson Avatar asked Mar 30 '17 13:03

Oskar Persson


People also ask

How do I create a one to many relationship in Django?

To define a one to many relationship in Django models you use the ForeignKey data type on the model that has the many records (e.g. on the Item model).

What is Primary_key true?

Since a primary key means a value that can uniquely identify an object. In the documentation on the primary_key parameter, we see: Field.primary_key. If True , this field is the primary key for the model.

What is OneToOneField in Django models?

One-to-one fields: This is used when one record of a model A is related to exactly one record of another model B. This field can be useful as a primary key of an object if that object extends another object in some way.

What is Onetoone field?

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True , but the "reverse" side of the relation will directly return a single object. In contrast to the OneToOneField "reverse" relation, a ForeignKey "reverse" relation returns a QuerySet .


1 Answers

Probably simple way to achieve this could be using pre_save/post_save signal which you see as a viable solution. But not sure how viable this answer would be, try to make some mods and see if this works!

from django.db.models.signals import post_save
from django.dispatch import receiver

class MyModel(models.Model):
    name = models.CharField(primary_key=True, max_length=255)
    next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)

@receiver(post_save, sender=MyModel)
def mymodel_post_save(sender, instance, **kwargs):
     if hasattr(instance, 'prev'): # if prev exists
          # now check if prev is added next
          if not instance.prev.next: # if next is not present 
                 instance.prev.next = instance
                 MyModel.objects.filter(
                     pk=instance.prev.pk
                 ).update(next=instance)
like image 166
rrmerugu Avatar answered Sep 22 '22 18:09

rrmerugu