Search code examples
djangosignalsmodels

Using a signal to create a new instance of a model when another models field changes


I'm trying to create a new ChatRoom whenever an Offer accepted field changes to True a Chatroom would be created for that Offer. What I did is a function that checks if an accepted field turns into a True so then it creates a ChatRoom. And then a post_save signal that creates the ChatRoom model and hook the fields together.

The problem is it works BUT only for the first Offer that has it's accepted field True. When tested it out, and changed the accepted field in another Offer to True I get the following error:

get() returned more than one Offer -- it returned 2!

Here are my models:

class Offer(models.Model):
    user = models.ForeignKey(User)
    post = models.ForeignKey(Post)
    comment = models.TextField()
    accepted = models.BooleanField(default=False)

    def __str__(self):
        return "{}".format(self.comment)

    class Meta:
        verbose_name_plural = "Offers"


class ChatRoom(models.Model):
    offer = models.ForeignKey(Offer)
    title = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = "Chat Rooms"

The function that I have used:

def create_chatroom_on_offer_accepted(sender, instance, **kwargs):
    if Offer.objects.get(accepted=True):
        ChatRoom.objects.create(offer=instance, title="Chatroom")

post_save.connect(create_chatroom_on_offer_accepted, sender=Offer)

Now the way I understand the error is that, it's trying to create a ChatRoom but it doesn't actually know which Offer exactly to choose from since there are 2.

How would I make sure that it knows the Offer accepted field that it's going to create the ChatRoom from? I thought of a custom save() function in the Offer model to detect the change in the field of accepted and that would trigger a post.save() signal to create a ChatRoom but I don't know exactly if that would work or not?


Solution

  • Change

    if Offer.objects.get(accepted=True):
    

    to

    if instance.accepted: