python - 根据 Django 中先前的模型选择限制表单字段选择

标签 python django python-3.x

我目前正在尝试使用 Django 和 WoTC 提供的 SRD Material 创建 DnD 5e 角色创建器。这是我第一次使用 Django,我是边学边学的。几天来,我遇到了一些挑战,这些挑战让我陷入困境。我研究了这个问题,在应用了我认为可能有帮助的多种技术之后,我的运气有限。我的问题是:

我有许多代表英雄、种族、子种族、类(Class)、背景等的模型。我希望能够根据用户事先选择的种族来限制用户选择子种族的能力。 到目前为止我有这个:

模型.py
class Race(models.Model):
    race_name = models.CharField(max_length=200)
    race_size = models.CharField(
        max_length=2, choices=SIZE_CHOICE, default='M')
    race_speed = models.IntegerField(
        default=30)
    race_lang = models.CharField(max_length=200, null=True, blank=True)
    race_str = models.IntegerField(default=0, null=True, blank=True)
    race_dex = models.IntegerField(default=0, null=True, blank=True)
    race_con = models.IntegerField(default=0, null=True, blank=True)
    race_int = models.IntegerField(default=0, null=True, blank=True)
    race_wis = models.IntegerField(default=0, null=True, blank=True)
    race_cha = models.IntegerField(default=0, null=True, blank=True)
    skill_spend = models.IntegerField(default=0, null=True, blank=True)
    race_extra = models.TextField(max_length=2000, blank=True, null=True)
    race_source = models.CharField(max_length=200, blank=True)

    def __str__(self):
        return self.race_name

    class Meta:
        verbose_name = 'Race'
        verbose_name_plural = 'Races'


class Subrace(models.Model):
    sub_name = models.CharField(max_length=200)
    sub_size = models.CharField(
        max_length=2, choices=SIZE_CHOICE, default='M', null=True)
    sub_speed = models.IntegerField(
        default=30, null=True)
    sub_lang = models.CharField(max_length=200, null=True, blank=True)
    sub_str = models.IntegerField(default=0, null=True, blank=True)
    sub_dex = models.IntegerField(default=0, null=True, blank=True)
    sub_con = models.IntegerField(default=0, null=True, blank=True)
    sub_int = models.IntegerField(default=0, null=True, blank=True)
    sub_wis = models.IntegerField(default=0, null=True, blank=True)
    sub_cha = models.IntegerField(default=0, null=True, blank=True)
    sub_extra = models.TextField(max_length=2000, null=True, blank=True)
    sub_parent = models.ForeignKey(Race, on_delete=models.CASCADE, null=True)

    def __str__(self):
        return self.sub_name

    class Meta:
        verbose_name = 'Subrace'
        verbose_name_plural = 'Subraces'

class Hero(models.Model):

    def roll_stats():
        d6 = die.Dice(6)
        list_stats = d6.roll(4)
        list_stats.sort()
        add = sum(list_stats[1:4])
        return add

    hero_name = models.CharField(max_length=200)
    author = models.ForeignKey(User, null=True)
    hero_subrace = models.ForeignKey(
        Subrace, on_delete=models.CASCADE, null=True, blank=True)
    pub_date = models.DateTimeField('date published', blank=True, null=True)
    hero_klass = models.ForeignKey(Klass, on_delete=models.CASCADE, null=True)
    hero_race = models.ForeignKey(Race, on_delete=models.CASCADE)
    background = models.ForeignKey(
        Background, on_delete=models.CASCADE, null=True)
    health = models.IntegerField(blank=True, null=True)
    hero_exp = models.IntegerField(default=0, null=True)
    hero_alignment = models.ForeignKey(Alignment, blank=True, null=True)
    hero_str = models.IntegerField(default=roll_stats, null=True, blank=True)
    hero_dex = models.IntegerField(default=roll_stats, null=True, blank=True)
    hero_con = models.IntegerField(default=roll_stats, null=True, blank=True)
    hero_int = models.IntegerField(default=roll_stats, null=True, blank=True)
    hero_wis = models.IntegerField(default=roll_stats, null=True, blank=True)
    hero_cha = models.IntegerField(default=roll_stats, null=True, blank=True)

    def save(self, *args, **kwargs):
        "Returns a hero's hp"
        die_str = str(self.hero_klass.hit_dice)
        die_nums = die_str.split("d")
        die_val = int(die_nums[1])
        die_roll = int(die_nums[0])
        hp_die = die.Dice(die_val)
        results = hp_die.roll(die_roll)
        self.health = sum(results)
        super(Hero, self).save(*args, **kwargs)

    def __str__(self):
        return self.hero_name

    def get_absolute_url(self):
        return reverse('hero.views.detail', args=[str(self.id)])

    class Meta:
        verbose_name = 'Hero'
        verbose_name_plural = 'Heroes'

View .py
def new_hero(request):
    user = request.user
    if request.method == "POST":
        form = HeroForm(request.POST)
        if form.is_valid():
            hero = form.save(commit=False)
            hero.author = request.user
            hero.save()
            return redirect('detail', hero.pk)
    else:
        form = HeroForm()
    return render(request, 'new_hero.html', {'form': form, 'user': user})

表单.py
class HeroForm(forms.ModelForm):

    class Meta:
        model = Hero
        fields = ['hero_name', 'hero_race', 'hero_subrace',
                  'hero_klass', 'hero_exp', 'health', 'background',
                  'hero_str', 'hero_dex', 'hero_con', 'hero_int',
                  'hero_wis', 'hero_cha', 'hero_alignment']

    def __init__(self, *args, **kwargs):
        super(HeroForm, self).__init__(*args, **kwargs)
        for fieldname in ['hero_str', 'hero_dex', 'hero_con', 'hero_int', 'hero_wis', 'hero_cha']:
            self.fields[fieldname].disabled = True
        race = Race.objects.all()
        for name in race:
            self.fields['hero_subrace'].queryset = Subrace.objects.filter(sub_parent=name)

我尝试了几种不同的技术,但这就是我现在的处境。这个:

for name in race:
            self.fields['hero_subrace'].queryset = Subrace.objects.filter(sub_parent=name)

是我最近添加到我的应用程序中的内容。在英雄创建屏幕上,我看到了一个空白的选择框,而不是没有循环或查询集的完整无限制列表。

基本上,我希望有人对我可能忽略的方法、我错过的或根本没有找到的方法提出一些建议。也请随意批评其余代码,就像我说这是我的第一个 Django 应用程序 :)。这也是我的第一个 Stack Overflow 问题,非常感谢 :)

最佳答案

对于任何想知道的人,我使用了 django-smart-selects解决我的问题。

base.html

<script type="text/javascript" src="{% static 'smart-selects/admin/js/chainedfk.js' %}"></script>
<script type="text/javascript" src="{% static 'smart-selects/admin/js/bindfields.js' %}"></script>

我将上面的 html 添加到我的 {% load staticfiles %} 调用中。

并更改了 models.py:

模型.py
from smart_selects.db_fields import ChainedForeignKey
class Hero(models.Model):
    ....
    race = models.ForeignKey(Race, on_delete=models.CASCADE)
    subrace = ChainedForeignKey(Subrace,
                                chained_field="race",
                                chained_model_field="race",
                                show_all=False,
                                auto_choose=True,
                                blank=True,
                                null=True)

现在我有一个 subrace 字段,它会在用户选择比赛时动态更新。

关于python - 根据 Django 中先前的模型选择限制表单字段选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46230686/

相关文章:

python - while-true 循环内的输入提示

python - 使用通用 View (CreateView) 限制 Django 中外键下拉列表中的选择

python - Django React Nginx 服务管理静态文件

python - 交替的 SQL 查询

python - 导入 sutime 模块时出现以下导入错误 - 这是什么意思?

python - 从 Weedmaps 中抓取菜单数据

python - 如何在不同形状的 ndarray 列表上使用 numpy.amax() ?

python - 从 python 整数列表中删除最大值和最小值

python - 直接在Models中存储django forms.MultipleChoiceField

python-3.x - 计算网页内的单词