Monthly Archives: December 2015

Django-allauth and modelforms

It took me a ridiculously long and frustrating time to work out how to do this, so I’m documenting what I’ve done in the hope that it helps someone else. If you want to extend the Django user model (to create a user profile, as described in the docs https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#extending-the-existing-user-model) to create a user profile, and to still use Django-allauth you might as well give up on the documentation: it’s not going to help you. But what you need to do is fairly simple:

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    phone = models.CharField(max_length=100)

forms.py

class SignupForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('first_name', 'last_name', 'phone', 'type')

    # A custom method required to work with django-allauth, see https://stackoverflow.com/questions/12303478/how-to-customize-user-profile-when-using-django-allauth
    def signup(self, request, user):
        # Save your user
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()

        # Save your profile
        profile = Profile()
        profile.user = user
        profile.phone = self.cleaned_data['phone']
        profile.type = self.cleaned_data['type']
        profile.save()

settings.py

# Required by django-allauth to extend the sign up form to include profile data
ACCOUNT_SIGNUP_FORM_CLASS = 'core.forms.SignupForm'

I’m not sure why I thought that django-allauth would take care of saving user profiles when it very explicitly says it doesn’t do anything apart from authentication. I suppose we should count ourselves lucky that it’s easy to extend the form to include additional profile fields.

Django multi select multiple choice model field

To me, it doesn’t really make sense to store static data in a database – especially if there are only 5 or 6 errr datum you are wanting to store. Django allows you to use a Charfield with choices, i.e.

WIND = 'W'
SOLAR = 'S'
ENERGY_TYPE_CHOICES = (
    (WIND, 'Wind turbine'),
    (SOLAR, 'Solar panels')
)
energy_type = models.CharField(max_length=1, choices=ENERGY_TYPE_CHOICES, default=WIND)

But unfortunately you can’t select multiple choices, so in this case it wouldn’t be possible to associate both wind & solar with one of my models. It is suggested that developers store this info in a separate table and associate the choices with models using a manytomanyfield. Perhaps this makes sense if you want to associate the field options with multiple models, but it really seems overkill if you just want to have multiple choices for a single model.

Strangely there don’t seem to be many other people who have felt this to be too much (I mean, going by google anyway). As I have frequently found with Django, a few people have discussed it on stackoverflow and there are a million ways of doing the same thing with no clear indiciation as to which is most widely used and most sensible. Well, there are 3 different modules/alternatives:

  • Multiselectfield: https://github.com/goinnn/django-multiselectfield
  • Multiple_select_field: https://gist.github.com/kottenator/9a50e4207cff15c03f8e
  • Select_multiple_field: https://github.com/kelvinwong-ca/django-select-multiple-field

This is ridiculous. Django’s “do-it-yourself” attitude is refreshing after coming from PHP and Drupal, but why isn’t something this ubiquitous integrated into Django itself?  This is something many projects are going to want. Or do I have it wrong and is it better to have a separate db table for like 2 or 3 fields?