2

I want to create_or_update in m-m through model field

This is my models.py

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    is_featured = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

In my view.py Below code is work perfectly fine

person_obj = Person.objects.get(id=1)
group_obj = Group.objects.get(id=1)
group_obj.add(person_obj, through_defaults={'is_featured': False, 'is_active': True})

Now for same group_obj and person_obj I want to update is_featured = True in membership model.

How can i do that? I can do it by filtering Membership table and update fields but i guess it is not a good practice. I wanted to do it by better solution.

I have tried with same line

group_obj.member.add(person_obj, through_defaults={'is_featured': True, 'is_active': True})

but it is not updating that field.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
Somil
  • 1,921
  • 1
  • 21
  • 35
  • Why do you think "filtering Membership table and update fields" is not the right answer? On the contrary, that is exactly what you should do: `Membership.objects.filter(group=group_obj, person=person_obj).update(is_featured=True)`. – Daniel Roseman Nov 15 '19 at 12:13
  • @DanielRoseman It will work. but I am searching for better way to do it like update_or_create. – Somil Nov 15 '19 at 12:23
  • @Somil: the problem is that you do not want `is_active` to be updated I think? – Willem Van Onsem Nov 15 '19 at 12:24
  • no , it depends on request data, if is_active is present in request data then it should be update. – Somil Nov 15 '19 at 12:26
  • @Somil: given it is not in the request data, and the membership does *not* exist, then what should happen? – Willem Van Onsem Nov 15 '19 at 12:27
  • @WillemVanOnsem request data is just like {'is_featured': True, 'is_active': True} – Somil Nov 15 '19 at 12:30
  • @Somil: I am trying to reproduce `group_obj.add(person_obj, .....)` but I get: `AttributeError: 'group_ob' object has no attribute 'add'` Did this really work as it is? – Gathide May 20 '21 at 13:18

1 Answers1

0

You can perform an .update_or_create(..) call [Django-doc] on the Membership model:

Membership.objects.update_or_create(
    person_id=person_id,
    group_id=group_id,
    defaults={'is_active': True, 'is_featured': True}
)

Here it will thus make a query where it looks if there already exists a Membership object for the given person_id and group_id. If not, it will construct one, with as values for is_active and is_featured here True (as specified in the defaults). If the Membership object already exists, then it will update both is_active and is_featured to True.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555