在django中扩展表单? [英] Extending forms in django?

查看:114
本文介绍了在django中扩展表单?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近尝试扩展django的注册表单与以下,但我只能看到默认的四个字段。有没有什么我失踪?



或者我应该创建自己的注册后端,如果我要创建一个自定义表单?

  class RegistrationForm(forms.Form):

username = forms.RegexField(regex = r'^ \w + $',
max_length = 30,
widget = forms.TextInput(attrs = attrs_dict),
label = _(u'Username'))
email = forms.EmailField(widget = forms.TextInput (attrs = dict(attrs_dict,
maxlength = 75)),
label = _(u'Email address'))
first_name = forms.CharField(widget = forms.TextInput(attrs = attrs_dict),label = _(u'First Name))
last_name = forms.CharField(widget = forms.TextInput(attrs = attrs_dict),label = _(u'Last Name))
password1 = forms.CharField(widget = forms.PasswordInput(attrs = attrs_dict,render_value = Fa lse),
label = _(u'Password'))
password2 = forms.CharField(widget = forms.PasswordInput(attrs = attrs_dict,render_value = False),
label = _ u'Password(again)'))
keywords = forms.ModelMultipleChoiceField(queryset = Keyword.objects.all())
#keywords = forms.ModelChoiceField(queryset = Keyword.objects.all())

def clean_username(self):
try:
user = User.objects.get(username__iexact = self.cleaned_data ['username'])
except User。 DoesNotExist:
return self.cleaned_data ['username']
raise forms.ValidationError(_(u'This username is already taken。请选择另一个。'))

def clean(self):
如果self.cleaned_data中的password1和self.cleaned_data中的password2:
如果self.cleaned_data ['password1']!= self.cleaned_data ['password2']:
raise forms.ValidationError(_(你必须每次输入相同的密码))
return self.cleaned_data

def save(self,profile_callback = None):
new_user = RegistrationProfile.objects.create_inactive_user(username = self.cleaned_data ['username'],password = self.cleaned_data ['password1'], email = self.cleaned_data ['email'],profile_callback = profile_callback)
new_profile = UserProfile(user = new_user,username = self.cleaned_data ['username'],keywords_subscribed = self.cleaned_data ['keywords'],first_name = self.cleaned_data ['first_name'],last_name = self.cleaned_data ['last_name'],email = self.cleaned_data ['email'])
new_profile.save()
返回new_user

添加了模板代码:



添加模板代码以供参考。



从注册模块中的forms.py引用

 < html> 
< body>
< div id =popupLayer_loginstyle =visibility:visible; position:fixed;>
< div id =content-homestyle =width:700px; margin-left:-300px; top:60px; position:fixed;>
< br />
{%block title%}< h2 style =margin:0px; margin-bottom:20px; text-align:center>注册一个帐户< / h2> {%endblock%}
{%block content%}
< table style =margin-left:100px; width:500px;>
< tbody>
< form method ='post'action =''>
{%csrf_token%}
{{form}}
< tr>
< td style =border-width:0px;>< / td>
< td style =border-width:0px;>
< input type =submitvalue =发送激活邮件/>
< / td>
< / tr>
< / form>
< / tbody>
< / table>
{%endblock%}
< / div>
< / div>
< / body>
< / html>

这是我的urls.py

  urlpatterns = patterns('',
#激活密钥由\w +匹配,而不是更具体的
#[a-fA -F0-9] {40},因为一个坏的激活密钥仍然应该得到视图;
#,这样它可以返回一个明智的无效的密钥消息,而不是一个
#confused 404.
url(r'^ activate /(?P< activation_key> \w +)/ $',
activate,
name ='registration_activate'),
url(r'^ login / $',
auth_views.login,
{'template_name':'registration / login.html'},
name ='auth_login'),
url(r'注销/ $',
auth_ views.logout,
{'template_name':'registration / logout.html'},
name ='auth_logout'),
url(r'^ password / change / $',
auth_views.password_change,
name ='auth_password_change'),
url(r'^ password / change / done / $',
auth_views.password_change_done,
name = 'auth_password_change_done'),
url(r'^ password / reset / $',
auth_views.password_reset,
name ='auth_password_reset'),
url(r'^ password /reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.password_reset_confirm,
name = 'auth_password_reset_confirm'),
url(r'^ password / reset / complete / $',
auth_views.password_reset_complete,
name ='auth_password_reset_complete'),
url(r'^ password / reset / done / $' ,
auth_views.password_reset_done,
name ='auth_password_reset_done'),
url(r'^ register / $',
register,
name ='registration_register') ,
url(r'^ register / complete / $',
direct_to_template,
{'template':'registration / registration_complete.html'},
name ='registration_complete' ),

和我的views.py p>

  def register(request,success_url = None,
form_class = RegistrationForm,profile_callback = None,
template_name ='registration / registration_form.html',
extra_context = None):
如果request.method =='POST':
form = form_class(data = request.POST,files = request.FILES)
如果form.is_valid():
new_user = form.save(profile_callback = profile_callback)
#success_url需要动态在这里生成使用reverse()设置
#的默认值将导致循环导入
#与此应用程序的默认URLConf的问题,
#导入此文件。
return HttpResponseRedirect(success_url or reverse('registration_complete'))
else:
form = form_class()

如果extra_context为None:
extra_context = {}
context = RequestContext(request)
为key,value为extra_context.items():
context [key] = callable(value)和value()或value
返回render_to_response(template_name,
{'form':form},
context_instance = context)


解决方案

实际上,你不应该修改外部应用程序的代码,除非你有一个很好的理由 - 显然这种情况下T。因为这被称为叉子,需要更多的维护:他们进行更新,您必须反映更新。



您应该总是尝试重用外部应用程序,而不触及其代码。在这种情况下,完全可以扩展注册表单而不触摸他们的代码。也就是说,它需要一点点巫术。请注意,这适用于任何理智的应用程序:


  1. 检查视图签名中的form_class参数 ,所涉及的视图具有以下签名: request(request,success_url = None,form_class = RegistrationForm,profile_callback = None,template_name ='registration / registration_form.html',extra_context = None)。这很酷,这意味着您可以使用不同的成功URL,配置文件回调,模板,额外的上下文,最重要的是在您的情况下重用该视图:form_class。


  2. 子表单,创建从RegistrationForm继承的另一个表单


  3. 覆盖URL以传递您的表单类,创建另一个通过您的表单类的URL


在项目目录中创建一个forms.py: p>

 $ d code从django导入表单

from registration.forms import RegistrationForm

class ProjectSpecificRegistrationForm (RegistrationForm):
keywords = forms.ModelMultipleChoiceField(queryset = Keyword.objects.all())
first_name = forms.CharField(widget = forms.TextInput(attrs = attrs_dict),label = _ 'first name'))
last_name = forms.CharField(widget = forms.TextInput(attrs = attrs_dict),label = _(u'Last Name))
/ pre>

然后,在您的 urls.py中,您应该具有以下内容:

  urlpatterns = patterns('',
url(r'registration /',include('registration.urls'),

使用绝对路径 / registration / register / url覆盖名为registration_register的网址:

 导入表单

urlpatterns = patterns('',
url(r'^ registration / register / $ ','views.registration.register',{
'form_class':forms.ProjectSpecificRegistrationForm},'registration_register'),
url(r'^ registration /',include('registration.urls' ,

这里发生了什么



url()函数有这样的签名: url(regex,view,kwargs = None,name = None,prefix ='')。在上面的定义中,我们将一个使用form_class的dict传递给kwargs。所以这个视图将被调用form_class =你的表单类。这真的很有趣,因为你也可以添加额外的上下文,如:

  url(r'^ registration / register / $'如果您导入SomeModel 
'extra_context':{'models':SomeModel.objects.all(),则可以使用$ {
'form_class':forms.ProjectSpecificRegistrationForm }},'registration_register'),

下一次打开 / registration / register / ,它将使用您的URL,通过您的表单类。



请注意,您也可以创建一个像 project_specific 这样的应用程序,您可以将所有的代码放在项目中,并且没有任何理由重新使用。


I recently tried extending django's registration form with the following but i can only see the default four fields. IS there anything i'm missing?

Or should i be creating my own registration backend if i were to create a custom form?

class RegistrationForm(forms.Form):

    username = forms.RegexField(regex=r'^\w+$',
                                max_length=30,
                                widget=forms.TextInput(attrs=attrs_dict),
                                label=_(u'Username'))
    email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
                                                               maxlength=75)),
                             label=_(u'Email address'))
    first_name =forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'First Name')) 
    last_name =forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'Last Name'))
    password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
                                label=_(u'Password'))
    password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
                                label=_(u'Password (again)'))
    keywords = forms.ModelMultipleChoiceField(queryset=Keyword.objects.all())
    #keywords = forms.ModelChoiceField(queryset=Keyword.objects.all())

    def clean_username(self):
        try:
            user = User.objects.get(username__iexact=self.cleaned_data['username'])
        except User.DoesNotExist:
            return self.cleaned_data['username']
        raise forms.ValidationError(_(u'This username is already taken. Please choose another.'))

    def clean(self):
        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
            if self.cleaned_data['password1'] != self.cleaned_data['password2']:
                raise forms.ValidationError(_(u'You must type the same password each time'))
        return self.cleaned_data

    def save(self, profile_callback=None):
        new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],password=self.cleaned_data['password1'],email=self.cleaned_data['email'],profile_callback=profile_callback)
    new_profile = UserProfile(user=new_user,username=self.cleaned_data['username'], keywords_subscribed=self.cleaned_data['keywords'],first_name=self.cleaned_data['first_name'],last_name=self.cleaned_data['last_name'],email=self.cleaned_data['email'])
    new_profile.save()       
        return new_user

Added the template code:

The template code is added for reference.

It's referencing from the forms.py in the registration module

<html>
    <body>
        <div id="popupLayer_login" style="visibility: visible; position: fixed;">
            <div id="content-home" style="width: 700px; margin-left: -300px; top: 60px; position: fixed;">
                <br />
                {% block title %}<h2 style="margin: 0px; margin-bottom: 20px; text-align: center">Register for an account</h2>{% endblock %}
                {% block content %}
                <table style="margin-left: 100px; width: 500px;">
                    <tbody>
                        <form method='post' action=''>
                            {% csrf_token %}
                            {{ form }}
                            <tr>
                                <td style="border-width: 0px;"></td>
                                <td style="border-width: 0px;">
                                <input type="submit" value="Send activation email" />
                                </td>
                            </tr>
                        </form>
                    </tbody>
                </table>
                {% endblock %}
            </div>
        </div>
    </body>
</html>

This is my urls.py

urlpatterns = patterns('',
                       # Activation keys get matched by \w+ instead of the more specific
                       # [a-fA-F0-9]{40} because a bad activation key should still get to the view;
                       # that way it can return a sensible "invalid key" message instead of a
                       # confusing 404.
                       url(r'^activate/(?P<activation_key>\w+)/$',
                           activate,
                           name='registration_activate'),
                       url(r'^login/$',
                           auth_views.login,
                           {'template_name': 'registration/login.html'},
                           name='auth_login'),
                       url(r'^logout/$',
                           auth_views.logout,
                           {'template_name': 'registration/logout.html'},
                           name='auth_logout'),
                       url(r'^password/change/$',
                           auth_views.password_change,
                           name='auth_password_change'),
                       url(r'^password/change/done/$',
                           auth_views.password_change_done,
                           name='auth_password_change_done'),
                       url(r'^password/reset/$',
                           auth_views.password_reset,
                           name='auth_password_reset'),
                       url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
                           auth_views.password_reset_confirm,
                           name='auth_password_reset_confirm'),
                       url(r'^password/reset/complete/$',
                           auth_views.password_reset_complete,
                           name='auth_password_reset_complete'),
                       url(r'^password/reset/done/$',
                           auth_views.password_reset_done,
                           name='auth_password_reset_done'),
                       url(r'^register/$',
                           register,
                           name='registration_register'),
                       url(r'^register/complete/$',
                           direct_to_template,
                           {'template': 'registration/registration_complete.html'},
                           name='registration_complete'),
                       )

and my views.py

def register(request, success_url=None,
             form_class=RegistrationForm, profile_callback=None,
             template_name='registration/registration_form.html',
             extra_context=None):
    if request.method == 'POST':
        form = form_class(data=request.POST, files=request.FILES)
        if form.is_valid():
            new_user = form.save(profile_callback=profile_callback)
            # success_url needs to be dynamically generated here; setting a
            # a default value using reverse() will cause circular-import
            # problems with the default URLConf for this application, which
            # imports this file.
            return HttpResponseRedirect(success_url or reverse('registration_complete'))
    else:
        form = form_class()

    if extra_context is None:
        extra_context = {}
    context = RequestContext(request)
    for key, value in extra_context.items():
        context[key] = callable(value) and value() or value
    return render_to_response(template_name,
                              { 'form': form },
                              context_instance=context)

解决方案

Actually, you are not supposed to modify the code of an external app, unless you have a really good reason to - which apparently this case doesn't. Because that's called a fork and requires more maintenance: they do an update, you'd have to reflect the updates.

You should always try to reuse the external app without touching its code. In this case, it is perfectly possible to extend the registration form without touching their code. That said, it requires a little voodoo. Note that this works for any sane app:

  1. Check for a form_class argument in the view signature, the view in question has such a signature: request(request, success_url=None, form_class=RegistrationForm, profile_callback=None, template_name='registration/registration_form.html', extra_context=None). That's pretty cool, it means that you can reuse the view with different success urls, profile callbacks, templates, extra context and most importantly in your case: form_class.

  2. Subclass the form, create another form which inherits from RegistrationForm

  3. Override the URL to pass your form class, create another url which passes your form class

Create a forms.py in your project directory:

from django import forms

from registration.forms import RegistrationForm

class ProjectSpecificRegistrationForm(RegistrationForm):
    keywords = forms.ModelMultipleChoiceField(queryset=Keyword.objects.all())
    first_name =forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'First Name')) 
    last_name =forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'Last Name'))

Then, in your urls.py, you should have something like:

urlpatterns = patterns('',
    url(r'registration/', include('registration.urls'),
)

Override the url named "registration_register" with absolute path /registration/register/ url as such:

import forms

urlpatterns = patterns('',
    url(r'^registration/register/$', 'views.registration.register', {
        'form_class': forms.ProjectSpecificRegistrationForm}, 'registration_register'),
    url(r'^registration/', include('registration.urls'),
)

What's going on here

The url() function has such a signature: url(regex, view, kwargs=None, name=None, prefix=''). In the above definition, we are passing a dict with form_class to kwargs. So the view will be called with form_class=your form class. It's quite interesting really because you could also add extra context like:

    url(r'^registration/register/$', 'views.registration.register', {
        'form_class': forms.ProjectSpecificRegistrationForm,
        # provided that you imported SomeModel
        'extra_context':  {'models': SomeModel.objects.all()}}, 'registration_register'),

Anyway next time you open /registration/register/, it will use your url, which passes your form class.

Note that you could also create a an app like project_specific where you'd put all the code that is really specific to your project and has no reason to be reused.

这篇关于在django中扩展表单?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆