Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a custom UserChangeForm that does not allow certain fields to be edited?

This is my second post on SO, as well as my second post on Django--please be gentle.

I am working on a simple User model. Users should be able to sign up for the site, and after signing up they should be able to change their account settings upon login. However, if I do the following, Users see a huge form with all kinds of info I don't want them to edit:

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) )

As if that wasn't bad enough, this form doesn't allow any changes to be made, citing "User with this Username already exists" as an error. This confuses me--I am attempting to save a UserChangeForm, so wouldn't it already existing be a given?

I've been looking online for a while now, attempting making my own custom forms, based on other questions I've seen on SO, like so:

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

Unfortunately this hasn't worked out. I'm kind of at a loss as to what to do, so any help would be greatly appreciated. Below are my urls.py and template:

urls.py

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

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

template

{% 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 %}

Thanks in advance for any help!

like image 405
modocache Avatar asked Apr 02 '11 04:04

modocache


2 Answers

First: to limit which fields are in the form, follow the documentation. There are basically two options to filter fields: fields and exclude.

Second: you are always creating a new user. Initialize form with the User instance, not only you will be able to save a form, but you will have an initial data set.

Your view code should read:

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

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

and remove value assignment from the form.py.

like image 147
Jerzyk Avatar answered Sep 19 '22 15:09

Jerzyk


This needs to be updated: You cannot exclude fields in UserChangeForm()

Too bad.

like image 41
Rob L Avatar answered Sep 21 '22 15:09

Rob L