-2

我正在尝试学习 auth django 系统,但我有几个问题。

我想使用电子邮件身份验证创建多个用户。所以,我使用了 AbtractBaseUserAbtractBaseManager。我在网站上阅读了 django doc 和这个问题:使用 Django 1.5 实现多种用户类型

我想使用它。所以,我尝试实现第二点:我的两种用户类型的所有字段都在 1 个模型中,并且使用 user_type 变量我可以选择要显示的字段。我的代码在下面:

模型.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 文件

后端.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 中,我会尝试在我的 views.py 中使用 CRUD 系统来创建和更新用户。

在我的文件下面:

表格.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),
        }

在这里,我认为它太复杂了,但我不知道如何降低复杂性。

视图.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 系统似乎失败了。所以,我第一次尝试解决:它是在我的表单中覆盖保存方法以使用 request.user.set_password 但它不起作用。

我知道这是一个很长的解释。但是每个人都可以给我一个带有 2 个表单的 CreateView 类的例子吗?如果不能使用类而是函数如何实现这个函数?

我提前谢谢你

4

1 回答 1

2

我将尝试回答您的多个问题,但请在未来 - 每个帖子一个问题。我知道你是新人,但 StackOverflow 不是一个讨论论坛,请查看帮助部分(每页底部的链接),特别是关于提问的部分。


我想使用电子邮件身份验证创建多个用户。[...] 你认为这是正确的吗?或者我应该为不同类型的用户创建 1 个具有公共字段的类和 2 个类?

如果它与你一起工作,它是正确的。这类问题更适合codereview.stackexchange.com。特别是因为没有错误。

但是,如何进行多表继承?可能吗 ?如果我有例如 [...],在检查密码之前如何知道用户类型是什么

首先,身份验证后端是完全不同的主题;它们与多表继承没有任何关系(我认为您的意思是关系或多个用户配置文件)。

如果您的密码认证算法对于每种用户类型都不同,您只需要多个认证后端。如果所有用户密码都存储在同一个位置/系统/数据库中,那么您不需要多个身份验证后端。

您应该在基本用户类中实现一个方法,该方法返回用户的类型。然后,您可以使用user_passes_check装饰器来限制视图中的访问。

这样,您将实现“本节仅适用于学生”等之后的我认为的目标。

最后,使用我的 models.py 和 backend.py,我会尝试在我的 views.py 中使用 CRUD 系统来创建和更新用户 [..] 在这里,我认为它太复杂了,但我不知道如何降低复杂性.

您不需要在 ModelForm 中重复模型的所有字段,只需要在需要修改字段时覆盖字段,或者在表单中添加额外的“非模型”字段。您可以从简单的 ModelForm 开始,如下所示:

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

添加额外字段的常见用途是通过额外的密码字段来要求密码确认。

对于 CreateProfile,我想在我的模板中发送 2 个表格,感谢 javscript,我可以选择正确的表格。但是当我提交表单时,我的用户密码有误。当我在管理页面中检查我的用户时,hashpassword 系统似乎失败了。所以,我第一次尝试解决:它是在我的表单中覆盖保存方法以使用 request.user.set_password 但它不起作用。

使用表单向导来实施多步骤注册过程。第一步,您询问要创建的基本信息和帐户类型;第二步,您只发送相关表单,而不是发送两个表单,然后使用 javascript 切换它们。

我在您的代码中看不到您使用的任何地方set_password,因此无法对第二部分发表评论。

于 2014-06-16T14:44:30.567 回答