django rest framework 学习笔记-实战商城

 01项目环境搭建_哔哩哔哩_bilibili  本博客借鉴至大佬的视频学习笔记


# 创建项目
django-admin startproject MyShop# 创建app
E:\desktop\my_drf\MyShop>django-admin startapp goodsE:\desktop\my_drf\MyShop>django-admin startapp orderE:\desktop\my_drf\MyShop>django-admin startapp cartE:\desktop\my_drf\MyShop>django-admin startapp users

创建apps文件夹放入的上面应用

# 注册应用
'rest_framework',
'corsheaders',
'apps.users',
'apps.goods',
'apps.cart',
'apps.order'# 配置mysql
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'shop','USER': 'root','PASSWORD': 'pass','HOST': 'localhost','PORT': 3306}
}# 允许所有的用户跨域请求
CORS_ORIGIN_ALLOW_ALL = True# 中文及时区调整
LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'

 创建shop数据库

mysql> create database shop charset=utf8;
Query OK, 1 row affected, 1 warning (0.01 sec)

 公共表设计:

# 定义继承时,需要setting自定义用户类模型
AUTH_USER_MODEL = 'users.User'
# 创建 common目录下db.py文件
from django.db import modelsclass BaseModel(models.Model):""" 抽象的模型基类,定义公共模型字段 """create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')update_time = models.DateTimeField(auto_now=True,verbose_name='更新时间')is_delete = models.BooleanField(default=False,verbose_name='删除标记')class Meta:# 声明这个是抽象模型,生成迁移文件时,不会在数据库生成表abstract = Trueverbose_name_plural = '公共字段表'db_table = 'BaseTabel'

用户表结构设计

from django.db import models
from django.contrib.auth.models import AbstractUser  # django自带的用户认证模型
from common.db import BaseModel
# Create your models here.class User(AbstractUser,BaseModel):"""用户表"""mobile = models.CharField(verbose_name='手机号',help_text='手机号',max_length=11,default='',blank=True)avatar = models.ImageField(verbose_name='用户头像',help_text='用户头像',max_length=30,null=True,blank=True)class Meta:db_table = 'users'verbose_name = '用户表'class Addr(models.Model):"""收货地址模型"""user = models.ForeignKey('User',verbose_name='所属用户',on_delete=models.CASCADE)phone = models.CharField(verbose_name='手机号',help_text='手机号',max_length=11,null=True,blank=True)name = models.CharField(verbose_name='联系人',help_text='联系人',max_length=20,null=True,blank=True)province = models.CharField(verbose_name='省份',help_text='省份',max_length=20,null=True,blank=True)city = models.CharField(verbose_name='城市',help_text='城市',max_length=20,null=True,blank=True)country = models.CharField(verbose_name='区县',help_text='区县',max_length=20,null=True,blank=True)is_default = models.BooleanField(verbose_name='是否为默认地址',help_text='省份',max_length=30,default=False)class Meta:db_table = 'addr'verbose_name = '收货地址表'class Area(models.Model):"""省市区县地址模型"""pid = models.ImageField(verbose_name='上级ID',help_text='上级ID',max_length=20,null=True,blank=True)name = models.CharField(verbose_name='地区名',help_text='地区名',max_length=20,null=True,blank=True)level = models.CharField(verbose_name='区域等级',help_text='区域等级',max_length=20,null=True,blank=True)class Meta:db_table = 'area'verbose_name = '地区表'class VerifyCode(models.Model):"""验证码模型"""mobile = models.CharField(verbose_name='手机号码',help_text='手机号码',max_length=11,null=True,blank=True)code = models.CharField(verbose_name='验证码',help_text='验证码',max_length=6,null=True,blank=True)create_time = models.DateTimeField(auto_now_add=True,verbose_name='生成时间',help_text='生成时间')class Meta:db_table = 'verifycode'verbose_name = '手机验证码表'

 执行迁移文件,生成表结构

E:\desktop\my_drf\MyShop>python manage.py makemigrations
Migrations for 'users':
  apps\users\migrations\0001_initial.py
    - Create model User
    - Create model Area
    - Create model VerifyCode
    - Create model Addr

E:\desktop\my_drf\MyShop>python manage.py migrate

 结果展示:

 用户鉴权:使用JWT认证

创建超级管理员用户

E:\desktop\my_drf\MyShop>python manage.py createsuperuser
用户名: pass
电子邮件地址: pass@qq.com
Password:
Password (again):

JWT权限认证配置

# 注册jwt
'rest_framework_simplejwt',# 配置setting
REST_FRAMEWORK = {# DRF配置鉴权方式'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication','rest_framework.authentication.BasicAuthentication',  # Basic 认证'rest_framework.authentication.SessionAuthentication',  # Session 认证),
}# 配置总路由urlspath('api/users/',include('apps.users.urls'))# user url 配置
from rest_framework_simplejwt.views import TokenVerifyView, TokenRefreshView, TokenObtainPairViewurlpatterns = [path('login/', TokenObtainPairView.as_view(), name='login'),  # 登录path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),  # token 刷新path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),  # token 效验
]

 配置Postman环境变量

Postman运行示图:

 自定义用户登录功能的实现

from rest_framework_simplejwt.views import TokenObtainPairView# Create your views here.
class LoginView(TokenObtainPairView):def post(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)try:serializer.is_valid(raise_exception=True)except TokenError as e:raise InvalidToken(e.args[0])# 自定义登录成功后返回的数据信息result = serializer.validated_dataresult['id'] = serializer.user.idresult['email'] = serializer.user.emailresult['mobile'] = serializer.user.mobileresult['username'] = serializer.user.usernameresult['token'] = result.pop('access')return Response(serializer.validated_data, status=status.HTTP_200_OK)

运行结果:

用户注册功能的实现

import re
from rest_framework import status
from rest_framework.response import Response
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.views import APIView
from .models import User
# Create your views here.
class RegisterView(APIView):def post(self,request):"""注册:接收参数并校验、创建用户 """username = request.data.get('username')password = request.data.get('password')email = request.data.get('email')password_confirmation = request.data.get('password_confirmation')# 检验print(all([username,password,email,password_confirmation]))print([username,password,email,password_confirmation])if not all([username,password,email,password_confirmation]):return Response({'error':'所有参数不能为空'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)# 检验用户是否已存在if User.objects.filter(username=username).exists():return Response({'error':'用户名已存在'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)# check passwordif password !=password_confirmation:return Response({'error':'两次输入的密码不一致'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)if not (6<len(password)<18):return Response({'error':'密码长度需要在6-18位之间'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)# check emailif User.objects.filter(email=email).exists():return Response({'error':'该邮箱已被他人注册'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)if not re.match(r'^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$',email):return Response({'error':'邮箱格式有误'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)# 创建用户obj = User.objects.create_user(username=username,email=email,password=password)res = {'username':username,'id':obj.id,'email':obj.email}return Response(res,status=status.HTTP_201_CREATED)# url 配置
path('register/', RegisterView.as_view(), name='register'),  # 注册

多字段用户登录功能支持

# 规范化格式,创建authentication.py放于common目录下from django.contrib.auth.backends import ModelBackend
from apps.users.models import User
from django.db.models import Q
from rest_framework import serializersclass Authentication(ModelBackend):"""自定义用户登录的认证类,实现多字段登录"""def authenticate(self, request, username=None, password=None, **kwargs):"""支持使用手机号/邮箱/用户名登录"""try:user = User.objects.get(Q(username=username) | Q(mobile=username) | Q(email=username))except:raise serializers.ValidationError({'error':'未找到该用户!'})# check passwordif user.check_password(password):return userraise serializers.ValidationError({'error':'密码错误'})# 配置setting 使用
# 使用自定义的认证类进行身份登录,登录时验证信息
AUTHENTICATION_BACKENDS =['common.authentication.Authentication',
]

注意上述代码使用 User 的导包方式

from apps.users.models import User √

from django.contrib.auth.models import User ×

因当前在setting设置的规范 AUTH_USER_MODEL = 'users.User'

第二行代码可能会导致找不到用户而抛出异常,此时的解决方法

from django.contrib.auth.models import User
from django.contrib.auth import get_user_modelUser= get_user_model()  # 重写获取注册的app模型类

运行结果展示:

刷新 jwt token: 当上述token失效时可以通过刷新refresh得到新的token

要求:检查参数不为空、检验密码账号正确、登录成功返回token,支持多字段登录

# 配置urls文件
from rest_framework_simplejwt.views import TokenRefreshView,TokenVerifyViewurlpatterns = [path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),  # 刷新tokenpath('token/verify/', TokenVerifyView.as_view(), name='token_verify'),  # 检验token
]

 获取用户信息,要求如下

  • 获取用户信息时进行权限检验,需要在请求中添加认证字段
  • 防止越权篡改数据

 

# 定义序列化器
from rest_framework import serializers
from apps.users.models import Userclass UserSerializer(serializers.ModelSerializer):"""用户的模型序列化器"""class Meta:model = Userfields = ['id','username','email','mobile','avatar','last_name']# 定义视图
from .models import User
from .serializers import UserSerializer
from rest_framework.viewsets import GenericViewSet,mixins# Create your views here.
class UserView(GenericViewSet,mixins.RetrieveModelMixin):"""用户相关的操作视图集"""queryset = User.objects.all()serializer_class = UserSerializer# 配置urls
path('users/<int:pk>/',UserView.as_view({'get':'retrieve'}), name='user_get'),  # 检验token

 运行结果展示:

增加权限管理,防止当前用户访问其他用户

from rest_framework import permissions
class UserPermissions(permissions.BasePermission):"""Custom permission to only allow owners of an object to edit it."""def has_object_permission(self, request, view, obj):# 判断是否是管理员if request.user.is_superuser:return True# 判断当前的用户对象和登录的用户对象是否是同一个,防止越权return obj == request.user# 更新配置视图文件
permission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证

更多详细权限配置:4 - Authentication and permissions - Django REST framework

 上传用户头像-

要求:检验参数avatar、文件大小不超过300kb、返回的url可以访问图片,防止用户越权

# 头像文件上传视图
class UserView(GenericViewSet,mixins.RetrieveModelMixin):"""用户相关的操作视图集"""queryset = User.objects.all()serializer_class = UserSerializerpermission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证def upload_avatar(self,request,*args,**kwargs):"""上传头像"""obj= self.get_object()avatar = request.data.get('avatar')if not avatar:return Response({'error':'上传文件不可为空!'},status=status.HTTP_400_BAD_REQUEST)size = avatar.sizeif size >1024*300:return Response({'error': '上传文件大小不可超过300kb!'}, status=status.HTTP_400_BAD_REQUEST)# partial 只对部分字段(上传的字段)进行校验serializer = self.get_serializer(obj,data={'avatar':avatar},partial=True)serializer.is_valid(raise_exception=True)serializer.save()return Response({'url':serializer.data['avatar']})# setting配置
# 文件上传的路径
MEDIA_ROOT = BASE_DIR / 'file/image'
# 文件的url路径
MEDIA_URL = 'file/image/'# 配置url
path('<int:pk>/avatar/upload/',UserView.as_view({'post':'upload_avatar'}), name='avatar_post')

头像文件获取

# 头像文件获取
class FileView(APIView):def get(self,request,name):path  = MEDIA_ROOT / nameif os.path.isfile(path):return FileResponse(open(path,'rb'))return Response({"error":'没有找到该文件!'},status=status.HTTP_400_BAD_REQUEST)# 配置总路由url
re_path(r'file/image/(.+?)/', FileView.as_view()),

文件上传更多知识:文件上传 | Django 文档 | Django

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/263653.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搭建私有Git服务器:GitLab部署详解

引言&#xff1a; 为了方便团队协作和代码管理&#xff0c;许多组织选择搭建自己的私有Git服务器。GitLab是一个集成了Git版本控制、项目管理、代码审查等功能的开源平台&#xff0c;是搭建私有Git服务器的理想选择。 目录 引言&#xff1a; 一、准备工作 在开始部署GitLab之…

Linux之ACL权限chmod命令

一. chmod命令 chmod命令来自英文词组change mode的缩写&#xff0c;其功能是改变文件或目录权限的命令。默认只有文件的所有者和管理员可以设置文件权限&#xff0c;普通用户只能管理自己文件的权限属性。 设置权限时可以使用数字法&#xff0c;亦可使用字母表达式&#xff0…

RisingWave最佳实践-利用Dynamic filters 和 Temporal filters 实现监控告警

心得的体会 刚过了年刚开工&#xff0c;闲暇之余调研了分布式SQL流处理数据库–RisingWave&#xff0c;本人是Flink&#xff08;包括FlinkSQL和Flink DataStream API&#xff09;的资深用户&#xff0c;但接触到RisingWave令我眼前一亮&#xff0c;并且拿我们生产上的监控告警…

Android Gradle 开发与应用 (一) : Gradle基础

1. Gradle是什么 Gradle是一个通用的构建工具&#xff0c;支持诸多主要的 IDE&#xff0c;包括 Android Studio、IntelliJ IDEA、Visual Studio 等 Gradle 的底层实现(核心引擎和框架)其实是用 Java 编写的开发者通常使用 Groovy 或 Kotlin 来编写构建脚本 1.1 那么为什么Gra…

Order By Limit不稳定性

文章目录 前置解决不确定性场景1 Order By索引1.1 背景1.2 不确定性产生原因1.2.1 正常情况下1.2.2 但是 1.3 补充1.4 场景1总结 场景2 Order by id2.1 背景2.2 不会产生不确定性原因1原因2 2.3 推荐使用方式 场景3 filesort3.1 背景3.2 不确定性产生原因3.3 内存排序和磁盘临时…

Jmeter基础(3) 发起一次请求

目录 Jmeter 一次请求添加线程组添加HTTP请求添加监听器 Jmeter 一次请求 用Jmeter进行一次请求的过程&#xff0c;需要几个步骤呢&#xff1f; 1、添加线程组2、添加HTTP请求3、添加监听器&#xff0c;查看结果树 现在就打开jmeter看下如何创建一个请求吧 添加线程组 用来…

【Java程序设计】【C00282】基于Springboot的校园台球厅人员与设备管理系统(有论文)

基于Springboot的校园台球厅人员与设备管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的校园台球厅人员与设备管理系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xf…

【数据结构与算法】(16)基础算法 之哈希表 相关示例 详细代码讲解

目录 3.6 哈希表第一版生成 hashCode思考习题E01. 两数之和-Leetcode 1E02. 无重复字符的最长字串-Leetcode 3E03. 字母异位词分组-Leetcode 49E04. 判断有没有重复元素-Leetcode 217E05. 找出出现一次的数字-Leetcode 136E06. 判断字母异位词-Leetcode 242E07. 第一个不重复字…

前端工程化面试题 | 16.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

vue : 无法加载文件 C:\Program Files\nodejs\node_global\vue.ps1,因为在此系统上禁止运行脚本。

解决方法&#xff1a; 打开PowerShell&#xff0c;在命令框输入set-ExecutionPolicy RemoteSigned 在PowerShell中输入会出现如下图&#xff0c;输入y即可。

数据结构-列表LinkedList

一,链表的简单的认识. 数组,栈,队列是线性数据结构,但都算不上是动态数据结构,底层都是依托静态数组,但是链表是确实真正意义上的动态数组. 为什么要学习链表? 1,链表时最简单的动态数据结构 2,掌握链表有助于学习更复杂的数据结构,例如,二叉树,trie. 3,学习链表有助于更深入…

unity学习(40)——创建(create)角色脚本(panel)——UI

1.点击不同的头像按钮&#xff0c;分别选择职业1和职业2&#xff0c;create脚本中对应的函数。 2.调取inputfield中所输入的角色名&#xff08;限制用户名长度为7字符&#xff09;&#xff0c;但愿逆向的服务器可以查重名&#xff1a; 3.点击头衔&#xff0c;显示选择的职业&a…

Spring Boot 手写starter!!!

原因&#xff1a;为什么要手写starter&#xff1f;&#xff1f;&#xff1f; 原因&#xff1a;简化功能。 实例&#xff1a;以分页为例&#xff1a;写一个starter。 1.首先定义一个PageX注解。 Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) Documented p…

LeetCode 热题 100 | 二叉树(一)

目录 1 基础知识 1.1 先序遍历 1.2 中序遍历 1.3 后序遍历 2 94. 二叉树的中序遍历 3 104. 二叉树的最大深度 4 226. 翻转二叉树 5 101. 对称二叉树 菜鸟做题&#xff0c;语言是 C 1 基础知识 二叉树常见的遍历方式有&#xff1a; 先序遍历中序遍历后序遍历…

RocketMQ-架构与设计

RocketMQ架构与设计 一、简介二、框架概述1.设计特点 三、架构图1.Producer2.Consumer3.NameServer4.BrokerServer 四、基本特性1.消息顺序性1.1 全局顺序1.2 分区顺序 2.消息回溯3.消息重投4.消息重试5.延迟队列&#xff08;定时消息&#xff09;6.重试队列7.死信队列8.消息语…

神经网络系列---感知机(Neuron)

文章目录 感知机(Neuron)感知机(Neuron)的决策函数可以表示为&#xff1a;感知机(Neuron)的学习算法主要包括以下步骤&#xff1a;感知机可以实现逻辑运算中的AND、OR、NOT和异或(XOR)运算。 感知机(Neuron) 感知机(Neuron)是一种简单而有效的二分类算法&#xff0c;用于将输入…

jmeter下载base64加密版pdf文件

一、何为base64加密版pdf文件 如下图所示&#xff0c;接口jmeter执行后&#xff0c;返回一串包含大小写英文字母、数字、、/、的长字符串&#xff0c;直接另存为pdf文件后&#xff0c;文件有大小&#xff0c;但是打不开&#xff1b;另存为doc文件后&#xff0c;打开可以看到和…

Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(二)

文章目录 上一篇效果演示Puppeteer 修改浏览器的默认下载位置控制并发数错误重试并发控制 错误重试源码 上一篇 Puppeteer 使用实战&#xff1a;如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客&#xff08;一&#xff09; 效果演示 上一篇实现了一些基本功能&#xff0c;…

Maxwell安装部署

1 Maxwell输出格式 database&#xff1a;变更数据所属的数据库table&#xff1a;变更数据所属的表type&#xff1a;数据变更类型ts&#xff1a;数据变更发生的时间xid&#xff1a;事务idcommit&#xff1a;事务提交标志&#xff0c;可用于重新组装事务data&#xff1a;对于inse…

uni-app nvue vue3 setup中实现加载webview,解决nvue中获取不到webview实例的问题

注意下面的方法只能在app端使用&#xff0c; let wv plus.webview.create("","custom-webview",{plusrequire:"none", uni-app: none, width: 300,height:400,top:uni.getSystemInfoSync().statusBarHeight44 }) wv.loadURL("https://ww…