Django несколько пользователей, бэкэнд и общие представления

Я пытаюсь изучить систему аутентификации Django, и у меня есть несколько вопросов.

Я хочу создать несколько пользователей с аутентификацией электронной почты. Итак, я использовал AbtractBaseUser и AbtractBaseManager. Я прочитал django doc и этот вопрос на веб-сайте: Реализация нескольких типов пользователей с Django 1.5

и я хотел бы использовать это. Итак, я пытаюсь реализовать второй пункт: все поля для моих двух пользовательских типов находятся в 1 модели, и с помощью переменной user_type я могу выбрать поля для отображения. Мой код ниже:

models.py

# -*- coding: utf-8 -*-

from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)

TYPE_USER = (
    ('student', _('Student')),
    ('employee', _('Employee')),
)

class MyuserManager(BaseUserManager):
    def create_user(self, email, last_name, first_name, date_of_birth, user_type, password=None):
        if not email:
            raise ValueError("users must have an email address")

        user = self.model(
            email         = self.normalize_email(email),
            last_name     = last_name,
            first_name    = first_name,
            date_of_birth = date_of_birth,
            user_type     = user_type,
        )

        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, last_name, first_name, date_of_birth, user_type):
        user = self.create_user(email,
            password      = password,
            date_of_birth = date_of_birth,
            last_name     = last_name,
            first_name    = first_name,
            user_type     = user_type,
        )
        user.is_admin = True
        user.is_staff = True
        user.save()
        return user

class MyUser(AbstractBaseUser):
    """Based model user"""
    email   = models.EmailField(
        verbose_name = 'email',
        max_length=255,
        unique=True,
    )
    last_name     = models.CharField(max_length=30)
    first_name    = models.CharField(max_length=30)
    date_of_birth = models.DateField()
    user_type     = models.CharField(_('Type'), choices=TYPE_USER, max_length=20, default='student')
    phone         = models.CharField(max_length=20, blank=True)
    friends       = models.ManyToManyField("self", blank=True)
    faculty       = models.ForeignKey(Faculty, null=True, blank=True)
    desk          = models.CharField(max_length=30, blank=True)
    campus        = models.ForeignKey(Campus, null=True, blank=True)
    job           = models.ForeignKey(Function, null=True, blank=True)
    cursus        = models.ForeignKey(Cursus, null=True, blank=True)
    year          = models.IntegerField(null=True, blank=True)
    is_active     = models.BooleanField(default=True)
    is_admin      = models.BooleanField(default=False)
    is_staff      = models.BooleanField(default=False)

    objects = MyuserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['last_name', 'first_name', 'date_of_birth', 'user_type']

Вопрос: Вы считаете это правильным? или я должен создать 1 класс с общими полями и 2 класса для отдельного типа пользователя?

Далее я хотел бы использовать свой собственный бэкэнд, чтобы я внедрил файл backend.py в свой проект

backend.py

from fbLike.models import MyUser
from django.contrib.auth.backends import ModelBackend


class EmailAuthBackend(ModelBackend):
    def authenticate(self, email=None, password=None, **kwargs):
        try:
            user = MyUser.objects.get(email=email)
            if user.check_password(password):
                return user
        except MyUser.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return MyUser.objects.get(pk=user_id)
        except:
            return None

Мне кажется, это правильная реализация.

Вопросы: Но как перейти к наследованию нескольких таблиц? Является ли это возможным? как узнать тип пользователя перед проверкой пароля, если у меня есть, например:

class BaseUser(AbstractBaseUser):
  email = models.EmailField(max_length=254, unique=True)
  # common fields


class Student(BaseUser):
  first_name = models.CharField(max_length=30)
  last_name = models.CharField(max_length=30)
  # ...


class employee(BaseUser):
  company_name = models.CharField(max_length=100)
  # ...

Наконец, с моим models.py, backend.py я бы попытался использовать систему CRUD в моем views.py для создания и обновления пользователей.

Ниже мои файлы:

forms.py

class StudentProfileForm(forms.ModelForm):
    phone = forms.CharField(required=True)
    faculty = forms.ModelChoiceField(Faculty.objects.all())
    campus = forms.ModelChoiceField(Campus.objects.all())
    cursus = forms.ModelChoiceField(Cursus.objects.all())
    year = forms.IntegerField(required=True)

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'first_name', 'last_name', 
                  'date_of_birth', 'phone', 'faculty', 'campus', 'cursus', 'year'
        )
        widgets = {
            'password': forms.PasswordInput(render_value=True),
        }

class EmployeeProfileForm(forms.ModelForm):
    date_of_birth = forms.DateField(widget = AdminDateWidget)
    phone = forms.CharField(required=True)
    faculty = forms.ModelChoiceField(Faculty.objects.all())
    campus = forms.ModelChoiceField(Campus.objects.all())
    job = forms.ModelChoiceField(Function.objects.all())
    desk = forms.IntegerField(required=True)

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'first_name', 'last_name', 
                  'date_of_birth', 'phone', 'faculty', 'campus', 'job', 'desk'
        )
        widgets = {
            'password': forms.PasswordInput(render_value=True),
        }

Здесь я думаю, что это слишком сложно, но я не знаю, как уменьшить сложность.

views.py

class RegisterProfile(CreateView):
    model = MyUser
    template_name = 'fbLike/user_profile.html'
    form_class = StudentProfileForm
    second_form_class = EmployeeProfileForm

    def get_object(self):
        return super(RegisterProfile, self).get_object()

    def get_success_url(self):
        return reverse('login',)

    def get_context_data(self, **kwargs):
        context = super(RegisterProfile, self).get_context_data(**kwargs)
        if 'studenForm' not in context:
            context['studentForm'] = self.form_class
        if 'employeeForm' not in context:
            context['employeeForm'] = self.second_form_class
        return context


    def form_valid(self, form):
        self.object = MyUser.objects.create_user(**form)
        return super(RegisterProfile, self).form_valid(form)

    def form_invalid(self, form):
        return super(RegisterProfile, self).form_invalid(form)

    def post(self, request, *args, **kwargs):
        self.object = None
        if request.POST['profileType'] == 'student':
            form = self.form_class(request.POST, prefix='st')
            form.user_type = 'student'
        else:
            form = self.second_form_class(request.POST, prefix='em')
            form.user_type = 'employee'

        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)


class UpdateProfile(UpdateView):
    model = MyUser
    template_name = 'fbLike/modify_profile.html'

    def get_form_class(self):
        if self.request.user.user_type == 'student':
            return StudentProfileForm
        return EmployeeProfileForm

    def get_success_url(self):
        return reverse('welcome',)

Для CreateProfile я хотел бы отправить 2 формы в моем шаблоне, и благодаря javscript я могу выбрать правильную форму. Но когда я отправляю форму, у меня появляется ошибка с паролем пользователя. Когда я проверяю своих пользователей на странице администратора, система hashpassword, похоже, дает сбой. Итак, моя первая попытка решить: это было переопределить метод save в моей форме, чтобы использовать request.user.set_password, но он не работает.

Я знаю, что это длинное объяснение. Но каждый может дать мне пример класса CreateView с 2 формами, пожалуйста? Если не возможно использовать класс, но функцию, как реализовать эту функцию?

Я благодарю вас заранее

1 ответ

Я постараюсь ответить на несколько ваших вопросов, но, пожалуйста, в будущем - один вопрос на пост. Я понимаю, что вы новичок, но Stackru не является дискуссионным форумом, посмотрите раздел справки (ссылка внизу каждой страницы), в частности раздел, посвященный вопросам.


Я хочу создать несколько пользователей с аутентификацией электронной почты. [...] Как вы думаете, это правильно? или я должен создать 1 класс с общими полями и 2 класса для отдельного типа пользователя?

Это правильно, если это работает с вами. Эти вопросы лучше подходят для http://codereview.stackexchange.com/. Тем более, что нет ошибки.

Но как поступить с многостольным наследованием? Является ли это возможным? как узнать тип пользователя, прежде чем проверять пароль, если у меня есть, например, [...]

Во-первых, бэкэнды аутентификации - это совсем другая тема; они не имеют ничего общего с наследованием нескольких таблиц (я думаю, вы имеете в виду отношения или несколько профилей пользователей).

Вам потребуется только несколько аутентификационных бэкэндов, если ваш алгоритм аутентификации по паролю отличается для каждого типа пользователя. Если все пароли пользователей хранятся в одном и том же месте / системе / базе данных, вам не нужно несколько бэкэндов аутентификации.

Вы должны реализовать метод в вашем базовом пользовательском классе, который возвращает тип пользователя. Вы можете использовать user_passes_check декоратор, чтобы ограничить доступ в ваших взглядах.

Таким образом, вы достигнете того, что я считаю тем, чем вы являетесь после "этого раздела только для студентов" и т. Д.

Наконец, с моим models.py, backend.py я бы попытался использовать систему CRUD в моем views.py для создания и обновления пользователей [..] Здесь я думаю, что это слишком сложно, но я не знаю, как уменьшить сложность.,

Вам не нужно повторять все поля вашей модели в ModelForm, вам нужно только переопределить поля, если вам нужно изменить их, или добавить дополнительные "немодельные" поля в форму. Вы можете начать с простой ModelForm, например так:

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('name', 'email', 'password')

Обычное использование добавления дополнительного поля - запросить подтверждение пароля, имея дополнительное поле пароля.

Для CreateProfile я хотел бы отправить 2 формы в моем шаблоне, и благодаря javscript я могу выбрать правильную форму. Но когда я отправляю форму, у меня появляется ошибка с паролем пользователя. Когда я проверяю своих пользователей на странице администратора, система hashpassword, похоже, дает сбой. Итак, моя первая попытка решить: это было переопределить метод save в моей форме, чтобы использовать request.user.set_password, но он не работает.

Используйте мастер форм для реализации многоэтапного процесса регистрации. На первом этапе вы запрашиваете основную информацию и тип учетной записи для создания; на втором шаге вы отправляете только соответствующую форму, а не отправляете две формы, а затем переключаете их с помощью JavaScript.

Я не вижу нигде в вашем коде, где вы используете set_passwordпоэтому не могу комментировать вторую часть.

Другие вопросы по тегам