如何在Django表单下拉框中显示Deck模型的is_cedh字段信息
问题描述
我正在给Django表单的下拉框添加额外信息,程序逻辑如下:
- 用户登录
- 用户可创建将在game_tracking页面展示的「卡组(decks)」
- 用户进入game_tracking页面后,第一个下拉框需要加载用户创建的所有卡组名称,同时显示Deck模型中的附加信息——该卡组是否为cEDH卡组。
目前我不确定如何在下拉框中除名称外,同时展示is_cedh的状态。当前下拉框仅显示卡组名称,理想效果是在cEDH卡组的名称旁标注「(cEDH)」。
以下是相关代码:
models.py文件
from django.db import models from django.contrib.auth.models import User class Profile(models.Model): profile_pic = models.ImageField(null=True, blank=True, default='Default.png', upload_to='images/') user = models.ForeignKey(User, max_length=10, on_delete=models.CASCADE, null=True) def __str__(self): return str(self.user) class Deck(models.Model): deck = models.CharField(max_length=150) is_cedh = models.BooleanField(default=False) user = models.ForeignKey(User, max_length=10, on_delete=models.CASCADE, null=True) def __str__(self): return str(self.deck) class Game(models.Model): NUM_PLAYERS_CHOICE = [ (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ] OUTCOME_CHOICE = [ ('Win', 'Win'), ('Loss', 'Loss'), ('Draw', 'Draw'), ('Incomplete', 'Incomplete'), ] # ForeignKeys deck = models.ForeignKey(Deck, on_delete=models.CASCADE, null=True) wincon = models.ForeignKey(Wincon, on_delete=models.CASCADE, null=True, blank=True) num_players = models.IntegerField(choices=NUM_PLAYERS_CHOICE, default=4) outcome = models.CharField(max_length=10, choices=OUTCOME_CHOICE, default='Win')
forms.py文件
class GameForm(forms.ModelForm): def __init__(self, user, *args, **kwargs): super(GameForm, self).__init__(*args, **kwargs) self.fields['deck'].queryset = Deck.objects.filter(user=user) class Meta: model = Game exclude = {'date', 'time', } labels = { 'deck': 'What deck', 'num_players': '# of Players', 'outcome': 'Outcome', },
views.py文件
@login_required(login_url='my-login') def game_tracker(request): user_decks = Deck.objects.filter(user=request.user) if request.method == "POST": form = GameForm(request.user, request.POST) if form.is_valid(): form.save() return HttpResponseRedirect('/') else: form = GameForm(request.user) context = {'form': form, } return render(request, 'gametracker_app/gametracker.html', context=context)
HTML文件
{% block content %} <form action="" method="POST"> {% csrf_token %} <div class="container-sm p-4"> <div class="card" style=""> <div class="card-body"> {{ form.deck|as_crispy_field }} <br> <a href="{% url 'my-decks' %}" class=""> <p class="">Add new deck?</p> </a> <div class="flex-container"> <div class="row"> <div class="col-sm"> {{ form.num_players|as_crispy_field }} </div> <div class="col-sm"> {{ form.outcome|as_crispy_field }} </div> </div> </div> <button type='submit' class="btn btn-secondary">Submit </button> </div> </div> </div> </form> {% endblock %}
解决方案
方法1:修改Deck模型的__str__方法
这是最简单的全局生效方案,直接在模型的字符串表示中加入cEDH标记:
class Deck(models.Model): deck = models.CharField(max_length=150) is_cedh = models.BooleanField(default=False) user = models.ForeignKey(User, max_length=10, on_delete=models.CASCADE, null=True) def __str__(self): # 针对cEDH卡组添加标记 if self.is_cedh: return f"{self.deck} (cEDH)" return self.deck
修改后,所有展示Deck实例的场景(包括表单下拉框)都会自动显示带标记的名称,无需修改其他代码。
方法2:在表单中自定义下拉选项
如果不想修改模型的全局字符串表示(比如其他场景需要纯卡组名称),可以在GameForm中手动构造下拉选项:
class GameForm(forms.ModelForm): def __init__(self, user, *args, **kwargs): super(GameForm, self).__init__(*args, **kwargs) # 获取用户卡组并构造自定义显示文本 user_decks = Deck.objects.filter(user=user) self.fields['deck'].choices = [ (deck.id, f"{deck.deck} (cEDH)" if deck.is_cedh else deck.deck) for deck in user_decks ] class Meta: model = Game exclude = {'date', 'time', } labels = { 'deck': '使用的卡组', 'num_players': '玩家数量', 'outcome': '对局结果', }
这种方式仅在当前表单中生效,不影响其他地方的Deck显示逻辑,选项的值仍为卡组ID,不影响表单提交后的保存。
注意事项
- 由于你使用了
django-crispy-forms(模板中的|as_crispy_field),两种方案都能正常渲染出带标记的下拉选项。
内容的提问来源于stack exchange,提问作者bld-sync
相关产品推荐
相关产品推荐

