Dynamic "through" property in inherited ManyToMany fields

Hello, I’m having an issue with Inherited Models and ManyToMany fields.

My models are the following:

app1/models.py

class AbstractSite(models.Model):
    class Meta:
        abstract = True


class Site(AbstractSite):
    ...


app2/models.py

class OtherModel(models.Model):
    ...


app3/models.py

class Banner(Site):
    data = models.ManyToManyField(OtherModel, blank=True)

I know it’s not a good practice to create this coupling between various apps, but that’s how it is right now and I can’t change it.

The issue I’m having is that the data m2m field is now supposed to also be available for Site instances, not only Banner instances.

The first thing I’ve thought of was just to create a new m2m for the Site class, but this doesn’t seem right, since any new model that will inherit from the Site class and uses an m2m data field will need to be set manually.

Then I’ve tried to add the m2m to the abstract class, but this led me to have a single table in the DB with both banner.id and site.id being saved in the same object_id column. Disastrous.

What I’m looking for is a way to use the through parameter in the ManyToMany declaration in a dynamic manner, getting the class of the calling model and populating separate tables instead of the current way.

Is there a way to do it?

I’m assuming that Site is not an abstract class?

Keep in mind the underlying relationships created by your models.

AbstractSite doesn’t create a table, it’s just a set of field definitions to be implemented elsewhere.

Assuming it’s not abstract, Site creates a table.

Banner creates a second table, containing a OneToOne relationship with Site.

A ManyToMany table creates a join table, with two Foreign Keys, one to each table being joined.

So yes, you could create the M2M between Site and OtherModel, accessing Banner through the O2O link.

Or, you could create a set of M2M relationships between Banner (et al) and OtherModel.

Which then leads me to:

I’m not following what you’re saying here.

It may just be that I’m not sufficiently aware of your specific modelling issue, but I’m not seeing a problem with either of these situations.
What specifically is the issue you’re trying to address here?

1 Like

The issue is trying to automate the creation of a new intermediate table when a new child model class is created.

Right now, Banner is inheriting from Site, and the M2M exists only in the Banner Class.

But the Site class will now also have an M2M field for the same OtherModel class. So in order to avoid having repeated field declarations for these 2 classes (and also any other future child classes from Site), I’m trying to find a way to create a Generic ManyToMany field with a dynamic through property that respects the class that is calling.

The only abstract class is the AbstractSite. I know it does not creates tables, but the Site class does, and it monopolized the m2m field, making the records from child classes populate the same table.

There are no FK, M2M, O2O or other relationships between Site and Banner, it’s just parent and a child class.

Are you saying that the M2M from Site would be a disjoint set from the M2M from Banner?

If so, then just create two M2M fields, one for each model. You can reuse the field name across all the models having a O2O with Site.

I don’t see why this is a problem if those are disjoint relationships.

1 Like

Oh, ok, I was just worried about repeating code, but I’ll try it here, thanks Ken.