Tankard666
Tankard666

Reputation: 29

Update datetimefiled of all related models when model is updated

I have two models (Post and Display). Both have Datetime-auto fields. My problem is that i want to update all display objects related to a post, once a post is updated.

I have read here that you could override one models save method, but all the examples are About updating the model with the foreign key in it and then call the save method of the other model. In my case it's the other way arround. How can i do this ?

class Post(models.Model):
    title = models.CharField(max_length=40)
    content = models.TextField(max_length=300)
    date_posted = models.DateTimeField(auto_now=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    rooms = models.ManyToManyField(Room, related_name='roomposts',  through='Display')


    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return "/post/{}/".format(self.pk)

class Display(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    room = models.ForeignKey(Room, on_delete=models.CASCADE)
    isdisplayed = models.BooleanField(default=0)
    date_posted = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.isdisplayed)

i want to update the date_posted of all related Display-objects once their related post is changed. I do not know if overriding the save-method works here.

Upvotes: 0

Views: 33

Answers (2)

Botte Oleksandr
Botte Oleksandr

Reputation: 144

Overriding save method works, but that's not were you should go, imo.

What you need is signals:

@receiver(post_save, sender=Post)
def update_displays_on_post_save(sender, instance, **kwargs):
    if kwargs.get('created') is False:  # This means you have updated the post
        # do smth with instance.display_set

Usually it goes into signals.py. Also you need to include this in you AppConfig

def ready(self):
    from . import signals  # noqa

Upvotes: 1

rabbit.aaron
rabbit.aaron

Reputation: 2607

in this case you should have a look at django's reverse foreign key documentation https://docs.djangoproject.com/en/2.2/topics/db/queries/#following-relationships-backward

in your case you can override the save method on your Post model

def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    #either: this excutes many sql statments
    for display in self.display_set.all():
        display.save()
    #or faster: this excute only one sql statements,
    #but note that this does not call Display.save
    self.display_set.all().update(date_posted=self.date_posted)

The name display_set can be changed using the related_name option

in Display, you can change it:

post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='displays')

Then, instead of using self.display_set in your code, you can use self.displays

Upvotes: 1

Related Questions