AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'. Did you mean: 'm2m_reverse_name'?

                                       currentmon.altforms.add(MonSpecies.objects.get(name=da,basepack=newpack))

^ running throws up a

AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'. Did you mean: 'm2m_reverse_name'?

(currentmon is a MonSpecies object, da is a string, newpack is an object)

models.py:

class MonSpecies(models.Model):
[...]
    altforms = models.ManyToManyField("self",through="MonFormData")
[...]
class MonFormData(models.Model):
    MonForm = models.ForeignKey("MonSpecies", on_delete=models.CASCADE)
    FormChangeItem = models.ForeignKey("OtherMonItemTags", on_delete=models.CASCADE)
[...]
class OtherMonItemTags(models.Model):
    name = models.CharField(max_length=50)

help

Welcome @HimejoshiHeart !

Please post the complete view containing this code along with the full error message and traceback. It may also be helpful to see the complete models - at least to see all the fields being referenced.

A follow-up: One of the reasons I’m asking for the full models is that what you are showing is an invalid definition of your through model.

A through model of a ManyToManyField where the relationship is defined by "self" consists of two ForeignKey fields - both referring to the same model. (See the second green “Note” box at Model field reference | Django documentation | Django)

The portion of the definition you are showing here shows two ForeignKey fields referencing two different models, which is inconsistent with the "self" definition.

The issue is with the definition of the intermediary model.

Because altforms is a self-referencing relationship:

altforms = models.ManyToManyField("self", through="MonFormData")

Django expects MonFormData to contain two foreign keys to MonSpecies: one for the source species and one for the alternate species.

FormChangeItem can remain as an additional field on the relationship:

class MonSpecies(models.Model):
    altforms = models.ManyToManyField(
        "self",
        through="MonFormData",
        through_fields=("base_species", "alt_species"),
        symmetrical=False,
        related_name="base_forms",
    )


class MonFormData(models.Model):
    base_species = models.ForeignKey(
        MonSpecies,
        on_delete=models.CASCADE,
        related_name="form_data_as_base",
    )
    alt_species = models.ForeignKey(
        MonSpecies,
        on_delete=models.CASCADE,
        related_name="form_data_as_alt",
    )
    form_change_item = models.ForeignKey(
        "OtherMonItemTags",
        on_delete=models.CASCADE,
    )


class OtherMonItemTags(models.Model):
    name = models.CharField(max_length=50)

The through_fields argument explicitly tells Django which foreign key is the source and which is the target. Without it, Django uses the first foreign key to MonSpecies as the source and the second as the target.

Then the relationship can be created like this:

target = MonSpecies.objects.get(
    name=da,
    basepack=newpack,
)

currentmon.altforms.add(
    target,
    through_defaults={
        "form_change_item": change_item,
    },
)

Or directly through the intermediary model:

MonFormData.objects.create(
    base_species=currentmon,
    alt_species=target,
    form_change_item=change_item,
)

change_item must be an instance of OtherMonItemTags.

If FormChangeItem is not actually needed as extra data, remove the through model and use a normal self-referencing many-to-many field:

altforms = models.ManyToManyField("self", symmetrical=False)

Then currentmon.altforms.add(target) will work directly.