Home > coding, django > django newforms tricks

django newforms tricks

Image you have some sort of user-profile, and you want to automatically render it using newforms. But leave certain fields out.
(i.e. the user may not be able to change the associated user)


so this is the example model:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
  user = models.ForeignKey(User, unique=True)

  _activated = models.BooleanField()

  _activation_key = models.CharField(maxlength=40)
  _key_expires = models.DateTimeField()

  # custom fields
  text = models.CharField(maxlength=100, blank=True)

  aboutme = models.TextField("About me",blank=True)
  ml = models.BooleanField("MailingList")

  class Admin:
    pass

As you should have noticed, i introduced a naming convention. (All members beginning with an underscore should not displayed to the user). The next step is to write the corresponding view:

def form_callback(f, **args):
  if f.name[0] == "_" or f.name == "user":
    return None
  return f.formfield(**args)

def edit_profile(request):
  if not request.user.is_authenticated():
    return HttpResponseRedirect("/accounts/login/")
  try:
    profile = request.user.get_profile()
  except UserProfile.DoesNotExist:
    # create new Profile for that user
    profile = createNewUserProfile(request.user, True)

  ProfileForm = newforms.models.form_for_instance(profile, formfield_callback=form_callback)

  if request.method == 'POST':
    form = ProfileForm(request.POST)

    if form.is_valid():
      for key in form.clean_data:
        profile.__setattr__(key, form.clean_data[key])
      profile.save()
      request.user.message_set.create(message='data saved')
  else:
    form = ProfileForm()
  return render_to_response('registration/profile.html', {
        'form': form,
        'username' : request.user.username
        }, context_instance=RequestContext(request))

The main part of the field filtering happens in the callback method form_callback and in the correct call in line 15.
You may not use form.save, as some fields are missing. So just go trough every single field and save it.

Categories: coding, django Tags:
  1. TaMeR
    April 1st, 2007 at 18:57 | #1

    Hi Thomas
    I am trying to get this to work and I am a novice.

    What does your 'createNewUserProfile' look like?

    Also what does the view pages look like

  2. April 2nd, 2007 at 00:04 | #2

    hi,
    the views.py:

    # python
    import datetime, random, sha

    # output
    from django.template import Template, Context, loader, RequestContext
    from django.http import HttpResponse, HttpResponseRedirect
    from django import forms, newforms

    # auth
    from django.contrib.auth import authenticate
    from django.contrib.auth.models import User
    from django.contrib.auth.forms import UserCreationForm, AuthenticationForm

    # mail
    from django.core.mail import send_mail

    # shortcuts
    from django.shortcuts import render_to_response, get_object_or_404

    # forms
    from repo.accounts.forms import *

    # models
    from repo.accounts.models import *

    def account_overview(request):
    account_base_url = "/accounts"
    return render_to_response('registration/account_overview.html',{
    'has_account': request.user.is_authenticated(),
    'account_base_url' : account_base_url,
    'username' : request.user.username,
    })

    def confirm(request, activation_key):
    if request.user.is_authenticated():
    return render_to_response('registration/confirm.html', {'has_account': True})
    user_profile = get_object_or_404(UserProfile,
    activation_key=activation_key)
    if user_profile.key_expires < datetime.datetime.today():
    return render_to_response('registration/confirm.html', {'expired': True})
    user_account = user_profile.user
    user_account.is_active = True
    user_account.save()
    return render_to_response('registration/confirm.html', {'success': True})

    def createNewUserProfile(new_user, activated=False):
    # Build the activation key for their account
    salt = sha.new(str(random.random())).hexdigest()[:5]
    activation_key = sha.new(salt+new_user.username).hexdigest()
    key_expires = datetime.datetime.today() + datetime.timedelta(2)

    # Create and save their profile
    new_profile = UserProfile(user=new_user,
    _activation_key=activation_key,
    _key_expires=key_expires,
    _activated=activated)
    new_profile.save()
    return new_profile
    ## Send an email with the confirmation link
    #email_subject = 'Your new example.com account confirmation'
    #email_body = "Hello, %s, and thanks for signing up for an \
    #example.com account!\n\nTo activate your account, click this link within 48 \
    #hours:\n\nhttp://example.com/accounts/confirm/%s" % (
    #new_user.username,
    #new_profile.activation_key)
    #send_mail(email_subject,
    #email_body,
    #'accounts@example.com',
    #[new_user.email])

    def register(request):
    if request.user.is_authenticated():
    # They already have an account; don't let them register again
    return HttpResponseRedirect('/accounts/profile')
    if request.POST:
    form = RegisterForm(request.POST)
    if form.is_valid():
    new_user = User.objects.create_user(form.clean_data['username'],
    form.clean_data['email'],
    form.clean_data['password1'])
    new_user.save()

    createNewUserProfile(new_user, True)

    #request.user.message_set.create(message='Account successfully created!')
    return HttpResponseRedirect('/accounts/register/done')
    #return render_to_response('registration/register.html', {'created': True})
    else:
    form = RegisterForm()
    return render_to_response('registration/register.html', {'form': form}, \
    context_instance=RequestContext(request))

    def created(request):
    return render_to_response('registration/created.html')

    def obj_callback(f, **kwargs):
    "tell forms to ignore fields"
    if f.name[0] == "_" or f.name == "user":
    return None
    return f.formfield(**kwargs)

    def edit_profile(request):
    if not request.user.is_authenticated():
    return HttpResponseRedirect("/accounts/login/")
    try:
    profile = request.user.get_profile()
    except UserProfile.DoesNotExist:
    # create new Profile for that user
    profile = createNewUserProfile(request.user, True)

    ProfileForm = newforms.models.form_for_instance(profile, formfield_callback=obj_callback)

    if request.method == 'POST':
    form = ProfileForm(request.POST)

    if form.is_valid():
    for key in form.clean_data:
    profile.__setattr__(key, form.clean_data[key])
    profile.save()
    request.user.message_set.create(message='data saved')
    else:
    form = ProfileForm()
    return render_to_response('registration/profile.html', {
    'form': form,
    'username' : request.user.username
    }, context_instance=RequestContext(request))

    def created(request):
    return render_to_response('registration/created.html')

    def loginajax(request):
    manipulator = AuthenticationForm(request)
    redirect_to = request.POST.get('next', '')
    if request.POST:
    errors = manipulator.get_validation_errors(request.POST)
    if not errors:
    if not redirect_to or '://' in redirect_to or ' ' in redirect_to:
    redirect_to = '/accounts/profile/'
    request.session[SESSION_KEY] = manipulator.get_user_id()
    request.session.delete_test_cookie()
    return HttpResponse(redirect_to)
    else:
    return HttpResponse("false")

    what template do you want?

  3. TaMeR
    April 4th, 2007 at 01:19 | #3

    Thank you

  4. Henrik
    April 8th, 2007 at 23:28 | #4

    Nice idea, but it seems like a hack to me. Introducing field naming conventions clashes with managing the field names in the db. It also assumes that you will only use one sort of form for your userprofile. I already have 2 in my app, and havent even started on allowing users to modify their settings.

    If you really want to maintain form configuration in the model, class Meta seems a much better place. admin_only = ('user','activated','key_expires')

  5. April 9th, 2007 at 00:23 | #5

    @hendrik:
    i just used this hack, as i did not found the method you propose.
    i think the biggest problem of newforms atm is the lack of documentation and real-world examples!

  6. maliciouskitty
    April 9th, 2007 at 14:27 | #6

    It might be easier to just add "editable=False" to the fields, and newforms won't render it:

    change _activated = models.BooleanField() to
    activated = models.BooleanField(editable=False)

  7. April 9th, 2007 at 16:09 | #7

    when i developed this, this function did not work. hopefully it is working now.

  1. No trackbacks yet.


eight − = 4