Skip to content

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

@rob101

Description

@rob101

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions