django-multitenant icon indicating copy to clipboard operation
django-multitenant copied to clipboard

Conflict in wrap_many_related_manager_add() When Using Tenant Models in M2M Relationships

Open rob101 opened this issue 1 year ago • 1 comments

Description

We've encountered an issue with the wrap_many_related_manager_add() function, where it forcefully sets the tenant field in through_defaults for many-to-many relationships.

This results in a TypeError when the tenant field (tenant_id) is already set by other parts of the application. This issue occurs specifically when adding objects to a many-to-many field on a tenant model where the tenant context is inherently managed.

Expected Behavior

The add method should intelligently handle the presence of tenant fields in through_defaults, avoiding conflicts by not overwriting existing tenant identifiers.

Current Behavior

When the tenant field is already included in through_defaults, the wrap_many_related_manager_add() function still attempts to set it, leading to a TypeError due to multiple values for keyword argument tenant_id.

Steps to Reproduce

  • Define a many-to-many relationship in a tenant model where tenant_id is a critical field.
  • Use .add() to add an object to this relationship while the tenant context is set.
  • Observe that adding an object results in a TypeError if tenant_id is already specified.

Suggested Fix

Modify the wrap_many_related_manager_add() function to check if the tenant field is already present in through_defaults before setting it:

def wrap_many_related_manager_add(many_related_manager_add):
    def add(self, *objs, through_defaults=None):
        if hasattr(self.through, "tenant_field"):
            tenant_field = get_tenant_column(self.through)
            current_tenant = get_current_tenant_value()
            through_defaults = through_defaults or {}
            
            if tenant_field not in through_defaults:
                through_defaults[tenant_field] = current_tenant

        return many_related_manager_add(self, *objs, through_defaults=through_defaults)
    return add

rob101 avatar Apr 21 '24 08:04 rob101

I have submitted a PR https://github.com/citusdata/django-multitenant/pull/217

rob101 avatar Apr 21 '24 19:04 rob101