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
поэтому не могу комментировать вторую часть.