在Python Django中创建多种用户类型并使用代理模型
在这篇文章中,我们将了解代理模型的概念,以及根据你在Django中的应用需求实现多种用户类型。
什么是Django中的代理模式
一个继承的代理模型可以有一些额外的功能、方法,以及与创建者或程序员所定义的父模型不同的行为。这在一些情况下可能很有用,比如有多种类型的用户从同一个用户模型继承,为代理(新继承的模型)定义新的功能,而这些功能只为代理(新继承的模型)使用,等等。新的字段不能被添加到代理模型中,代理模型的限制是你不能在那里有自定义字段。
创建一个代理模型的属性:
- 代理模型正好可以继承自一个非抽象的模型类。
- 它不能继承于多个非抽象模型类,因为它不能提供数据库中不同表中的行之间的连接。
- 它可以继承自任何数量的抽象类模型。
- 代理模型可以继承自任何数量的具有相同的非抽象父类的代理模型。
在Django中可以用代理模型做什么
- 我们可以通过以下方式改变模型的Pythonic行为,比如改变排序,用不同于父类的名字注释模型,等等。
- 我们可以有一个代理模型,并有一个定制的query_set,根据模型获得相关的数据。
- 我们可以有各种方法、属性和功能,这些都是该模型所特有的。
- 我们可以创建多种类型的用户,这些用户继承自你的基本用户模型,他们都可以登录、认证,并执行不同的功能。
文件结构:
一步一步实现
第1步:创建一个名为ProxyModel.的Django项目。
django-admin startproject ProxyModel
第2步:移动到项目文件夹,然后创建一个名为proxymodelapp的应用程序。
python manage.py startapp proxymodelapp
第3步:创建应用程序后,进入setting.py并在INSTALLED_APPS中注册该应用程序。
INSTALLED_APPS = [
# add to the installed apps .
'proxymodelapp.apps.ProxymodelappConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
第4步:为ProxyModel项目设置URL。
第5步:为proxymodelapp应用程序设置URL。
第6步:将代码粘贴到proxymodelapp/views.py中。
from django.shortcuts import render
def homePage(request) :
return render(request , "proxymodelapp/homePage.html" )
第7步:我们将创建一个自定义的用户名为UserAccount,其对象名为UserAccountManager,具有字段和权限。它将给不同的用户提供权限。在这里,我们将创建两种类型的用户:教师和学生,除了模型中的基本字段,我们还将添加两个字段,即is_teacher和is_student,因为它们不是必需的,但对于小问题,这可能是有帮助的。
proxymodelapp/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser , BaseUserManager
class UserAccountManager(BaseUserManager):
def create_user(self , email , password = None):
if not email or len(email) <= 0 :
raise ValueError("Email field is required !")
if not password :
raise ValueError("Password is must !")
user = self.model(
email = self.normalize_email(email) ,
)
user.set_password(password)
user.save(using = self._db)
return user
def create_superuser(self , email , password):
user = self.create_user(
email = self.normalize_email(email) ,
password = password
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using = self._db)
return user
class UserAccount(AbstractBaseUser):
class Types(models.TextChoices):
STUDENT = "STUDENT" , "student"
TEACHER = "TEACHER" , "teacher"
type = models.CharField(max_length = 8 , choices = Types.choices ,
# Default is user is teacher
default = Types.TEACHER)
email = models.EmailField(max_length = 200 , unique = True)
is_active = models.BooleanField(default = True)
is_admin = models.BooleanField(default = False)
is_staff = models.BooleanField(default = False)
is_superuser = models.BooleanField(default = False)
# special permission which define that
# the new user is teacher or student
is_student = models.BooleanField(default = False)
is_teacher = models.BooleanField(default = False)
USERNAME_FIELD = "email"
# defining the manager for the UserAccount model
objects = UserAccountManager()
def __str__(self):
return str(self.email)
def has_perm(self , perm, obj = None):
return self.is_admin
def has_module_perms(self , app_label):
return True
def save(self , *args , **kwargs):
if not self.type or self.type == None :
self.type = UserAccount.Types.TEACHER
return super().save(*args , **kwargs)
代码解释:
- 在UserAccount模型中,创建了一个新的类Types(models.TextChoices),它将为我们提供选择UserAccount内部的代理模型的用户类型。
- 创建了一个字段类型,告诉用户的类型,默认设置为教师,电子邮件字段对于一个认证系统来说是唯一的。这里我们定义了3个字段,即is_superuser, is_admin, and is_staff,这为用户提供了权限。
- 创建了两个新的字段is_student和is_teacher,它们只是布尔字段,告诉用户是教师还是学生。
- 在保存时,如果没有为用户定义类型,则将其设置为教师。
- 我们还创建了两个函数create_user和create_superuser,帮助创建具有不同权限的用户和超级用户。这个方法create_user将被用于我们的代理模型来创建用户,这样做是因为在代理模型中没有办法对密码进行散列。
第8步:在setting.py中设置认证模型,该模型将用于所有工作。
settings.py
AUTH_USER_MODEL = "proxymodelapp.UserAccount"
第9步:在创建了用户认证模型后,主要的任务是用代理模型创建多个用户类型,并配备各自的管理器,如果我们不为代理模型创建管理器,它们将继承父模型。在models.py中添加两个模型。
proxymodelapp/models.py
class StudentManager(models.Manager):
def create_user(self , email , password = None):
if not email or len(email) <= 0 :
raise ValueError("Email field is required !")
if not password :
raise ValueError("Password is must !")
email = email.lower()
user = self.model(
email = email
)
user.set_password(password)
user.save(using = self._db)
return user
def get_queryset(self , *args, **kwargs):
queryset = super().get_queryset(*args , **kwargs)
queryset = queryset.filter(type = UserAccount.Types.STUDENT)
return queryset
class Student(UserAccount):
class Meta :
proxy = True
objects = StudentManager()
def save(self , *args , **kwargs):
self.type = UserAccount.Types.STUDENT
self.is_student = True
return super().save(*args , **kwargs)
class TeacherManager(models.Manager):
def create_user(self , email , password = None):
if not email or len(email) <= 0 :
raise ValueError("Email field is required !")
if not password :
raise ValueError("Password is must !")
email = email.lower()
user = self.model(
email = email
)
user.set_password(password)
user.save(using = self._db)
return user
def get_queryset(self , *args , **kwargs):
queryset = super().get_queryset(*args , **kwargs)
queryset = queryset.filter(type = UserAccount.Types.TEACHER)
return queryset
class Teacher(UserAccount):
class Meta :
proxy = True
objects = TeacherManager()
def save(self , *args , **kwargs):
self.type = UserAccount.Types.TEACHER
self.is_teacher = True
return super().save(*args , **kwargs)
代码解释:
注意,我们通过继承UserAccount创建了Student和Teacher模型,然后我们将代理关键字设置为True,以便将模型归类为代理,并且我们重写了保存函数,在这里我们将UserAccount的类型设置为它们各自的类型,并在每次保存函数时保存它。这是因为你可能从管理面板上改变它,它将改变为另一种类型,以克服这种情况,每次都要保存该类型。我们已经为教师和学生模型创建了各自的管理器,返回各自模型的查询集,其中包含各自类型的对象。
在每个用户、教师和学生的管理者中,我们都添加了create_user方法,用来创建学生和教师。
第10步:如果你想只改变或设置一次类型,请在保存函数中使用这段代码,而不是上述保存函数的代码片段。
# for teacher snippet
def save(self , *args , **kwargs):
if not self.id or self.id == None :
self.type = UserAccount.type.TEACHER
return super().save(*args , **kwargs)
# for student snippet
def save(self , *args , **kwargs):
if not self.id or self.id == None :
self.type = UserAccount.type.STUDENT
return super().save(*args , **kwargs)
第11步:确保将所有模型注册到管理面板。
第12步:在cmd中写下以下命令,将数据迁移到数据库。
python manage.py makemigrations
python manage.py migrate
第13步:现在创建一个超级用户,他可以登录到应用程序并可以看到各种功能,为此,我们将创建一个超级用户,电子邮件:testingmail@gmail.com,密码为123。
python manage.py createsuperuser
第14步:移动到终端中的Django shell。同时,我们将从Django shell中创建两种类型的多个用户。
python manage.py shell
在这里,我们在数据库中创建了4个用户,这些用户可以登录并拥有多种功能。
from proxymodelapp.models import *
user1 = Teacher.objects.create_user(
email = "teachermailone@gmail.com" , password = "password")
user1.save()
user2 = Teacher.objects.create_user(
email = "teachermailtwo@gmail.com" , password = "password")
user2.save()
user3 = Student.objects.create_user(
email = "studentmailone@gmail.com" , password = "password")
user3.save()
user4 = Student.objects.create_user(
email = "studentmailtwo@gmail.com" , password = "password")
user4.save()
第15步:为登录页面创建一个HTML页面。这个模板有助于通过输入电子邮件及其密码来登录用户。随着用户的登录,它被重定向到主页。
proxymodelapp/templates/proxymodelapp/loginPage.html
<!DOCTYPE html>
<html>
<body>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<br />
<input type="submit" value="Submit" />
</form>
</body>
</html>
第16步:为主页创建一个HTML页面。这个模板显示谁在登录,他的电子邮件是什么,他的用户类型是什么。如果用户经过认证,将显示详细信息。
proxymodelapp/templates/proxymodelapp/homePage.html
<!DOCTYPE html>
<html>
<body>
<hr>
<br>
{% if request.user.is_authenticated %}
The current_user is : {{request.user.email}}
<br>
<br>
The type of the user is : {{request.user.type}}
{% endif %}
<br />
<br />
<a href="{% url 'login-user' %}"> Login </a>
<br />
<hr>
</body>
</html>
输出:这三种都是不同的模式,你可以从任何一种模式中登录。