You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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数据,你可以通过以下方式解决:

  1. 从字段实例直接获取选项
    模板中放弃从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和显示文本。
  2. 修正表单的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())
    
  3. 规范继承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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:04:58