0

I noticed that the User model that Django provides does not have a Date of Birth Field. I do not want to write my own custom User class just to include this attribute. I am wondering if it is possible in some way to "attach" date of birth to the User model. If not what are the other simple options to make this work. I am also ok to save the contents of User Model to a profile model with additional date of birth information.

But would my form has to save both User and profile model which I am confused as how this work.

EDIT 2: (After implementing frnhr's solution):

Two issues: No activation email is sent out in the development server. I tried default User model with django-registration and I see activation email being sent out. but now, with the custom user model, no activation email is sent out.

when I login as admin, http://127.0.0.1:8000/admin/, I see no User model but only registration profiles and Groups. when I click registration profiles, it does not show all the information about User, but just username and activation key which is shown as already expired. Attached is a screenshot. how to fix this? enter image description here

enter image description here

eagertoLearn
  • 9,772
  • 23
  • 80
  • 122

2 Answers2

3

In newer versions of Django, making your own custom User model is quite painless. See this answer for details: https://stackoverflow.com/a/16125609/236195

You might run into problems if you are using some older third-party apps which have model relationships hardcoded to auth.models.User. Most of third-party apps which have ongoing development have probably switched already or will do so soon.


Edit - getting it to work with django-registration

myapp/models.py:

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _

class CustomUser(AbstractUser):
    age = models.PositiveIntegerField(_("age"), null=True)  # this field is added to default User model

settings.py:

INSTALLED_APPS = (
    # ...

    'registration_defaults',
    'registration',

    'myapp',
)

# ...

AUTH_USER_MODEL = "myapp.CustomUser"
ACCOUNT_ACTIVATION_DAYS = 2  # or something

urls.py (add this line):

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

myapp/admin.py (optionally):

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _

from .models import CustomUser


class CustomUserAdmin(UserAdmin):
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'age')}),  # added "age" field
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
                                       'groups', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )


admin.site.register(CustomUser, CustomUserAdmin)

django-registration

Get it from here: https://bitbucket.org/fhrzenjak/django-registration and put it in your project folder.

Disclaimer: this is my fork of the original django-registration repo, with applied patch for custom user models by mrginglymus: https://bitbucket.org/ubernostrum/django-registration/pull-request/30/django-15-compatibility-with-custom-user/diff

Django-registration-defaults is a collection of default templates from here: https://github.com/yourcelf/django-registration-defaults It's pip-installable

EDIT 2 - accept a custom field on registration

Well, this is a separate question, but ok here is how...

Create a MyRegistrationFormform:

from registration.forms import RegistrationForm

class MyRegistrationForm(RegistrationForm):
    age = forms.CharField(required=False)

In your urls.py add a line before django-registration include. That will override whatever is in the include:

url(r'^accounts/register/$',
        RegistrationView.as_view(form_class=MyRegistrationForm),
        name='registration_register',
    ),
url(r'^accounts/', include('registration.backends.default.urls')),

Modify your custom user model to respond on user_registered signal and save the additional data:

class CustomUser(AbstractUser):
    age = models.PositiveIntegerField(_("age"), null=True)

    @classmethod
    def user_created(cls, sender, user, request, **kwargs):
        from myapp.forms import MyRegistrationForm
        form = MyRegistrationForm(request.POST)
        user.age = form.data.get('age', None)
        user.save()
        pass

from registration.signals import user_registered
user_registered.connect(CustomUser.user_created)
Community
  • 1
  • 1
frnhr
  • 12,354
  • 9
  • 63
  • 90
  • thanks for the answer. I actually want to use with third party app. `django-registration.`. It claims to provide a way to extend user model, but that is not trivial. – eagertoLearn Mar 21 '14 at 18:06
  • django-registration is compatible with custom user models – frnhr Mar 21 '14 at 18:14
  • Thats what it claims, do you have some code snippet how you made it to work or some links, I have followed many posts, but it is not straightforward in my opinion. This link claims it is simple. but actually it is not. http://johnparsons.net/index.php/2013/06/28/creating-profiles-with-django-registration/ – eagertoLearn Mar 21 '14 at 18:16
  • Looks like I was wrong: django-registration is not compatible with the custom user model. There was a patch ages ago, it has been reject4ed by the author of django-registration, and for no good reason, it would seem: https://bitbucket.org/ubernostrum/django-registration/pull-request/30/django-15-compatibility-with-custom-user – frnhr Mar 21 '14 at 19:35
  • @eagertoLearn I got django-registration to work with custom user model, see the updated anwser – frnhr Mar 21 '14 at 19:48
  • I gave it a try with your custom user model but I have few issues which I pasted above. please see the edit above – eagertoLearn Mar 22 '14 at 18:34
  • @eagertoLearn See updated answer. That is quite a separate question, though. – frnhr Mar 22 '14 at 19:38
  • First of all, big thanks to you!. you have a great knowledge in Django!. I think I have almost got it to work, just a couple of issues. please help me fix that. I have pasted in Edit 2 above. Thanks a lot – eagertoLearn Mar 23 '14 at 05:04
  • I have my code (which is exactly as you guided) is available here; https://github.com/sridhar1982/djangoRegistration_CustomUser, please help me to fix this issue! – eagertoLearn Mar 23 '14 at 20:31
  • See the above "**myapp/admin.py** (optionally):" section, that is how you add the custom user model to admin. – frnhr Mar 23 '14 at 21:58
  • BTW, Registration Profiles are something else (not holding your user fields). – frnhr Mar 23 '14 at 21:59
  • I get this error for password reset `Reverse for 'password_reset_complete' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []`, in the github repo, I gave above. please help in fixing this.. – eagertoLearn Mar 24 '14 at 07:00
  • during development phase, I used to do `python -m smtpd -n -c DebuggingServer localhost:1025` on a `terminal` and the `activation emails` are sent to this `terminal`. but now I see (with your changes and your `git repo`), the `activation email` is sent to same `terminal` as where I run `./manage.py runserver`. why is that? – eagertoLearn Mar 24 '14 at 17:41
  • [Console Email Backend](https://docs.djangoproject.com/en/1.7/topics/email/#console-backend) it for developmeny only. It's a quick way to work with emails locally without having to set up an email server on your dev box. Your solution seems quite ok, but in that case use default Email Backend in your `settings.py`(i.e. remove the `EMAIL_BACKEND = ... ` line from `setting.py`). – frnhr Mar 24 '14 at 18:36
  • Thanks for the reply. In the CustomUser class above, there is only field `age` but I see in the `admin page`, it has `fields` such as `username`, `email` etc, where does they come from? I have defined my own `CustomUser model` that has only `field` in it correct? so why these extra fields? – eagertoLearn Mar 24 '14 at 22:53
  • Inherited from `django.contrib.auth.models.AbstractUser` (if I got it correct there). [Django Model Inheritance](https://docs.djangoproject.com/en/1.7/topics/db/models/#model-inheritance) May I recommend a book: [Tango With Django](http://www.tangowithdjango.com/) And there are always [the official tutorials](https://docs.djangoproject.com/en/1.7/intro/) – frnhr Mar 24 '14 at 23:04
1

Your best bet is probably to go ahead and create a custom User model (you can subclass django.contrib.auth.models.AbstractUser and add whatever fields you want).

Regarding processing multiple models in single form, it's actually quite easy. You actually want to use multiple Forms, but render them both in the same <form> element, and process them separately in the view.

Another approach is just to create a single Form (probably not a ModelForm), which contains all of the fields you want. Then, write a save method on your form, which creates/updates the relevant models. This makes your view and template code simpler than the approach above.

As an example, here is a form class that lets an existing user change their email address and date of birth. Note that you pass the logged in User from your view when calling save():

class UserEditForm(forms.Form):
    email = forms.EmailField()
    date_of_birth = forms.DateField()

    def save(self, user):
        user.email = self.cleaned_data['email']
        user.save()
        user.userprofile.date_of_birth = self.cleaned_data['date_of_birth']
        user.userprofile.save()

Note this assumes you have a UserProfile model, which has a one-to-one field to User.

Chris Lawlor
  • 47,306
  • 11
  • 48
  • 68
  • I want to integrate my custom user model with `django-registration` app which is not trivially simple. I followed this post: `http://johnparsons.net/index.php/2013/06/28/creating-profiles-with-django-registration/` but it is not updating the User model at all. – eagertoLearn Mar 21 '14 at 18:11
  • Based on my experience in getting ``django-registration`` to work with custom User models about a year ago, I'd say you are probably better off writing your own registration workflow. – Chris Lawlor Mar 21 '14 at 18:23