首页 >后端开发 >Python教程 >Django 帐户管理应用程序(注册和激活

Django 帐户管理应用程序(注册和激活

Patricia Arquette
Patricia Arquette原创
2024-11-04 21:57:021085浏览

从这篇文章中可以期待什么?

我们在上一篇文章中已经创建了项目的骨架结构,本文将在此基础上进行构建。它将覆盖

  • 账户数据库结构,包括用户和验证码。
  • 模型序列化器。
  • 帐户注册、激活的帐户视图。下一篇文章应该涵盖其余的视图,例如登录、刷新令牌、更改密码、忘记密码和重新发送代码。

我会尽力介绍尽可能多的细节,以免让您感到无聊,但我仍然希望您熟悉 Python 和 Django 的某些方面。

最终版本的源代码可以在 https://github.com/saad4software/alive-diary-backend

系列订购

感兴趣的话可以查看之前的文章!

  1. 从头开始的人工智能项目、创意、Alive 日记
  2. 用 Google AI Studio 证明它是可行的
  3. Django API 项目设置
  4. Django 账户管理应用程序(一)、注册和激活(你在这里?)

帐户应用程序设置

让我们在应用程序中创建序列化器文件

from rest_framework import serializers
from app_account.models import *

app_account/serializers.py

和网址文件

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/urls.py

最后,让我们通过将项目 url 文件编辑为
将应用程序 url 连接到项目 url

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

alive_diary/urls.py

现在我们可以调用任何前缀为“api/account/”的账户网址

模特

帐户应用程序的主要模型当然是用户模型

from django.db import models
from django.contrib.auth.models import AbstractUser
from datetime import timedelta, datetime

class User(AbstractUser):
    userTypes = (
        ('A', 'Admin'),
        ('C', 'Client'),
    )

    role = models.CharField(max_length=1, choices=userTypes, default="C")

    hobbies = models.CharField(max_length=255, null=True, blank=True)
    job = models.CharField(max_length=100, null=True, blank=True)
    bio = models.TextField(null=True, blank=True)

    country_code = models.CharField(max_length=10, null=True, blank=True)
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=30))

app_account/models.py

通常,最好保持用户模型尽可能简单,并将其他详细信息移动到与用户具有一对一关系的配置文件模型中,但为了简化事情,我将添加所需的用户信息这次直接进入 User 模型。

我们继承AbstractUser模型,AbstractUser包含多个字段

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(...)
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    email = models.EmailField(...)
    is_staff = models.BooleanField(...)
    is_active = models.BooleanField(...),
    date_joined = models.DateTimeField(...)

最重要的是:

  • 用户名将用于登录。
  • is_active 将用于防止未经验证的帐户登录。
  • is_staff 将区分 admin(值为 true)和普通用户。

我们还为此项目用户添加了多个字段,它们是

  • 为了区分管理员和客户帐户,我们可以在这个简单的项目中使用 is_staff,因为我们只有两个角色,但较大的项目可以有两个以上的角色,使得该字段对于权限处理至关重要。
  • 爱好、工作、个人简介 更多地了解用户有助于建立更好的反思,因此我们询问用户的爱好、工作以及如何描述自己。
  • 用于统计的国家/地区代码
  • Expiration_date 表示基于订阅的到期日期。

我们还需要一个验证码模型来保存和跟踪帐户激活、忘记密码和重新发送验证码的验证码。

from rest_framework import serializers
from app_account.models import *

app_account/models.py

它与 User 模型连接并生成 6 位代码的随机值。它还有 24 小时的过期时间。我们还归档了电子邮件,以防用户想要验证多个电子邮件地址,这种情况很少见,可以为此应用程序删除。接下来让我们转向序列化器。

注册API

让我们从序列化器开始

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/serializers.py

我们正在使用来自 Django Rest 框架的 ModelSerializer。我们在 Meta 类中选择了用户模型 get_user_model() 和序列化字段列表。

我们在模型序列化器中添加了两个附加字段:password1 和password2。为了验证它们具有相同的值,我们重写了 validate 方法。为了强制使用有效的电子邮件作为用户名,我们为用户名字段添加了一个字段验证器。
is_valid_email 函数应该看起来像这样

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

common/utils.py

就我个人而言,我不喜欢正则表达式,我从来没有掌握它们,但它们似乎是验证电子邮件的最佳方式。如果您有更好的方法,请与我们分享。

由于我们的新字段password1和password2不属于原始用户模型,因此我们将它们从数据字典中删除并添加了password字段,以便直接使用序列化器数据来创建新用户。

序列化器的最佳实践困境

  • 序列化器应该使用数据库查询和编辑数据库吗?
  • 或者他们应该只进行基本字段类型验证(字符串、整数……)?

实际上没有明确的答案,例如,Django Rest框架模型序列化器似乎对唯一字段进行查询,就像我们在尝试创建同名用途时遇到的序列化器错误,它是由序列化器生成的,不是风景。
创建、保存、更新方法将值写入数据库。
然而,仅在视图中访问数据库似乎更符合关注点分离灵活性

你觉得哪个更好?

我读过很多关于将事物分开的内容,甚至将数据库查询与数据库更新方法分开。所以让我们尝试这样做。在views.py 文件中创建AccountActivateView 应该如下所示。

在我们的例子中,我们可以覆盖 RegisterSerializer 的创建方法,以便创建新用户和验证代码实例,甚至从序列化器发送验证代码。

但是,我会将模型相关操作保留在视图文件中

让我们转到注册视图

from rest_framework import serializers
from app_account.models import *

app_account/views.py

我们使用其余框架中的CreatAPIView,它接受具有serializer_class schema的POST请求,BrowsableAPIRenderer为此API构建一个Web界面,JSONRenderer负责构建JSON响应。

重写perform_create方法允许我们控制用户创建机制,我们正在创建用户实例,确保is_active字段设置为False,然后创建连接到新用户模型的验证码实例,最后发送向用户发送一封包含验证码的电子邮件。

发送电子邮件需要在设置文件中正确配置电子邮件字段,如果您在这一点上遇到问题,请告诉我,以便为此创建单独的文章

最后,让我们添加 API url

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/urls.py

好啊,我们来试试吧

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

打开http://localhost:8555/api/account/register,我们应该能够看到这样的内容(这是由于BrowsableAPIRenderer)

Django accounts management app ( registration and activation

必填字段为用户名、密码1和密码2,我们希望使用电子邮件作为用户名。
看起来不错,它创建了一个用户模型,并连接了一个验证码模型(使用SqlBrowser打开SQLite db文件)。但默认响应看起来像这样,状态为 201。

from django.db import models
from django.contrib.auth.models import AbstractUser
from datetime import timedelta, datetime

class User(AbstractUser):
    userTypes = (
        ('A', 'Admin'),
        ('C', 'Client'),
    )

    role = models.CharField(max_length=1, choices=userTypes, default="C")

    hobbies = models.CharField(max_length=255, null=True, blank=True)
    job = models.CharField(max_length=100, null=True, blank=True)
    bio = models.TextField(null=True, blank=True)

    country_code = models.CharField(max_length=10, null=True, blank=True)
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=30))

我希望所有回复都具有此架构

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(...)
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    email = models.EmailField(...)
    is_staff = models.BooleanField(...)
    is_active = models.BooleanField(...),
    date_joined = models.DateTimeField(...)

  • 状态应该是“成功”或“错误”
  • code 是响应状态代码
  • data 是实际的响应数据
  • 消息应包含错误文本或任何其他消息

但是该怎么做呢?
最好的方法是实现自定义 JSON 渲染器 函数。让我们开始吧

import random

class VerificationCode(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    code = models.CharField(max_length=6, default=random.randint(111111, 999999))
    email = models.EmailField()
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=1))

    def __str__(self):
        return self.user.username

common/utils.py

我们继承自JSONRenderer并覆盖了render方法。序列化器错误。

  • 首先读取响应状态代码,并将其放入代码字段
  • 我们将实际响应数据移动到响应架构中的数据字段
  • 为了区分错误和成功响应,我们检查状态代码。如果状态码在 200 系列中,则表示成功响应
  • 如果不是,那就是一个错误。因此我们将状态更改为“错误”,并从响应详细信息字段中提取错误消息(如果可用)。
  • 序列化器的验证错误没有详细信息字段,它是一个字典,指示每个字段名称(键)的错误消息(值),因此我们创建了一个小函数 dict2string 将其转换为简单字符串。我觉得还可以进一步改进,你能帮忙吗?

这就是响应模式,让我们现在尝试使用它!
在views.py中将我们的自定义渲染器添加到注册视图类

from rest_framework import serializers
from app_account.models import *

app_account/views.py

运行服务器,打开http://localhost:8555/api/account/register/ 直接看到区别

Django accounts management app ( registration and activation

我们可以在错误消息中看到我们的架构?,酷,让我们尝试注册一个新用户,我将其称为“test5@gmail.com”

Django accounts management app ( registration and activation

看起来很棒,现在让我们测试序列化器验证错误,我们将尝试再次注册同一用户

Django accounts management app ( registration and activation

太棒了,这是一个验证错误响应,它被序列化为字段:消息
注册后会发生什么?这是验证
注册->确认电子邮件->登录->无论如何

激活API

我们要检查用户是否收到了我们在注册时发送的激活码,如果用户发送了正确的代码,我们将激活他们的帐户,如果没有,我们将要求他们再次检查,或者也许重新发送代码(稍后使用另一个 API)
与注册 API 创建过程类似,让我们从序列化器开始

from django.urls import path, include
from .views import *

urlpatterns = [

]

这与某个数据库模型无关,所以我们继承自通用序列化器,注意序列化器与表单类似,所以我们设置字段及其验证规则。
我们使用两个字符串字段(CharField),两者都是必需的,用户名(用户电子邮件地址)和代码。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

app_account/views.py

由于我们使用的是自定义API视图,因此我们继承自APIView,它提供了5个功能(get、post、put、delete和patch)。我们从 POST 请求中反序列化请求数据,并验证其类型,然后进行查询以查找提供的数据是否存在,如果存在,我们激活用户并从其表中删除代码对象。如果不是,我们会发送一条错误消息,指出它是“invalid_code”。最后,应该更新 URL 文件以包含此视图的 URL

from rest_framework import serializers
from app_account.models import *

app_account/urls.py

现在我们可以打开URL http://localhost:8555/api/account/activate/,我们使用的是自定义API视图,所以它没有获取必填字段

Django accounts management app ( registration and activation

我们可以从数据库中获取代码(用于测试目的)。该请求应类似于

from django.urls import path, include
from .views import *

urlpatterns = [

]

如果一切顺利,响应应该如下所示

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

就是这样
让我们总结一下吧!我知道我们还没有登录,但这确实是一篇很长的文章,我们下一篇继续

敬请期待?

以上是Django 帐户管理应用程序(注册和激活的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn