0
from django.db import models

class Reporter(models.Model):
    pass

class Article(models.Model):
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE, null=True)

Now whenever I add an article to a reporter (like below) I want to run some custom code, what method should I override (without changing bulk=True)?

>>> new_article = Article.objects.create()
>>> new_reporter = Reporter.objects.create()
>>> new_reporter.article_set.add(new_article, bulk=True)
Oskar Persson
  • 6,605
  • 15
  • 63
  • 124

1 Answers1

0

The answer will depend on how you create objects on your application, this will run the code the FIRST time an Article is added to a reporter

class Article(models.Model):
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        if self.reporter:
            if not self.reporter.article__set: 
                #do your code here
        super(Article, self).save(*args, **kwargs)

This will run the code if the Article on the reporter is changing

class Article(models.Model):
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        if self.reporter:
            if not self.reporter.article__set is self: 
                #do your code here
        super(Article, self).save(*args, **kwargs)

Haven't tested it but the logic seems sound

Mojimi
  • 2,561
  • 9
  • 52
  • 116
  • The save method isn't executed when running the example I provided – Oskar Persson Jan 26 '17 at 07:40
  • @OskarPersson the create method is a shortcut to creating and saving, also creating the Article without a reporter should give an error – Mojimi Jan 26 '17 at 13:33
  • You're right, it should. I updated the Article model with the reporter field being nullable. – Oskar Persson Feb 02 '17 at 22:42
  • @OskarPersson so, the solution would depend on how you create objects in your database, I'll update the answer – Mojimi Feb 03 '17 at 13:11
  • Once again, the save method isn't executed when running the example I provided. This doesn't work. – Oskar Persson Feb 03 '17 at 15:20
  • @OskarPersson unless you ovewrote the `create` method, it calls `save`, you have to call save in order for changes to take effect in your database. – Mojimi Feb 03 '17 at 15:25
  • But I want it to trigger whenever I **add to the relation**. This could be long after the creation of both objects and doesn't call `save` – Oskar Persson Feb 03 '17 at 15:37
  • @OskarPersson it does actually, any change made in an object needs to be saved in order to take effect in the database. Save is not called only on creation – Mojimi Feb 03 '17 at 17:09
  • [Here](https://docs.djangoproject.com/en/1.10/ref/models/relations/#django.db.models.fields.related.RelatedManager.add) is the documentation for `add` stating otherwise. _Note: I can't change bulk=True_ – Oskar Persson Feb 03 '17 at 17:13
  • @OskarPersson that's only with m2m as it says there, because the save method is called on the intermediary table, also it says how to listen to changes in m2m relationships – Mojimi Feb 03 '17 at 17:17
  • The example and the two lines following it are **clearly** talking about a Many-To-One relation. "In the example above, in the case of a ForeignKey relationship, QuerySet.update() is used to perform the update". And as the documentation for [`QuerySet.update()`](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#update) says: "Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save())" – Oskar Persson Feb 03 '17 at 17:22
  • @OskarPersson I see now, well is there a reason you want to use add? It seems that add is specifically aimed at being faster and not needing to save, which sounds like is what you need – Mojimi Feb 03 '17 at 17:26
  • Well, I need the speed. – Oskar Persson Feb 03 '17 at 17:27
  • @OskarPersson I think it's safe to say it is not possible at the moment, listeners will always hinder speed, you can always make a trigger at the db level which will also hinder speed – Mojimi Feb 03 '17 at 17:28