Django之DRF-CBV(基于类的视图)
简介
- FBV(function base views) 基于函数的视图,就是在视图里使用函数处理请求。
- CBV(class base views) 基于类的视图,就是在视图里使用类处理请求。
-
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from django.http import HttpResponse
from django.views import View
from django.shortcuts import render
from user.models import User
# Create your views here.
class RegisterView(View):
def get(self, request):
return render(request, 'register.html')
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
repassword = request.POST.get('repassword')
if password == repassword:
if user := User.objects.create(username=username, password=password):
return HttpResponse(f'{user}注册成功!')
return HttpResponse('注册失败') -
register.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<h1>注册</h1>
<form action="{% url 'register' %}" method="post">
{% csrf_token %}
<p><input type="text" name="username" placeholder="username"></p>
<p><input type="password" name="password" placeholder="password"></p>
<p><input type="password" name="repassword" placeholder="password"></p>
<p><input type="submit" value="注册"></p>
</form>
</body>
</html> -
urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25"""RESTful URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from user.views import RegisterView
urlpatterns = [
path('admin/', admin.site.urls),
path('register', RegisterView.as_view(), name='register')
]
原生实现(View)
-
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from django.http import JsonResponse
from django.views import View
from django.shortcuts import render
from user.models import User
# Create your views here.
class UserView(View):
def get(self, request, uid):
user = User.objects.get(pk=uid)
return JsonResponse({'status': 200, 'user': user.to_dict()})
def post(self, request, uid):
username = request.POST.get('username')
password = request.POST.get('password')
repassword = request.POST.get('repassword')
if password == repassword:
if User.objects.create(username=username, password=password):
return JsonResponse({'status': 200, 'msg': '注册成功'})
return JsonResponse({'status': 200, 'msg': '注册失败'}) -
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=20, unique=True, verbose_name='用户名')
password = models.CharField(max_length=20, verbose_name='密码')
class Meta:
db_table = 'user'
verbose_name = '用户表'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
# 手动序列化
def to_dict(self):
return {'id': self.id, 'username': self.username, 'password': self.password} -
urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25"""RESTful URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from user.views import RegisterView, UserView
urlpatterns = [
path('admin/', admin.site.urls),
path('user/<int:uid>', UserView.as_view(), name='user')
]
序列化
-
简介
- 序列化:对象
--->
IO中传输的格式 - 反序列化:IO中传输的格式
--->
对象
- 序列化:对象
-
注意事项
- 如果想使用序列化和APIView,必须安装:
1
pip install djangorestframework
- 然后将
rest_framework
添加到settings.py
中的INSTALLED_APPS
里,如下:1
2
3
4
5INSTALLED_APPS = [
...
'user.apps.UserConfig',
'rest_framework',
]
- 如果想使用序列化和APIView,必须安装:
-
创建模型(
models.py
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=20, unique=True)
password = models.CharField(max_length=128)
phone = models.CharField(max_length=11)
add_time = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'user'
def __str__(self):
return self.username -
原生序列化
-
在应用目录下创建名为
serializers.py
文件1
2
3
4
5
6
7
8
9
10
11from rest_framework import serializers
from user.models import User
class UserSerializer(serializers.Serializer):
# 定义需要序列化的字段
id = serializers.IntegerField(read_only=True)
username = serializers.CharField(max_length=20, min_length=5, required=True)
password = serializers.CharField(max_length=128, required=True)
phone = serializers.CharField(max_length=11, min_length=11) -
使用序列化类:views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27from django.contrib.auth.hashers import make_password
from django.shortcuts import render
from rest_framework.views import APIView
from django.http import JsonResponse
from user.serializers import UserSerializer
from user.models import User
# Create your views here.
class UserViews(APIView):
def get(self, request):
pass
def post(self, request):
# 获取POST中的值
username = request.POST.get('username')
password = request.POST.get('password')
phone = request.POST.get('phone')
password = make_password(password)
# 构建对象
user = User.objects.create(username=username, password=password, phone=phone)
# 将对象传递给UserSerializer
us = UserSerializer(user)
# 获取序列化后的数据:us.data
# print(us.data)
return JsonResponse({'status': 200, 'user': us.data})
-
-
使用ModelSerializers序列化
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class UserSerializer1(serializers.ModelSerializer):
repassword = serializers.CharField(max_length=128, write_only=True)
class Meta:
model = User
fields = ['id', 'username', 'password', 'phone', 'repassword']
def validate(self, attrs): # attrs 就是一个提交数据的字典形式
if attrs['password'] != attrs['repassword']:
attrs['flag'] = False
return attrs
def create(self, validated_data):
username = validated_data['username']
password = validated_data['password']
phone = validated_data['phone']
# 密码加密
password = make_password(password)
user = User.objects.create(username=username, password=password, phone=phone)
return user-
定制校验
-
定制具体字段的校验
1
2
3
4
5
6
7
8class UserSerializer1(serializers.ModelSerializer):
......
def validate_email(self, mail):
if re.match(r'', email):
return email
else:
raise serializers.ValidationError('邮箱错误') -
定制全局校验
1
2
3
4
5
6
7class UserSerializer1(serializers.ModelSerializer):
......
def validate(self, attrs): # attrs 就是一个提交数据的字典形式
if attrs['password'] != attrs['repassword']:
attrs['flag'] = False
return attrs
-
-
定制create方法:重写父类的create方法
1
2
3
4
5
6
7
8
9
10
11
12
13class UserSerializer1(serializers.ModelSerializer):
......
def create(self, validated_data):
username = validated_data['username']
password = validated_data['password']
phone = validated_data['phone']
# 密码加密
password = make_password(password)
user = User.objects.create(username=username, password=password, phone=phone)
return user -
ModelSerializer 之 read_only 和 write_only
- write_only
- 某个字段不属于指定model,它是write_only,需要用户传进来,但我们不能对它进行
save()
,因为ModelSerializer是基于Model,这个字段在Model中没有对应,这个时候,我们需要重写validate()
方法! - 就是用户post过来的数据,后台服务器处理后不会再经过序列化后返回给客户端;最常见的就是我们在使用手机注册的验证码和填写的密码。
- 某个字段不属于指定model,它是write_only,需要用户传进来,但我们不能对它进行
- read_only
- 某个字段属于指定model,它是read_only,表示不允许用户自己上传,只能用于api的输出。
- 如果某个字段设置了
read_only=True
,那么就不需要进行数据验证,只会在返回时,将这个字段序列化后返回。 - 举个简单的例子:在用户进行购物的时候,用户post订单时,肯定会产生一个订单号,而这个订单号应该由后台逻辑完成,而不应该由用户post过来,如果不设置
read_only=True
,那么验证的时候就会报错。 - 再例如,我们在网上购物时,支付时通常会产生支付状态,交易号、订单号、支付时间等字段,这些字段都应该设置为read_only=True,即这些字段都应该由后台产生然后返回给客户端。
- write_only
-
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from django.http import JsonResponse
from rest_framework.views import APIView
from user.serializers import UserSerializer1
class UserViews1(APIView):
def get(self, request):
pass
def post(self, request):
# 只有在APIView中才能使用request.data data = JSONParser().parse(request)
us = UserSerializer1(data=request.data)
if us.is_valid(): # 验证
us.save() # 保存
return JsonResponse({'status': 200, 'user': us.data})
-
-
关系模型序列化
-
models.py(一对多)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27from django.db import models
# Create your models here.
# 一
class UserType(models.Model):
name = models.CharField(max_length=20, unique=True)
add_time = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'user_type'
# 多
class User(models.Model):
username = models.CharField(max_length=20, unique=True)
password = models.CharField(max_length=128)
phone = models.CharField(max_length=11)
add_time = models.DateTimeField(auto_now=True)
usertype = models.ForeignKey(to=UserType, on_delete=models.CASCADE, related_name='users', null=True)
class Meta:
db_table = 'user'
def __str__(self):
return self.username -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from rest_framework import serializers
from user.models import UserType
class UserTypeSerializer(serializers.ModelSerializer):
# 此类型下的多个用户,名称必须要与models中的外键related_name保持一致
# users = serializers.StringRelatedField(many=True) # 名称展示
users = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 主键展示
class Meta:
model = UserType
# 自定义的字段需要添加到fields中:“users”
fields = ['id', 'name', 'add_time', 'users'] -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from django.http import JsonResponse
from rest_framework.views import APIView
from user.serializers import UserTypeSerializer
from user.models import UserType
# Create your views here.
class UserTypeView(APIView):
def get(self, request):
usertypes = UserType.objects.all()
# 只要序列化的是多的内容则必须添加many=True
serializer = UserTypeSerializer(usertypes, many=True)
data = {
'status': 200,
'types': serializer.data
}
return JsonResponse(data)
-
反序列化
1 | # 序列化 |
Generic views
-
1
2
3
4
5
6
7
8
9
10from rest_framework import serializers
from user.models import User
class SingleUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password', 'phone', 'usertype'] -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from user.models import User
from user.serializers import SingleUserSerializer
class UserResource(ListCreateAPIView):
# 操作的模型
queryset = User.objects.all()
# 此模型对应的序列化类
serializer_class = SingleUserSerializer
class UserResource1(RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = SingleUserSerializer -
1
2
3
4
5
6
7
8
9
10
11from django.urls import path, include
from user.views import UserResource, UserResource1
app_name = 'user'
urlpatterns = [
path('single', UserResource.as_view(), name='single'),
path('single1/<int:pk>', UserResource1.as_view(), name='single1'),
]
ViewSets
-
1
2
3
4
5
6
7
8
9
10from rest_framework.viewsets import ModelViewSet
from user.models import User
from user.serializers import SingleUserSerializer
class UserResource2(ModelViewSet):
queryset = User.objects.all()
serializer_class = SingleUserSerializer -
1
2
3
4
5
6
7
8
9
10
11
12
13
14from django.urls import path, include
from rest_framework.routers import DefaultRouter
from user.views import UserResource2
app_name = 'user'
router = DefaultRouter()
router.register(r'single', UserResource2)
urlpatterns = [
path('', include(router.urls))
]