0

I have a method which has a required field for the author and a non-required field for co-authors. Sometimes the person which creates the post unintentionally, or because of the lack of knowledge, selects his/her own profile as a co-author. I would like to remove the actual author from the co-authors, and I think the best way to do it is overriding model's save() method. Here's what I have so far, but it doesn't seem to work.

models.py

from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _

User = get_user_model()


class Post(models.Model):
    PUBLICATION_STATUS_CHOICES = [
        ("PUBLIC", _("public")),
        ("PRIVATE", _("private")),
        ("DRAFT", _("draft")),
    ]

    title = models.CharField(max_length=100, verbose_name=_("post title"))
    summary = models.CharField(max_length=250, verbose_name=_("post summary"))
    content = models.TextField(verbose_name=_("post content"))
    is_markdown = models.BooleanField(default=True, verbose_name=_("Markdown"), help_text=_("Is this a post written in Markdown format?"))
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts", verbose_name=_("author of the post"))
    coauthors = models.ManyToManyField(User, blank=True, related_name="colab_posts", verbose_name=_("colaborators / co-authors"))
    date_created = models.DateTimeField(default=now, verbose_name=_("date of creation"))
    date_updated = models.DateTimeField(default=now, verbose_name=_("last update"))
    status = models.CharField(max_length=10, choices=PUBLICATION_STATUS_CHOICES, default=PUBLICATION_STATUS_CHOICES[0][0], verbose_name=_("post status"))
    slug = models.SlugField(unique=True, verbose_name=_("slug"))

    class Meta:
        ordering = ["-date_created"]
        verbose_name = _("post")
        verbose_name_plural = _("posts")

    def __str__(self):
        return f"{self.title} ← {self.author} ({self.date_created.strftime('%Y-%m-%d %H:%M:%S')})"

    def get_absolute_url(self):
        return reverse("blog:post_details", args=[self.slug])

    def save(self, *args, **kwargs):
        if self.author in self.coauthors.all():
            self.coauthors.remove(self.author)
        super(Post, self).save(*args, **kwargs)
  • are you using the django admin to add coauthors or just inside a view ? – Thierno Amadou Sow Apr 10 '22 at 16:02
  • I use both of those ways to create new posts. The users create the posts from a personalized page and I normally do it from the admin panel. I forgot to add that the same thing (removing duplicated author) should also happen when an existing post is being saved. – Danijela Popović Apr 10 '22 at 16:08

1 Answers1

0

IMO pre_save signal will be the best way to do that. Save your model as usual and then in pre_save signal remove author from coauthors.

example code:

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


@receiver(pre_save, sender=Post)
def validate_post_authors(sender, instance, created, **kwargs):
    post_author = instance.author
    instance.coauthors.remove(post_author)
Bartosz Stasiak
  • 1,415
  • 1
  • 4
  • 9
  • If I put this in a separated `signals.py`, is it enough to do ```def ready(self): import blog.signals ``` in the `apps.py`? – Danijela Popović Apr 10 '22 at 16:28
  • It should work. If not then read this questions: https://stackoverflow.com/questions/28135029/why-django-model-signals-are-not-working – Bartosz Stasiak Apr 10 '22 at 16:39
  • And what about the recursion? **RecursionError at /admin/blog/post/6/change/** - maximum recursion depth exceeded while calling a Python object – Danijela Popović Apr 10 '22 at 19:43
  • instance.save() might be causing that. Remove it – Bartosz Stasiak Apr 10 '22 at 19:54
  • This is strange... whatever I do, it still gives me the co-authors with the post author included in the template with ```

    {{ post.coauthors.all|join:", " }}

    ```, although it prints the value without the author from the signal function.
    – Danijela Popović Apr 10 '22 at 21:14
  • Can you try my updated answer with `if created` and `save`? – Bartosz Stasiak Apr 10 '22 at 21:52
  • Just did so, still having the same strange issue. – Danijela Popović Apr 10 '22 at 22:36
  • Well, this is becoming funny... I just saw that, when "created" is specified as a parameter, it works if the post is created or edited through the customized form. But the admin site and the signal don't compaginate for some reason... if I create or edit a post through the admin site, the duplicated author isn't removed. – Danijela Popović Apr 10 '22 at 22:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/243779/discussion-between-bartosz-stasiak-and-danijela-popovic). – Bartosz Stasiak Apr 11 '22 at 08:53