【问题标题】:Extend CreatesUserForm and keep l10n / i18n built-in feature扩展 CreatesUserForm 并保留 l10n / i18n 内置功能
【发布时间】:2018-09-25 09:54:37
【问题描述】:

我正在发现 Django (v2.1.1) 并想设置一个 登录页面,其中我有 2 个电子邮件字段,如果 2 个字段相同,我拨打form.is_valid()

项目树

├── manage.py
├── requirements.txt
├── project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── views.py
│   ├── wsgi.py
│   └── templates
│       ├── base.html
│       ├── project
│       │   └── home.html
│       └── registration
│           ├── logged_out.html
│           ├── login.html
│           └── signin.html
└── app
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── urls.py
    ├── views.py
    ├── migrations
    └── templates
        └── app
            └── home.html

project/settings.py 中的国际化配置:

# (…)
# Internationalization
LANGUAGE_CODE = 'fr-fr'
USE_I18N = True
USE_L10N = True
# (…)

使用 基本的 django 登录视图 效果很好

project/views.py

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm

def index(request):
    return render(request, 'project/home.html', {'context':'project index'})

def signin(request):
    # (…)
    form = UserCreationForm()
    return render(request, 'registration/signin.html', {'form': form})

我有一个很好的法语翻译 HTML 表单(submit button 除外):


让我们在表单中添加一个email 字段,email 是一个内置的用户字段(如first_namelast_name)所以我只需添加一个新类SignInForm 继承自UserCreationForm

project/forms.py

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class SignInForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('username', 'email', 'password1', 'password2')

我更新project/views.py

# (…)
from project.forms import SignInForm
# (…)
def signin(request):
    # (…)
    form = SignInForm()
    return render(request, 'registration/signin.html', {'form': form})

有效:添加了一个不错的法语翻译字段,但它没有help_text 属性:


现在我被困住了……

如果我想将属性'required': True 设置为email 字段(它是必需的,我想显示翻译后的help_text)。我发现的唯一方法是覆盖内置的电子邮件字段,但我松散了翻译,它没有显示help_text

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms

class SignInForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ('username', 'email', 'password1', 'password2')

如果我添加第二个email2 字段,我希望使用email2 = User.email 之类的内容复制原始User.email,但看起来这不是存储电子邮件的好地方。我可以像上面一样使用forms.EmailField(),但我真的很想利用内置翻译。


那么这是我的问题

如何将email 字段与内置属性(名称、必需、help_text、...)一起使用并获得翻译? (当我有答案时,我假设我会找到对submitfirst_namelast_name 执行相同操作的方法)

我可以使用此限制复制电子邮件字段吗? (我不想存储第二个字段,只是在调用form.is_valid() 之前检查)

_

【问题讨论】:

    标签: python django forms localization internationalization


    【解决方案1】:

    这里有一些事情在起作用。

    UserCreationForm 是一个ModelForm,它从模型派生其字段。在这种情况下,模型是您当前的AUTH_USER_MODEL 设置。当创建email 表单字段时,它会检查模型中相应的email 字段,它会在其中找到help_text,它包含在gettext(或gettext_lazy)调用中以允许i18n工作,以及任何其他属性。

    如果我正确理解您的问题,您希望复制 email 表单字段以覆盖某些(如果有)属性并允许您根据原始属性对其进行验证。虽然 Django 使用metaclasses 来生成表单类,所以它比您尝试的要难一些,但自 1.8 版以来就有一个公共 API 可以做到这一点:get_field

    以下是您可以执行的操作的示例:

    class SignInForm(UserCreationForm):    
        def __init__(self, *args, **kwargs):
            super(SignInForm, self).__init__(*args, **kwargs)
            email_field = settings.AUTH_USER_MODEL._meta.get_field('email')
            self.fields['email2'] = email_field.formfield()
            self.fields['email'].required = True
            self.fields['email2'].required = True
    
        class Meta:
            model = settings.AUTH_USER_MODEL
            fields = (...)
    

    几点说明:

    • 如果您切换到自定义用户模型,使用 settings.AUTH_USER_MODEL 而不是仅使用 User 可以避免在整个代码库中更改对 User 的引用。
    • get_field 也有一个复数形式(参见文档)来同时检索多个字段。
    • 一般来说,表单的任何运行时修改(覆盖字段属性等)都发生在 __init__ 方法中,因为这是在 Django 使用元类执行黑魔法之后您第一次获得“真实”表单的地方,请参阅 @ 987654340@ 属性覆盖。
    • 如果你想覆盖一个可翻译的文本,你必须通过gettext 并了解这个机制,如果你想正确地做到这一点。您当然可以用法语对其进行硬编码。 ;)
    • 编辑:表单验证发生在validatevalidate_{field} 表单方法中,由is_valid 触发。您不必在视图中包含此逻辑。

    希望对你有帮助。

    【讨论】:

    • 里面有很多东西,谢谢。我会尽快尝试并提供反馈。
    猜你喜欢
    • 2011-06-04
    • 2022-01-10
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多