在Django中指定一组相关字段时,公认的最佳实践是什么?

2024-03-29 14:22:30 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我在Django中为RPG创建了一个“角色”模型,我希望所有属性(力量、灵活性、耐力等)都以类似的方式定义,并且能够以类似的方式进行处理。在

显然我可以做到:

intelligence = IntegerRangeField(min_value=1, max_value=10)
wits= IntegerRangeField(min_value=1, max_value=10)
resolve = IntegerRangeField(min_value=1, max_value=10)
strength = IntegerRangeField(min_value=1, max_value=10)
dexterity = IntegerRangeField(min_value=1, max_value=10)
stamina = IntegerRangeField(min_value=1, max_value=10)
presence = IntegerRangeField(min_value=1, max_value=10)
manipulation = IntegerRangeField(min_value=1, max_value=10)
composure = IntegerRangeField(min_value=1, max_value=10)

集成字段definition

但这并不是特别的DRY。这也意味着,当我增加30种相似的技能时,我会变得更不枯燥,更容易出错。在

这些似乎不值得通过外键创建(这是解决方案here),因为我需要为每个属性指定9个外键

有没有解决这个问题的办法已经是干的了?或者我需要自己动手吗?在

编辑:
我对属性和技能的主要用途是提供技能检查的总数,例如,如果我想知道要掷多少骰子,Programming我可以指定它使用字符intelligence+computers属性和技能,例如,从“任务”列表中(例如,其他属性和技能的组合)显示角色可以执行的前五项。在


编辑:

看来走M2M路线导致我过度正常化。有人能suggest improvements吗?在


Tags: django模型角色编辑属性value技能方式
3条回答

对于这种需要重复字段的情况(如@ronaldenburger建议),可以使用多对多字段关系。例如:

class Skill(models.Model):
    name = models.CharField(max_length=255)
    value = IntegerRangeField(min_value=1, max_value=10)

class Character(models.Model):
    name = models.CharField(max_length=255)
    skill = models.ManyToManyField(Skill)

如果使用modelform创建一个Character模型实例,那么可以使用model formset factory向其添加Skill。在

你为什么不直接用^{}工作呢?在

这样您就可以轻松地添加和管理这些属性。而且更易于管理,因为在您的情况下,您必须为每个属性添加一列。在

好吧,我会被指责死亡,但也有MonkeyPatch技术(我喜欢和使用它,但可能导致可读性差),或者你可以做一个简单的捷径。

这里的猴子补丁,它的最好部分是,如果你有一个技能索引,你可以使用它:

SKILLS = ["skill_1", "skill_2", "skill_3"]
for skill in SKILLS:
    IntegerRangeField(
        min_value=min_value, max_value=max_value
    ).contribute_to_class(MyModel, skill)

注意:它在迁移时很好地工作,同时将其保存在正确的应用程序模型文件中

以下是快捷方式:

^{pr2}$

希望它能帮上忙。

编辑:建议将重复的丑陋部分拆分,列出其他文件中所有字段,以便有新的可能性,在抽象类中隐藏大量不干法的代码(或拆分型号.py但这很难解释)。

^{pr3}$

然后在你的型号.py(2):

^{pr4}$

这里是关于抽象类的更多信息:https://docs.djangoproject.com/en/1.7/topics/db/models/#abstract-base-classes

或者,如果你是一个有趣的人,你可以把所有的东西都结合在一起:

此处为工具:

def skill_fields(*skills):
    class MyAbstractModel(models.Model):
        class Meta:
            abstract = True

    for skill in skills:
        new_skill().contribute_to_class(MyAbstractModel, skill)
    return MyAbstractModel

这里的用法:

from skills_utils import skill_fields

class Character(skill_fields("skill_1", "skill_2", *settings.MY_APP_SKILL_LIST)):
    name = CharField(max_length=128)

但这最后一个是给那些只有最幽默的人;-)

如果我是你,如果你想拥有一些更大或更小范围的特殊技能,我会选择一种让你更开放的快捷方式,而且对于那些能在你之后接受项目的人来说,它更容易理解。

相关问题 更多 >