Автогенерируемые Django модели и отношения не отображаются в мета модели

У меня есть следующий код для создания модели Vote для любой данной другой модели, к которой я хочу присоединить это отношение.

from functools import lru_cache

from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import gettext_lazy as _

from apps.common.models.base import BaseModel
from apps.common.utils import camel_to_snake


@lru_cache(maxsize=None)
def create_vote_class(klass):
    class Vote(BaseModel):
        class VoteType(models.IntegerChoices):
            UPVOTE = 1, _("Upvote")
            DOWNVOTE = -1, _("Downvote")

        user = models.ForeignKey(
            get_user_model(),
            on_delete=models.CASCADE,
            related_name=f"{camel_to_snake(klass.__name__)}_votes",
            verbose_name=_("User"),
            help_text=_("The voter."),
        )
        post = models.ForeignKey(
            klass,
            on_delete=models.CASCADE,
            related_name=f"{camel_to_snake(klass.__name__)}_votes",
            verbose_name=_("Post"),
            help_text=_("The post this vote is for."),
        )
        body = models.IntegerField(
            choices=VoteType.choices,
            verbose_name=_("Body"),
            help_text=_("The actual vote. -1 or +1"),
        )

        def type(self):
            return self.get_body_display()

        class Meta:
            abstract = True
            app_label = klass._meta.app_label  # NOQA

    klass_name = f"{klass.__name__}Vote"
    bases = (Vote,)

    class Meta:
        app_label = klass._meta.app_label  # NOQA
        verbose_name = _(klass_name)
        verbose_name_plural = _(f"{klass_name}s")

    klass_dict = {"__module__": klass.__module__, "Meta": Meta}
    vote_class = (type(klass_name, bases, klass_dict)  # NOQA
    return vote_class


class VoteMaker:
    is_relation = True
    many_to_many = True

    def __init__(self, **kwargs):
        self.related_name = kwargs.get("related_name")
        self.vote_class_attribute_name = kwargs.get("vote_class_attribute_name")

    def contribute_to_class(self, cls, name):
        setattr(cls, self.vote_class_attribute_name, create_vote_class(cls))
        setattr(cls, name, self.get_votes_field(cls))

    def get_votes_field(self, cls):
        field = models.ManyToManyField(
            get_user_model(),
            through=create_vote_class(cls),
            related_name=self.related_name or f"voted_{camel_to_snake(cls.__name__)}s",
            verbose_name=_("Votes"),
            help_text=_("Votes for this post."),
        )
        return field


def votes(related_name=None, vote_class_attribute_name="vote_class"):
    vote_maker = VoteMaker(
        related_name=related_name,
        vote_class_attribute_name=vote_class_attribute_name,
    )
    return vote_maker

Я использую его следующим образом:

class Post(BaseModel):
    votes = votes()

Генерируется модель Vote, связанные имена и имена атрибутов в модели корректны, я могу запросить модель Vote, там все хорошо.

Но теперь, когда я пытаюсь создать страницу администратора для этой модели Post:

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    fields = ["votes"]

Я получаю ошибку:

Unknown field(s) (votes) specified for Post. Check fields/fieldsets/exclude attributes of class PostAdmin.

Я пытался углубиться в исходный код, но пока добрался только до

model._meta._get_fields(reverse=False) 

вызывается, в котором должно быть мое поле m2m, голоса, но его нет.

Кто-нибудь может указать мне правильное направление, как решить эту проблему?

Редактирование 1:

Экстра:

In [1]: from apps.core.models import *

In [2]: Post.votes
Out[2]: <django.db.models.fields.related.ManyToManyField>

In [3]: 

Как вы видите, Post.votes действительно является полем ManyToMany

Редактирование 2:

Продвигаясь вперед, я обнаружил, что это не должно выглядеть так, как в редактировании 1 выше.

Например, в модели пользователя:

ipdb> User.groups
<django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x1334e5a90>

Итак, я немного изменил свой первоначальный код, и теперь он выглядит следующим образом:

def contribute_to_class(self, cls, name):
    setattr(cls, self.vote_class_attribute_name, create_vote_class(cls))
    self.get_votes_field(cls).contribute_to_class(cls, name)

что помогло справиться с некоторыми проблемами.

ipdb> Post._meta.many_to_many
(<django.db.models.fields.related.ManyToManyField: comments>, <django.db.models.fields.related.ManyToManyField: votes>)

Теперь я могу видеть множество полей, но теперь у меня все еще есть некоторые проблемы в других частях django, все еще связанные с администратором.

Полный отслеживание:

Вернуться на верх