Boky
Boky

Reputation: 12064

Add and remove items in ManyToMany relation in Django

I have model as follows:

class BusinessUnitGroup(models.Model):
    name = models.CharField(max_length=255)
    business_units = models.ManyToManyField(to=BusinessUnit, blank=True, null=True)
    capacity = models.IntegerField(null=True, blank=True)

    def __unicode__(self):
        return self.name

Now in an view I have fields with group id's where the business unit needs to be added. From the other one it needs to be remove if it exists. I do it as follows:

business_unit = get_or_none(BusinessUnit, id=business_unit_id)

# Groups
old_groups = BusinessUnitGroup.objects.exclude(id__in=form_data['groups'])
for group in old_groups:
    group.business_units.remove(business_unit)

new_groups = BusinessUnitGroup.objects.filter(id__in=form_data['groups'])
for group in new_groups:
    group.business_units.add(business_unit)

Where form_data['groups'] is an param and it's just a list of ids [1, 2, 3]

That works fine, but is there any better way to do it?

UPDATE

@transaction.commit_on_success
def handle_edit_business_unit(form_data, company_id, business_unit_id):
    if not form_data:
        return {'result': 'nok', 'message': 'The form data is not provided.'}

    try:
        business_unit = get_or_none(BusinessUnit, id=business_unit_id)

        if business_unit:
            business_unit.name = form_data['name']
            business_unit.save()

            # Groups
            business_unit.businessunitgroup_set.set(form_data['groups'])
        

        return {'result': 'ok', 'message': ''}
    except Exception as err:
        # TODO Log error message somewhere
        print(str(err))
        return {'result': 'nok', 'message': 'The business unit could not be handled. Please try again.'}

Upvotes: 4

Views: 637

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

Yes, you can work with .set(…) [Django-doc]:

business_unit = get_or_none(BusinessUnit, id=business_unit_id)
business_unit.businessunitgroup_set.set(form_data['groups'])

We here thus work with the ManyToManyField in reverse. Instead of altering the BusinessUnitGroups by removing or adding a business_unit. We simply set the businessunitgroup_sets of the business_unit.

By setting the many-to-many field that way, this normally should work with two queries: one to remove all the items not in forms_data['groups'], and one that adds the form_data['groups'] to the business_unit.

Upvotes: 2

Related Questions