如何隐式(动态)在模板中显示模型的属性

时间:2015-04-21 07:53:45

标签: django django-models django-templates django-views

我正在为我的游戏制作一个高分的应用程序。 这是我的模特

class Skills(models.Model):
    attack = models.IntegerField(default=1)
    attack_xp = models.FloatField(default=0)

    constitution = models.IntegerField(default=10)
    constitution_xp = models.FloatField(default=0)

    mining = models.IntegerField(default=1)
    mining_xp = models.FloatField(default=0)

    strength = models.IntegerField(default=1)
    strength_xp = models.FloatField(default=0)

    agility = models.IntegerField(default=1)
    agility_xp = models.FloatField(default=0)

    smithing = models.IntegerField(default=1)
    smithing_xp = models.FloatField(default=0)

    defence = models.IntegerField(default=1)
    defence_xp = models.FloatField(default=0)

    herblore = models.IntegerField(default=1)
    herblore_xp = models.FloatField(default=0)

    fishing = models.IntegerField(default=1)
    fishing_xp = models.FloatField(default=0)

    ranged = models.IntegerField(default=1)
    ranged_xp = models.FloatField(default=0)

    thieving = models.IntegerField(default=1)
    thieving_xp = models.FloatField(default=0)

    cooking = models.IntegerField(default=1)
    cooking_xp = models.FloatField(default=0)

    prayer = models.IntegerField(default=1)
    prayer_xp = models.FloatField(default=0)

    crafting = models.IntegerField(default=1)
    crafting_xp = models.FloatField(default=0)

    firemaking = models.IntegerField(default=1)
    firemaking_xp = models.FloatField(default=0)

    magic = models.IntegerField(default=1)
    magic_xp = models.FloatField(default=0)

    fletching = models.IntegerField(default=1)
    fletching_xp = models.FloatField(default=0)

    woodcutting = models.IntegerField(default=1)
    woodcutting_xp = models.FloatField(default=0)

    runecrafting = models.IntegerField(default=1)
    runecrafting_xp = models.FloatField(default=0)

    slayer = models.IntegerField(default=1)
    slayer_xp = models.FloatField(default=0)

    farming = models.IntegerField(default=1)
    farming_xp = models.FloatField(default=0)

    construction = models.IntegerField(default=1)
    construction_xp = models.FloatField(default=0)

    hunter = models.IntegerField(default=1)
    hunter_xp = models.FloatField(default=0)

    summoning = models.IntegerField(default=1)
    summoning_xp = models.FloatField(default=0)

    dungeoneering = models.IntegerField(default=1)
    dungeoneering_xp = models.FloatField(default=0)

    overall_xp = models.FloatField(default=0)
    overall = models.IntegerField(default=0)
    user_name = models.CharField(max_length=30, primary_key=True)

你可以看到有很多属性。 总共有25个技能等级和经验值。

我想按照模型类中指定的顺序在我的模板上显示它。 喜欢这个

attack_level | attack_exp
constitutionlvl | constitution_exp
mining_level | mining_exp

在表格中。

我知道我可以明确地做,但我不想这样做。


这是我到目前为止所尝试的

我尝试执行像这样的原始查询

cursor.execute("SELECT * FROM highscores_skills WHERE user_name = %s", [user_name])

这样我就可以在列表中获取数据然后在模板上循环它,但它按列名对数据进行排序。 攻击 - >构成 - >建筑 - >像那样精心制作。

如果我不使用星号并使用列名,那么我得到了我想要的东西,但还有一个问题。

这是我的模板代码

{% for skill in skills %}
    <tr>
        <td class = "col1 align">
            <a href="">{{ skill }}</a>
        </td>
        <td class = "col2">
            <a href="">{{ player|lookup:forloop.counter0 }}</a>
        </td>
        <td class = "col3 align">
            <a href="">{{ player|lookup:forloop.counter }}</a>
        </td>
    </tr>
{% endfor %}

循环运行25次。技能是一系列技能名称。 我做了一个自定义过滤器,通过索引使用循环计数器获取列表数据。 如果我设法在最后输入循环计数器的值,那么这件事就可以了。

因为这就是它现在的样子:

enter image description here

1 个答案:

答案 0 :(得分:1)

一个好的解决方案是创建两个Model字段子类,一个用于存储技能级别,另一个用于存储技能XP。这会给出类似的东西:

from django.db import models


class XpField(models.FloatField):
    '''
    Django model field used to store a skill XP.
    '''
    def __init__(self, *args, **kwargs):
        # Have a default "default" set to 0.
        if kwargs.get('default') is None:
            kwargs['default'] = 0

        super(XpField, self).__init__(*args, **kwargs)


class LevelField(models.IntegerField):
    '''
    Django model field used to store a skill level.
    Takes a required argument xp_field which is the XpField
    associated with this field's skill.
    '''
    def __init__(self, *args, **kwargs):
        # Have a default "default" set to 1.
        if kwargs.get('default') is None:
            kwargs['default'] = 1
        self.xp_field = kwargs.pop('xp_field')

        super(LevelField, self).__init__(*args, **kwargs)

正如您所看到的,LevelField存储了对XpField实例的引用,该实例应该是代表相同技能的XP的字段。

然后,您可以使用这些字段类设置Skills模型:

class Skills(models.Model):
    attack_xp = XpField()
    attack = LevelField(xp_field=attack_xp)

    # etc...

    def get_skills(self):
        '''
        Returns a list of dictionnaries containing name, level and XP
        for each of the model's skills.
        '''
        skill_values = []

        # Iterate over all the model's fields.
        for field in self._meta.get_fields():
            if isinstance(field, LevelField):
                level = getattr(self, field.name)
                xp = getattr(self, field.xp_field.name)
                skill_values.append({
                    'name': field.name,
                    'level': level,
                    'xp': xp,
                })

        return skill_values

get_skills方法将迭代Skills模型字段,检测LevelField个实例,并使用它们构建技能列表数据。 Model._meta.get_fields方法仅出现在Django 1.8中。如果您使用的是旧版本,我认为Model._meta.fields可以解决问题。

然后您可以这样在模板中使用它:

{% for skill in skills.get_skills %}
    <tr>
        <td class = "col1 align">
            <a href="">{{ skill.name }}</a>
        </td>
        <td class = "col2">
            <a href="">{{ skill.level }}</a>
        </td>
        <td class = "col3 align">
            <a href="">{{ skill.xp }}</a>
        </td>
    </tr>
{% endfor %}

P.S:我没有测试代码,因此可能包含错误,但我希望这可以让您了解如何解决问题。