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?
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).
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.
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.
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 .
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With