在 Django 中自动填充一组通用的多对多字段?

Posted

技术标签:

【中文标题】在 Django 中自动填充一组通用的多对多字段?【英文标题】:Autopopulate a set of generic many to many fields in Django? 【发布时间】:2015-04-10 19:29:29 【问题描述】:

我正在尝试将this 答案和这个one 结合起来,并带有一点 for 循环。

在创建角色时,我想添加值为 0 的所有可能技能,但我对如何遵循上述答案感到困惑。

我有这个混音:

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

(最终,cross_character_types 将被扩展)

还有这个模型:

class CharacterSkillLink(Trait, CrossCharacterMixin):
    PRIORITY_CHOICES = (
        (1, 'Primary'), (2, 'Secondary'), (3, 'Tertiary')
    )
    skill = models.ForeignKey('SkillAbility')
    priority = models.PositiveSmallIntegerField(
        choices=PRIORITY_CHOICES, default=None)
    speciality = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        spec_string = " (" + self.speciality + ")" if self.speciality else ""
        return self.skill.skill.label + spec_string

我开始写的是这个,在 NWODCharacter 模型上:

def save(self, *args, **kwargs):
    if not self.pk:
        character_skills_through = CharacterSkillLink.content_object.model

        CharacterSkillLink.objects.bulk_create([
            [character_skills_through(skill=SkillAbility(
                skill), content_object=self) for skill in SkillAbility.Skills]
        ])

    super(NWODCharacter, self).save(*args, **kwargs)

这不起作用,因为我认为我传递的对象不正确。

虽然基于此answer:

from django.db import models

class Users(models.Model):
    pass

class Sample(models.Model):
    users = models.ManyToManyField(Users)

Users().save()
Users().save()

# Access the through model directly
ThroughModel = Sample.users.through

users = Users.objects.filter(pk__in=[1,2])

sample_object = Sample()
sample_object.save()

ThroughModel.objects.bulk_create([
    ThroughModel(users_id=users[0].pk, sample_id=sample_object.pk),
    ThroughModel(users_id=users[1].pk, sample_id=sample_object.pk)
])

在这种情况下,我的ThroughModel 是什么?是CharacterSkillLink.content_object.model吗?

如何在我的场景中执行此操作?如果这是微不足道的,我很抱歉,但我正在努力解决它。

【问题讨论】:

能否让我知道如何改进问题? 【参考方案1】:

在我看来,CharacterSkillLink 在这种情况下本身就是您的直通模型...它通常将内容类型连接到 SkillAbility

如果您考虑一下,如果您正在执行bulk_create,那么您传入的对象必须与您正在执行bulk_create 的模型相同。

所以我认为你想要这样的东西:

def save(self, *args, **kwargs):
    initialise_skill_links = not self.pk
    super(NWODCharacter, self).save(*args, **kwargs)
    if initialise_skill_links:
        CharacterSkillLink.objects.bulk_create([
            CharacterSkillLink(
                skill=SkillAbility.objects.get_or_create(skill=skill)[0],
                content_object=self
            )
            for skill in SkillAbility.Skills
        ])

请注意,您的 bulk_create 中有太多的 [] 对。

另外我认为你应该使用SkillAbility.objects.get_or_create()... 作为你需要相关对象存在的外键。如果它已经存在,只是做SkillAbility() 不会从数据库中获取它,如果它不存在,则不会将它保存到数据库中。

【讨论】:

刚刚下班回家。明天会尝试使用这个。顺便说一句,你是对的,CharacterSkillLink 是我的原型……我不知道我在想什么。 这在我的管理页面上运行良好,但它没有在该内联的下拉框中(单独的问题)显示任何技能。我删除了内联以查看它是否会创建和保存技能,但现在它给了我两个错误。第一个在错误页面的顶部:ValueError at /admin/characters/mage/add/Cannot assign "(<SkillAbility: Academics>, False)": "CharacterSkillLink.skill" must be a "SkillAbility" instance. 然后,Error in formatting: 'CharacterSkillLink' object has no attribute 'speciality' 设置 speciality = "" 并指定无效。帮忙? 我发现问题get_or_create返回一个元组,技能被分配给这个元组,而不是SkillAbility对象。这似乎应该可以工作(它不会出错),但我认为它不起作用。我添加了一个 GenericRelation 到它,当我保存并尝试访问 mage_instance.skills.all() 它返回并清空列表。 我已经用你想要做的编辑更新了答案,还添加了[0] 来处理元组问题 是的,问题是还没有object_id 可以设置,因为我们在if not self.pk 块中执行此代码...将更新答案

以上是关于在 Django 中自动填充一组通用的多对多字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何在引导选项卡块中按 django 模板中的多对多字段过滤对象

CASCADE 究竟如何与 Django 中的多对多字段一起工作

DJANGO:与附加字段的多对多关系

Django,使用最低参数的多对多字段元素的ID注释字段

如何过滤和访问 Django QuerySet 中的多对多字段?

从 Django QuerySet 中获取所有相关的多对多对象