Search code examples
djangodjango-formsdjango-registration

Python/Django django-registration add an extra field


I have read a lot about how to add an extra field when using Django-registration, for example here, here and here. The code snippets are: forms.py (from the registration app)

class RegistrationForm(forms.Form):
    username = forms.RegexField(regex=r'^\w+$', max_length=30, widget=forms.TextInput(attrs=attrs_dict), label=_("Username"), error_messages={ 'invalid': _("This value must contain only letters, numbers and underscores.") })
    email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=75)), label=_("Email"))
    password1=forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), label=_("Password"))
    institute=forms.CharField(max_length=50) #This is the new!
    password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), label=_("Password (again)"))
    captcha = CaptchaField()

I use the django's registration save method, which is in the default backend:

def register(self, request, **kwargs):
    username, email, password = kwargs['username'], kwargs['email'], kwargs['password1']
    if Site._meta.installed:
        site = Site.objects.get_current()
    else:
        site = RequestSite(request)
    new_user = RegistrationProfile.objects.create_inactive_user(username, email,
                                                                password, site)

    signals.user_registered.send(sender=self.__class__,
                                 user=new_user,
                                 request=request)
    return new_user

In models.py I have created a new class:

class UserProfile(models.Model):  
    user = models.OneToOneField(User)
    institute=models.CharField(max_length=50)
def create_user_profile(sender, instance, created, **kwargs):  
    if created:  
        profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)

In the admin.py:

admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
    model = UserProfile
class UserProfileAdmin(UserAdmin):
    inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)

I have not altered anything alse. When I render the form I can see the Institute Field I have added. When I am in the admin site I can see the user profile of each user. However nothing is saved there when I create a new user while the other details of the user are normally saved. I think that I need some kind of configuration but where? Maybe in the files of the Django-registration app?


Solution

  • I have figured out a solution to this problem, and I will post it here in case somebody can use it. It's pretty simple, I suppose.

    Step 1 Add a new model, which will be a profile, in the models.py:

    #models.py
    class user_profile(models.Model):
         user=models.ForeignKey(User, unique=True)
         institution=models.CharField(max_length=200)
    
         def __unicode__(self):
             return u'%s %s' % (self.user, self.institution)
    

    Step 2 Create the form that will use this model:

    #forms.py
    from registration.forms import RegistrationForm
    from django.forms import ModelForm
    from Test.models import user_profile
    
    class UserRegForm(RegistrationForm):
        institution=forms.CharField(max_length=200)
    

    Step 3 Create ragbackend.py and define how the data will be saved:

    from Test.models import user_profile
    from forms import *
    
    def user_created(sender, user, request, **kwargs):
        form = UserRegForm(request.POST)
        data = user_profile(user=user)
        data.institution = form.data["institution"]
        data.save()
    
    from registration.signals import user_registered
    user_registered.connect(user_created)
    

    Step 4 Go to urls.py and make the following changes:

    import regbackend 
    from registration.views import register
    
    url(r'^accounts/register/$', register, {'backend': 'registration.backends.default.DefaultBackend','form_class': UserRegForm}, name='registration_register'),
    (r'^accounts/', include('registration.urls')),
    

    Note that you have to put the URLs in that order. Easy to understand why.

    Step 5 Now everything works, but you cannot see the information in the admin site. So you have to go to admin.py and add:

    #admin.py
    from django.contrib.auth.models import User
    from Test.models import user_profile
    admin.site.unregister(User)
    class UserProfileInline(admin.StackedInline):
        model = user_profile
    
    class UserProfileAdmin(UserAdmin):
        inlines = [ UserProfileInline, ]
    admin.site.register(User, UserProfileAdmin)
    

    And that's it. Do not forget the syncdb before runserver. I hope this will help someone.