Django:使用CreateView时在模板Select中仅显示对象指定属性(不改__str__)
自定义Django表单下拉框显示内容(不修改模型__str__方法)
问题场景
现有以下Django模型、视图及模板代码:
模型代码
class Usuario(models.Model): login = models.CharField(max_length=200) senha = models.CharField(max_length=200) meta = models.ManyToManyField('meta', through='Usuario_meta') def __str__(self): return f'id: {self.id} - login: {self.login} - senha: {self.senha}' class Meta(models.Model): tipo = models.CharField(max_length=200) def __str__(self): return f'id: {self.id} - senha: {self.tipo}' class Usuario_meta(models.Model): usuario = models.ForeignKey(Usuario,on_delete=models.CASCADE) meta = models.ForeignKey(Meta,on_delete=models.CASCADE) data = models.DateField() valor = models.IntegerField() def __str__(self): return f'Meta do usuário: {self.usuario} - meta:{self.meta} - data:{self.data} - valor: {self.valor}'
视图代码
class UsuarioMetaCreate(CreateView): model = Usuario_meta template_name = 'lancamento_meta_cadastro.html' fields = '__all__'
原模板代码
<form action="" method="post"> {% csrf_token %} {{form}} <input type="submit" value="Submit" /> </form>
默认渲染后,usuario下拉框会调用Usuario模型的__str__方法显示完整字符串,但需求是仅显示login属性,且不能修改模型的__str__方法。尝试直接在模板中使用{{form.usuario.login}}无效果,需要可行方案。
解决方案
方法一:自定义表单类,重写label_from_instance
通过自定义ModelForm,为usuario字段指定ModelChoiceField并修改选项的显示逻辑,无需修改模型代码。
- 创建自定义表单(可在
forms.py或views.py中定义):
from django import forms from .models import Usuario_meta, Usuario class UsuarioMetaForm(forms.ModelForm): usuario = forms.ModelChoiceField( queryset=Usuario.objects.all(), label='Usuário', # 重写选项显示逻辑,仅返回login字段 label_from_instance=lambda obj: obj.login ) class Meta: model = Usuario_meta fields = '__all__'
- 修改视图,指定使用自定义表单:
class UsuarioMetaCreate(CreateView): model = Usuario_meta template_name = 'lancamento_meta_cadastro.html' form_class = UsuarioMetaForm # 替换为自定义表单类
- 模板仍使用原代码即可:
<form action="" method="post"> {% csrf_token %} {{form}} <input type="submit" value="Submit" /> </form>
这种方式简洁高效,适合需要全局复用该表单的场景。
方法二:模板中手动渲染下拉框
若不想修改后端代码,可直接在模板中手动生成select元素,自定义选项显示内容。
修改后的模板代码:
<form action="" method="post"> {% csrf_token %} <!-- 手动渲染usuario下拉框 --> <div> <label for="{{ form.usuario.id_for_label }}">Usuário:</label> <select id="{{ form.usuario.id_for_label }}" name="{{ form.usuario.name }}"> {% for usuario in form.usuario.field.queryset %} <option value="{{ usuario.id }}" {% if usuario.id == form.usuario.value %}selected{% endif %}> {{ usuario.login }} </option> {% endfor %} </select> <!-- 显示字段错误信息 --> {% if form.usuario.errors %} <div style="color: red;">{{ form.usuario.errors }}</div> {% endif %} </div> <!-- 渲染其余字段 --> <div>{{ form.meta.label_tag }} {{ form.meta }}</div> <div>{{ form.data.label_tag }} {{ form.data }}</div> <div>{{ form.valor.label_tag }} {{ form.valor }}</div> <input type="submit" value="Submit" /> </form>
这种方式灵活性高,仅需修改模板代码,适合单个页面的定制需求。
内容的提问来源于stack exchange,提问作者Matheus
相关产品推荐
相关产品推荐

