Search code examples
djangodjango-registration

django-registration 1.0 saving custom user fields


I've been trying to use django-registration with a custom User, but cannot get past one small problem. I added one additional field to User which DISPLAYS on the register form, but fails to SAVE any data. Here's the relevant codes:

models.py

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

class eduuser(AbstractUser):
   USER_TYPE_CHOICES = (
      #Choices
)
   user_type = models.CharField(max_length=3, choices=USER_TYPE_CHOICES)

forms.py

from registration.forms import RegistrationForm
from django import forms
from django.forms import ModelForm
from .models import eduuser

class eduuserForm(forms.ModelForm):
    class Meta:
        model = eduuser
        fields = ('user_type',)

RegistrationForm.base_fields.update(eduuserForm.base_fields)


class CustomRegistrationForm(RegistrationForm):
    def save(self, profile_callback=None):
        user = super(CustomRegistrationForm, self).save(profile_callback=None)
        edu, c = eduuser.objects.get_or_create(user=user, \
            user_type=self.cleaned_data['user_type'])

urls.py

from posts.forms import CustomRegistrationForm

urlpatterns = patterns('',
    url(r'^accounts/register/$', RegistrationView.as_view(
        form_class=CustomRegistrationForm)),
)

The problem seems to be in the forms.py file, specifically the "CustomRegistrationForm" class. That idea came from this post, which was for django-registration 0.8.

Anyways, does anyone have any idea of how to save extra custom user fields with django-registration 1.0? Any ideas/suggestions/solutions help!!


Solution

  • Well I figured out a solution, albeit a rough one. If anyone else is having similar issues in regards to adding & saving extra user fields to the registration page provided by django-registration 1.0, hopefully this will be of some help... (although I can't guarantee this will actually work for you)

    1) Create a new user model in an app, adding an extra fields you please:

    # posts/models.py
    from django.contrib.auth.models import AbstractUser
    
    class eduuser(AbstractUser):
        # Created USER_TYPE_CHOICES, omitted here due to length
        user_type = models.CharField(max_length=3, choices=USER_TYPE_CHOICES)
    

    2) Add the user model to your settings file. My app happens to be called "posts" so my user model is:

    # appName/settings.py
    AUTH_USER_MODEL = "posts.eduuser"
    

    3) Adjust django-registration to deal with a new user model. I made the changes seen here. This should not affect the functionality of django-registration, if you happen to be using it with another project.

    4) Add the extra field(s) to the form:

    # posts/forms.py
    from registration.forms import RegistrationForm
    from django import forms
    from django.forms import ModelForm
    from .models import eduuser
    
    
    class eduuserForm(forms.ModelForm):
        """
        Get extra 'user_type' field to add to form for django-registration
        """
        class Meta:
            model = eduuser
            fields = ('user_type',)
    
    RegistrationForm.base_fields.update(eduuserForm.base_fields)
    

    5) Override the RegistrationView. I'm not entirely sure why this is necessary, but I get errors without it. I believe it's saying, "Hey models, be prepared for an extra field". This is basically copy/pasted from registration/backends/default/views.py, but with the extra field added

    # posts/views.py
    from registration.backends.default.views import RegistrationView
    from registration import signals
    from registration.models import RegistrationProfile
    from django.contrib.sites.models import Site
    from django.contrib.sites.models import RequestSite
    
    class CustomRegistrationView(RegistrationView):
        """
        Needed override this django-registration feature to have it create
        a profile with extra field
        """
        def register(self, request, **cleaned_data):
            username, email, password, user_type = cleaned_data['username'], cleaned_data['email'], cleaned_data['password1'], cleaned_data['user_type']
            if Site._meta.installed:
                site = Site.objects.get_current()
            else:
                site = RequestSite(request)
            new_user = RegistrationProfile.objects.create_inactive_user(
                username, email, password, user_type, site)
            signals.user_registered.send(sender=self.__class__,
                                         user=new_user,
                                         request=request)
        return new_user
    

    6) Update the model. I did this by directly editing the django-registration model (since it's a lone-wolf project and this is my only use of it), but DO NOT do this if you are using django-registration for anything else. You could try overriding the model in your app I reckon. Anyways, in registration/models.py I added the extra field:

    # registration/models.py
    def create_inactive_user(self, username, email, password, user_type,
                             site, send_email=True):
        """
        Create a new, inactive ``User``, generate a
        ``RegistrationProfile`` and email its activation key to the
        ``User``, returning the new ``User``.
    
        By default, an activation email will be sent to the new
        user. To disable this, pass ``send_email=False``.
    
        """
        new_user = get_user_model().objects.create_user(username, email, password, user_type=user_type)
        new_user.is_active = False
        new_user.save()
    
        registration_profile = self.create_profile(new_user)
    
        if send_email:
            registration_profile.send_activation_email(site)
    
        return new_user
    

    7) Update you urls file:

    #appName/urls.py
    urlpatterns = patterns('',
        url(r'^accounts/register/$', CustomRegistrationView.as_view(
        form_class=RegistrationForm)),
    )
    

    Hopefully somebody, somewhere gets some use out of this. Happy Django-ing!