根据外键函数过滤 Django GenericRelation

Filter Django GenericRelation based on function on foreignkey

我想找到适合各种类别的与我的角色相关的属性。最终我想要这个输出:

"Attributes": {
        "Physical": {
            "Level": 1,
            "Strength": 1,
            "Dexterity": 1,
            "Stamina": 1
        },
        "Mental": {
            "Level": 2,
            "Intelligence": 1,
            "Wits": 1,
            "Resolve": 1
        },
        "Social": {
            "Level": 3,
            "Presence": 1,
            "Manipulation": 1,
            "Composure": 1
        }
    },

我有一个 Class/Enum(AutoNumber) 中的属性,以及查找哪个是哪个的方法:

class AttributeAbility(models.Model):

    class Attributes(AutoNumber):
        INTELLIGENCE = ()  # Mental, Power
        WITS = ()  # Mental', 'Finesse
        RESOLVE = ()  # Mental', 'Resistance
        STRENGTH = ()  # Physical', 'Power
        DEXTERITY = ()  # Physical', 'Finesse
        STAMINA = ()  # Physical', 'Resistance
        PRESENCE = ()  # Social', 'Power
        MANIPULATION = ()  # Social', 'Finesse
        COMPOSURE = ()  # Social', 'Resistance

    attribute = EnumField(Attributes)

    @property
    def attribute_type(self):
        attribute_group = lambda attribute: (
            int((attribute.value - 1) / 8)) + 1 % 3

        return Category(attribute_group(self.attribute))

class Category(AutoNumber):
    MENTAL = ()
    PHYSICAL = ()
    SOCIAL = ()

我使用这些 类:

将 AttributeAbility 与我的角色连接起来
class CrossCharacterMixin(models.Model):
    cross_character_types = models.Q(app_label='mage', model='mage')
    content_type = models.ForeignKey(ContentType, limit_choices_to=cross_character_types,
                                     null=True, blank=True)
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    class Meta:
        abstract = True

class CharacterAttributeLink(Trait, CrossCharacterMixin):
    MIN = 1
    PRIORITY_CHOICES = (
        (0, 'Unassigned'), (1, 'Primary'), (2, 'Secondary'), (3, 'Tertiary')
    )
    attribute = models.ForeignKey('AttributeAbility')
    priority = models.PositiveSmallIntegerField(
        choices=PRIORITY_CHOICES, default=0
    )

    def __str__(self):
        return self.attribute.attribute.label

然后在法师上我有:

attributes = GenericRelation('CharacterAttributeLink')

@property
def physical_attributes(self):
    type_id = Category['PHYSICAL']
    return self.attributes.filter(attribute_type=type_id)

但我得到的错误是:Cannot resolve keyword 'attribute_type' into field. Choices are: attribute, attribute_id, content_type, content_type_id, current_value, id, maximum_value, object_id, priority

我的功能是这样的:

@property
def physical_attributes(self):
    type_id = Category['PHYSICAL']
    return self.attributes.filter(attribute__attribute_type=type_id)

我收到此错误:Related Field got invalid lookup: attribute_type 这有一定道理(尽管我在文档中看到过:>>> Entry.objects.filter(blog_id=4))。

在末尾添加 __exact,得到以下信息:Relation fields do not support nested lookups...此时我迷路了。我需要 custom manager 吗?我需要将我的 physical_attribute 函数移到别处吗?

我最终创建了一个自定义管理器:

class CategoryManager(models.Manager):

    '''
    Class to manage instances that rely on the category enum
    '''

    def physical(self):
        return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
                if categorised_item.category == Category['PHYSICAL']]

    def mental(self):
        return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
                if categorised_item.category == Category['MENTAL']]

    def social(self):
        return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
                if categorised_item.category == Category['SOCIAL']]

然后将其添加到我的 AttributeAbility 模型中:

objects = CategoryManager()

并在我的角色模型上定义这个 属性:

@property
def social_skills(self):
    return [self.skills.filter(skill=skill) for skill
            in SkillAbility.objects.social()]