2

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.

Gocht
  • 9,924
  • 3
  • 42
  • 81
  • What about to intercept the user creation signal and create whatever you want with the related information? – Omkommersind Mar 03 '16 at 14:55
  • I'd like to use the built-in function to create users. How can I interceptt that process to save another table and to fill custom fields? – Gocht Mar 03 '16 at 15:00
  • 1
    Seems better explained here: [stackoverflow.com...creating-a-extended-user-profile](http://stackoverflow.com/questions/1910359/creating-a-extended-user-profile) – Omkommersind Mar 03 '16 at 15:11
  • @ArtemChauzov Thanks, but in that example he's working with a 1-to-1 relationship to the default `auth_user` table, I want to use only another table for users, and keep using `auth_user` for admins. – Gocht Mar 03 '16 at 15:30
  • Django isn't really designed for this. Why can't you have all users in the `auth_user` table, and use the `is_staff` flag to identify admins? – Alasdair Mar 03 '16 at 15:35
  • @Alasdair That's the way I'd work usually, but this is a requirement. This is working with an existing DB structure. – Gocht Mar 03 '16 at 15:41
  • @Gocht I faced the same issue. Since the old administrators table only had a few dozens of entries, I manually moved all administrators to the members table, and added a value "Staff" to the "state" field which originally had "Active", "Inactive" and "Pending" states. My custom User model thus have a property `is_staff` that returns `self.state == self.STATE_STAFF`. Maybe this could be accurate for you? – Antoine Pinsard Mar 03 '16 at 15:54

1 Answers1

2

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='someuser@somemail.com', password='123')
<MyUserModel: MyUserModel object>
>>> 

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

Gocht
  • 9,924
  • 3
  • 42
  • 81