Problem with prefetch_related, when use related_names="+".

I don’t know much about prefetch and I may have missed something.

I use multiple many-to-many fields and declare the related_name with “+” to avoid creating reverse relationships.
This is a setting that cannot be changed.

The problem arises when using querysets with prefetch_related or call manytomany objects.
When I call an object belonging to a many-to-many relationship, the following error occurs.

django.core.exceptions.FieldError: Cannot resolve keyword '_post' into field. Choices are: id, name, slug

Because django request wrong table name.

	
(<Q: (AND: ('_post_tags_+__in', [<Post: (1)>, <Post: (2)>]))>,)

If I set related_name separately, this problem wouldn’t occur, but I can’t do that.

Is there any good way to solve this problem?

class Post:
    tag1 = related.ManyToManyField(
        Tag,
        related_name='+',
    )
    tag2 = related.ManyToManyField(
        Tag,
        related_name='+',
    )
    ...

class Tag:
  ...
for i in Post.objects.all().prefetch_related('tag1', 'tag2'):
  i.tags.all()
=> error
for i in Post.objects.all().prefetch_related(Prefetch('tag1', Tag.objects.all()), Prefetch('tag2', Tag.objects.all())):
  i.tag1.all()
=> error
  1. Why you cannot do that?

  2. I think that when you use related_name='+' , Django does not create a reverse relationship from the related model back to the model that defines the ManyToManyField .
    So you could Prefetch your query with something like this:

from django.db.models import Prefetch

# Prefetch related tags for tag1 and tag2
tag1_prefetch = Prefetch('tag1', queryset=Tag.objects.all())
tag2_prefetch = Prefetch('tag2', queryset=Tag.objects.all())

# Use prefetch_related with Prefetch objects
posts = Post.objects.all().prefetch_related(tag1_prefetch, tag2_prefetch)

# Access the prefetched tags
for post in posts:
    tag1_list = post.tag1.all()
    tag2_list = post.tag2.all()
    print(f"Post: {post.name}, Tag1: {[tag.name for tag in tag1_list]}, Tag2: {[tag.name for tag in tag2_list]}")

The presence of “_(underscore)” and “+(plus)” characters in query names was due to Django’s internal code.

Solving this requires editing Django internal code, and there doesn’t seem to be any way to modify it from outside.
Although I could solve the problem by overriding the Django code, I decided to give individual fields set unique related names.
It’s cumbersome to modify each model, but I think it’s simpler.