如何创建不允许编辑某些字段的自定义UserChangeForm?

时间:2011-04-02 04:59:27

标签: django django-models django-admin django-forms

这是我关于SO的第二篇文章,以及我关于Django的第二篇文章 - 请保持温和。

我正在研究一个简单的用户模型。用户应该能够注册该网站,注册后他们应该能够在登录时更改其帐户设置。但是,如果我执行以下操作,用户会看到一个包含我不希望他们编辑的各种信息的巨大表单:

views.py

from django.shortcuts import render_to_response, get_object_or_404
from django.core import urlresolvers
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import UserChangeForm

@login_required 
def settings( request, template_name = 'accounts/settings.html' ):
    """
    Processes requests for the settings page, where users
    can edit their profiles.
    """
    page_title = 'Account Settings'
    if request.method == 'POST':
        postdata = request.POST.copy()
        form = UserChangeForm( postdata )
        if form.is_valid():
            form.save()
    else:
        form = UserChangeForm()
    title = 'Settings'
    return render_to_response( template_name, locals(), context_instance = RequestContext( request) )

好像这还不够糟糕,此表单不允许进行任何更改,引用“具有此用户名的用户已存在”作为错误。这让我感到困惑 - 我试图保存一个UserChangeForm,所以它不会已经存在了吗?

我一直在网上寻找一段时间,尝试制作我自己的自定义表单,基于我在SO上看到的other questions,就像这样:

forms.py

class CustomUserChangeForm( UserChangeForm ):
    def __init__( self, *args, **kwargs ):
        super( CustomUserChangeForm, self ).__init__( *args, **kwargs )
        if self.instance and self.instance.pk:
            # Since the pk is set this is not a new instance
            self.fields['username'] = self.instance.username
            self.fields['username'].widgets.attrs['readonly'] = True

不幸的是,这还没有成功。我有点不知道该做什么,所以任何帮助都会非常感激。以下是我的urls.py和模板:

urls.py

urlpatterns = patterns('appname.accounts.views',

    url(r'^settings/$', 'settings', { 
            'template_name': 'accounts/settings.html' 
        }, 'settings'
    ),
)

模板

{% extends "accounts/base.html" %}

{% block main %}
    <h1>Welcome, {{ request.user.pk }}{{ request.user.username }} to accounts.templates.accounts.settings.html.</h1>
    <h2>Here you can update your user settings. You can change your password <a href="{% url change_password %}">here</a>.</h2>
    <form action="." method="post" accept-charset="utf-8">
        {% csrf_token %}
        {{ form.as_p }}
        <p><input type="submit" value="Update &rarr;"></p>
    </form>
{% endblock %}

提前感谢您的帮助!

7 个答案:

答案 0 :(得分:8)

首先:要限制表单中的字段,请按照documentation进行操作。筛选字段基本上有两个选项:fieldsexclude

第二:你总是在创造一个新用户。使用User实例初始化表单,不仅可以保存表单,还可以使用初始数据集。

您的观看代码应为:

# in the POST:
form = UserChangeForm(request.POST, instance=request.user)

# otherwise
form = UserChangeForm(instance=request.user)

并从form.py中删除值分配。

答案 1 :(得分:4)

这需要更新:您不能排除UserChangeForm()中的字段

太糟糕了。

答案 2 :(得分:2)

三件事。首先,您应该将self.fields ['username']设置为表单字段,例如forms.CharField(ini​​tial = self.instance.username)。其次,您在视图中使用UserChangeForm而不是CustomUserChangeForm。第三,http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#using-a-subset-of-fields-on-the-form(现在是一个适当的链接,而不是某人的硬盘......

答案 3 :(得分:1)

看起来您没有仔细阅读文档。

让我帮助你,查看using-a-subset-of-fields-on-the-form

基本上您只需要将exclude = ('fieldname',)添加到您的模型元数据

答案 4 :(得分:1)

它对我有用的方法是添加一个覆盖UserChangeForm的表单类(在forms.py中):

from django.contrib.auth.forms import UserChangeForm    

class UserChangeForm(UserChangeForm):
"""Overriding visible fields."""
    class Meta:
        model = User
        fields = ('username', 'password', 'email', 'first_name', 'last_name',)

最后在views.py而不是contrib.auth.forms

上导入此版本

答案 5 :(得分:0)

我认为我在这本书上还很晚,但为了将来的读者,我还是会发表自己的观点。

class UserUpdateForm(UserChangeForm):
    password = None

    class Meta:
        model = CustomUser
        fields = ['username', 'email', 'first_name', 'last_name', 'description', ]
        widgets = {
            'description': forms.Textarea(attrs={'rows': 3}),
            'username': forms.TextInput(attrs={'readonly': 'readonly'}),
            'email': forms.TextInput(attrs={'readonly': 'readonly'})
        }

这将创建一个自定义表单,其中usernameemail字段为只读,因为您不希望用户在创建用户帐户后更改这些唯一字段。由于在个人资料页面上显示匆忙的password也没有意义,因此也会显示password字段。

答案 6 :(得分:0)

我也遇到了排除密码字段的问题,这就是我登陆这里的方式。

在检查了一些好的项目的代码后,我找到了一种排除密码字段的方法(不使用排除)

只需像下面的代码一样输入 password = None

from django.contrib.auth.forms import UserChangeForm    

class CustomUserChangeForm(UserChangeForm):

    # make the password as None for removing the password field from the form
    password = None

    class Meta:
        model = User

        # select the fields that you want to display
        fields = ('email', 'first_name', 'last_name',)