Gocht
Gocht

Reputation: 10256

Work with two Users table

I wonder if is it possible to use the default django.contrib.auth.models.User to store admins users, users created with python manage.py createsuperuser, but use another table to store registered by form users, also users that will be registered with Social provides (python-social-auth). By using another table for users I will need to use the same password hashing also.

Use a 1-to-1 relationship with auth_users is not an option.

Thanks.

Upvotes: 2

Views: 2646

Answers (1)

Gocht
Gocht

Reputation: 10256

Well, this is how I did this:

From python-social-auth docs is possible define a custom model:

SOCIAL_AUTH_USER_MODEL = 'foo.bar.User'

Here I got an error when I tried 'myapp.models.MyUserModel', this must be: 'myapp.MyUserModel'.

This fixed the python-social-auth register.

For a common form register I just did a form and create a user in MyUserModel:

class RegisterAction(FormView):

    form_class = RegisterForm

    def form_valid(self, form):

        MyUserModel.objects.create(
            first_name=form.data.get('f_name'),
            password=form.data.get('pwd'),
            email=form.data.get('email'),
            newsletter=form.data.get('newsletter')
        )

        return super(RegisterAction, self).form_valid(form)

    def get_success_url(self):
        return reverse('home')

You can find docs for FormView here.

To fix the autentication methods I created a custom authentication backend:

from django.contrib.auth.hashers import check_password

from myapp.models import MyUserModel

class MyAuthenticationBackend(object):

    MODEL = MyUserModel

    def authenticate(self, email, password):
        """
            Returns a User (MODEL instance) if email and password match
        """
        if email and password:
            try:
                user = self.MODEL.objects.get(email=email)
                if check_password(password=password, encoded=user.password):
                    return user
                return None
            except self.MODEL.DoesNotExist:
                return None
        return None

    def get_user(self, user_id):
        """
            Returns a User based on user_id
        """
        try:
            user = self.MODEL.objects.get(pk=user_id)
            return user
        except self.MODEL.DoesNotExist:
            return None
        except self.MODEL.MultipleObjectsReturned:
            return None

You can find authentication backends docs here and how write your own backend here.

Then you need to register your new backend:

# Authentication Backends
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'myapp.backends.MyAuthenticationBackend',
    'social.backends.facebook.FacebookOAuth2',
    'social.backends.twitter.TwitterOAuth',
]

You will find AUTHENTICATION_BACKENDS settings docs here

Now I can go to a shell:

>>> from django.contrib.auth import authenticate
>>> authenticate(email='[email protected]', password='123')
<MyUserModel: MyUserModel object>
>>> 

And still can create user with python manage.py createsuperuser, which are stored in default auth_user table.

Upvotes: 2

Related Questions