如何在allauth模板中正确加载ChoiceField与ModelChoiceField选项?
问题描述
基于allauth默认模板,我希望构建一个包含ChoiceField和ModelChoiceField的自定义注册表单,已做如下调整:
accounts/models.py
class Country(models.Model): name = models.CharField(max_length=20, unique=True) def __str__(self): return self.name class CustomUser(AbstractUser): SALUTATION = ( ('m', _('Mr')), ('f', _('Mrs')), ) salutation = models.CharField( max_length=1, choices=SALUTATION, blank=True, null=True ) country = models.ForeignKey( Country, on_delete=models.PROTECT, verbose_name=_('Country'), blank=True, null=True )
accounts/forms.py
class CustomSignupForm(forms.Form): salutation = forms.ChoiceField(widget=Select, choices=CustomUser.SALUTATION, initial=CustomUser.SALUTATION) country = forms.ModelChoiceField(queryset=Country.objects.all(), initial=Country.objects.all())
templates/allauth/elements/field.html
{% load allauth %} {% if attrs.type == "select" %} <select name="{{ attrs.name }}" id="{{ attrs.id }}" class="form-select mb-3"> {% for option in attrs.value %} <option value="{% if option.0 %}{{ option.0 }}{% else %}{{ option.id }}{% endif %}"> {% if option.1 %} {{ option.1 }} {% else %} {{ option }} {% endif %} </option> {% endfor %} </select> {% elif attrs.type == "checkbox" or attrs.type == "radio" %} ...
目前发现只有在表单中传递initial参数时,选项才会被填充到attrs.value中,但按预期应该由choices或queryset参数提供。请问是否有其他方式可以从attrs对象中获取这些值?
解决方案
allauth的模板渲染逻辑里,attrs对象不会直接携带choices或queryset数据,你可以通过以下方式解决:
从字段实例直接获取选项
模板中放弃从attrs取数据,改为通过field对象获取选项列表。修改field.html的select部分:{% load allauth %} {% if attrs.type == "select" %} <select name="{{ attrs.name }}" id="{{ attrs.id }}" class="form-select mb-3"> {% for option_value, option_label in field.field.choices %} <option value="{{ option_value }}" {% if field.value == option_value %}selected{% endif %}> {{ option_label }} </option> {% endfor %} </select> {% elif attrs.type == "checkbox" or attrs.type == "radio" %} ...- 对
ChoiceField,field.field.choices直接返回你定义的选项元组; - 对
ModelChoiceField,field.field.choices自动将模型实例转换为(instance.id, instance.__str__())的元组,无需手动处理id和显示文本。
- 对
修正表单的initial参数
你当前的initial设置存在错误:salutation的initial应设为单个值(比如'm'),而非整个选项列表;country的initial应设为单个Country实例或其id,而非所有查询集。修正后的表单代码:
class CustomSignupForm(forms.Form): salutation = forms.ChoiceField(widget=Select, choices=CustomUser.SALUTATION, initial='m') country = forms.ModelChoiceField(queryset=Country.objects.all(), initial=Country.objects.first())规范继承allauth的SignupForm
建议直接继承allauth.account.forms.SignupForm,自动关联用户模型,更符合allauth扩展规范:from allauth.account.forms import SignupForm class CustomSignupForm(SignupForm): salutation = forms.ChoiceField(widget=Select, choices=CustomUser.SALUTATION, initial='m') country = forms.ModelChoiceField(queryset=Country.objects.all(), initial=Country.objects.first()) def save(self, request): user = super().save(request) user.salutation = self.cleaned_data['salutation'] user.country = self.cleaned_data['country'] user.save() return user
内容的提问来源于stack exchange,提问作者CodeResearcher
相关产品推荐
相关产品推荐

