[Django]-Django custom registration fields

1👍

I eventually used Django Registration’s own signals to give me this fix.

I will clean up the try/except flow at some point. dokkaebi also points out above that I might be able to assess the request.GET parameters for when a checkbox is left empty.

My app / models.py

from registration.signals import user_registered
from django.dispatch import receiver

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    event_commitments = models.ManyToManyField(Event, null=True, blank=True)
    receive_email = models.BooleanField(default=True)

@receiver(user_registered)
def registration_active_receive_email(sender, user, request, **kwargs):
    user_id = user.userprofile.id
    user = UserProfile.objects.get(pk=user_id)

    try:
        if request.POST['receive_email']:
            pass
    except:
        user.receive_email = False
        user.save()

Registration app / forms.py

class RegistrationForm(forms.Form):

    # default fields here, followed by my custom field below

    receive_email = forms.BooleanField(initial=True, required=False)

2👍

What you have looks like a workable approach.

I’ve looked through the django-registration code, and based on the following comments in the register view I’ve come up with another solution. I’m not totally sure this is cleaner, but if you aren’t a fan of signals this is good. This also provides a much easier avenue if you intend to make more customizations.

# from registration.views.register:
"""
...
2. The form to use for account registration will be obtained by
   calling the backend's ``get_form_class()`` method, passing the
   ``HttpRequest``. To override this, see the list of optional
   arguments for this view (below).

3. If valid, the form's ``cleaned_data`` will be passed (as
   keyword arguments, and along with the ``HttpRequest``) to the
   backend's ``register()`` method, which should return the new
   ``User`` object.
...
"""

You could create a custom backend and override those mentioned methods:

# extend the provided form to get those fields and the validation for free
class CustomRegistrationForm(registration.forms.RegistrationForm):
    receive_email = forms.BooleanField(initial=True, required=False)

# again, extend the default backend to get most of the functionality for free
class RegistrationBackend(registration.backends.default.DefaultBackend):

    # provide your custom form to the registration view
    def get_form_class(self, request):
        return CustomRegistrationForm

    # replace what you're doing in the signal handler here
    def register(self, request, **kwargs):
        new_user = super(RegistrationBackend, self).register(request, **kwargs)
        # do your profile stuff here
        # the form's cleaned_data is available as kwargs to this method
        profile = new_user.userprofile
        # use .get as a more concise alternative to try/except around [] access
        profile.receive_email = kwargs.get('receive_email', False)
        profile.save()
        return new_user

To use the custom backend, you can then provide separate urls. Before including the default urls, write 2 confs that point at your custom backend. Urls are tested in the order defined, so if you define these two before including the defaults, these two will capture before the default ones are tested.

url(r'^accounts/activate/(?P<activation_key>\w+)/$',
    activate,
    {'backend': 'my.app.RegistrationBackend'},
    name='registration_activate'),
url(r'^accounts/register/$',
    register,
    {'backend': 'my.app.RegistrationBackend'},
    name='registration_register'),

url(r'^accounts/', include('registration.backends.default.urls')),

The docs actually describe all this, but they aren’t particularly accessible (no readthedocs). They are all included in the project, and I was browsing them here.

Leave a comment