一、继承View类[CBV与类结合,需要自定义方法将对象转为json对象]
urls.py[CBV与类结合]
CBV提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实例,
然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用相应的方法来处理request(如get() , post()等)
#[不带参数的请求]UsersResouces,get请求全部用户信息,post添加用户信息,
#[带参数的请求]UsersResource,user/2 get请求id为2的信息,delete删除,put/patch更新信息
urlpatterns = [
path('index', UserView.as_view(), name='index'),
path('modify/<int:id>', UserModifyView.as_view(), name='modify'),
]
views.py[CBV与类结合]
## 定义一个User类
class User:
def __init__(self, id, username, password):
self.id = id
self.username = username
self.password = password
def to_dict(self):#[返回的格式需要时json格式]
return {'id': self.id, 'username': self.username, 'password': self.password}
def __str__(self):
return self.username
user_list = []
id = 0
# CBV与类结合,不需要传参
class UserView(View):
def get(self, request):
if len(user_list) > 0:
data = {'status': 200,'users': user_list}
else:
data = {'status': 200,'msg': "还没有用户"}
return JsonResponse(data)
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
global id
id += 1
if username not in user_list:
user = User(id, username, password)
user_list.append(user.to_dict()) #需要将json格式放在list中返回
data = {'status': 201,'msg': "用户%s添加成功" % username,'users': user_list}
else:
data = {'status': 201,'msg': "用户%s已存在" % username}
return JsonResponse(data)
# put,patch,delete需要传参单独定义一个view类
class UserModifyView(View):
def put(self, request, id):
pass
def patch(self, request, id):
flag = False
for user in user_list:
if id == user['id']:
user['password'] = "111111"
flag = True
break
if flag:
data = {'status': 400,'msg': "用户%s的密码修改成功" % id,'users': user_list}
else:
data = {'status': 400,'msg': "用户%s不存在,修改失败" % id,'users': user_list}
return JsonResponse(data)
def delete(self, request, id):
pass
二、继承View类[CBV与数据库结合,需要自定义方法将对象转为json对象]
urls.py
urlpatterns = [
path('mindex',UserModelView.as_view(),name='mindex'),
path('mmodify/<int:id>',UserModelModifyView.as_view(),name='mmodify')
]
models.py
class UserModel(models.Model):
username=models.CharField(max_length=100)
password=models.CharField(max_length=100)
def to_dict(self):#将模型转为json对象
return {'id':self.id,'username':self.username,'password':self.password}
def __str__(self):
return self.username
class Meta:
db_table="user"
views[CBV和数据库结合]
# CBV和数据库结合,不需要传参
class UserModelView(View):
def get(self, request):
users = UserModel.objects.all()
user_list = []
for user in users:
user_list.append(user.to_dict())
if len(user_list) > 0:
data = {'status': 200,'msg': '获取全部用户','users': user_list}
else:
data = {'status': 200,'msg': '还没有用户',}
return JsonResponse(data)
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
userisexist = UserModel.objects.filter(username=username)
if userisexist:
data = {'status': 400,'msg': '用户%s已存在' % username}
else:
user = UserModel.objects.create(username=username, password=password)
if user:
data = {'status': 201,'msg': '用户%s添加成功' % username,
'user': user.to_dict()}
else:
data = {'status': 400,'msg': '用户%s添加失败' % username}
return JsonResponse(data)
# put,patch,delete需要传参单独定义一个view类
class UserModelModifyView(View):
def get(self, request, id):
user = UserModel.objects.filter(id=id).first()
if user:
data = {'status': 200,'msg': 'id%s用户获取成功' % id,'user': user.to_dict()}
else:
data = {'status': 201,'msg': 'id%s用户不存在' % id}
return JsonResponse(data)
def patch(self, request, id):
user = UserModel.objects.filter(id=id).first()
if user:
user.password = "11111"
user.save()
data = {'status': 201,'msg': 'id%s的用户密码修改成功' % id,
'user': user.to_dict()
}
else:
data = {
'status': 400,'msg': 'id%s的用户不存在,修改失败' % id
}
return JsonResponse(data)
def delete(self, request, id):
user = UserModel.objects.filter(id=id).first()
if user:
user.delete()
data = {'status': 204,'msg': 'id%s的用户删除成功' % id}
else:
data = {'status': 400,'msg': 'id%s的用户不存在,删除失败' % id}
return JsonResponse(data)
三、序列化与反序列化[继承Serializer,APIView]
解决模型需要转为json返回前端,前端数据处理之后放进数据库的问题,引入序列化与反序列化
为了方便拿到前端传过来的数据,引入APIView,使用request.data,什么类型数据都能拿到
APIView和View
# REST framework提供了一个APIView类,它是Django的View类的子类。
APIView比View更为强高级之处就是APIView的dispatch()比View的dispatch()高级
APIView与View的不同之处
传入到视图方法中的是Request对象,而不是Django的HttpRequest对象
视图方法可以返回Response对象,会为响应数据处理(render)为符合前端要求的格式
任何APIException异常都会被捕获到,并且处理成合适的响应信息
在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
Django之DRF-一个请求的前世今生:https://blog.youkuaiyun.com/weixin_47454485/article/details/107505904
Django之DRF-APIView:
https://blog.youkuaiyun.com/weixin_47454485/article/details/107461486
Django之DRF-APIView、View源码对比:
https://www.pianshen.com/article/30771764378/
1.概念
为优化 自定义方法将对象转为json 的过程,引入序列化与反序列化
2.使用步骤
作用:提高RestAPI接口开发的效率
关键功能:
序列化器:序列化和反序列化
类视图,MiXin扩展类:简化视图代码的编写
文档地址:https://www.django-rest-framework.org/
1.pip install djangorestframework
2.将‘rest_framework’添加在installed_apps中
3.在需要的app中新建serializers.py文件
3.实例
urls.py
urlpatterns = [
path('index', GameResources.as_view(), name='index'),
path('aindex', GameResoucesAPI.as_view(), name='aindex'),
path('amodify/<int:id>',GameResourcesModifyAPI.as_view(),name='amodify')
]
models.py
class Game(models.Model):
name=models.CharField(max_length=100)
role=models.CharField(max_length=100)
company=models.CharField(max_length=100)
publish_date=models.DateField(auto_now=True)
def __str__(self):
return self.name
class Meta:
db_table="game"
serialziers.py[新建serializers.py文件,字段和model字段一样]
#继承Serializer
from rest_framework import serialziers
class GameSerializer(Serializer):
name = serializers.CharField(max_length=100)
role = serializers.CharField(max_length=100)
company = serializers.CharField(max_length=100)
publish_date = serializers.DateField()
#继承Serializer,反序列化需要手动实现create,update方法
#传参根据是否传递了instance自动区分调用create还是update
def create(self, validated_data):
return Game.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.role = validated_data.get('role', instance.role)
instance.company = validated_data.get('company', instance.company)
instance.save()
return instance
3.1序列化方法及实例:序列化对象(将模型实例或者结果集转成json的格式)
得到模型实例-->转为json-->结果gameserlizer.data
单个:
game=Game.objects.create(name=name,role=role,company=company)
gameserlizer=GameSerializer(game)
多个:
games=Game.objects.all()
gamesSerializer=GameSerializer(games,many=True)
views.py
class GameResources(View):
def get(self,request):
games=Game.objects.all()
gamesSerializer=GameSerializer(games,many=True)
if games.count()>0:
data={'status':200,'count':games.count(),
'games':gamesSerializer.data}
else:
data = {'status': 200,'count': games.count(),'msg':'还没有数据'}
return JsonResponse(data)
def post(self,request):
name=request.POST.get('name')
role=request.POST.get('role')
company=request.POST.get('company')
game=Game.objects.create(name=name,role=role,company=company)
gameserlizer=GameSerializer(game)
if game:
data={'status':201,'msg':'游戏%s添加成功'%name,
'game':gameserlizer.data}
else:
data = {'status': 400,'msg': '游戏%s添加失败' % name}
return JsonResponse(data)
4.反序列化方法及实例
数据校验
1.使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
2.在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
3.验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。
4.验证成功,可以通过序列化器对象的validated_data属性获取数据。
5.在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为
数据入库:
1.数据保存 save方法
2.序列化器中传入两个参数,即数据的更新操作,
继承自Serializer的类,需要手动实现create,update方法
views.py[需要通过request.data获取传过来的数据,继承APIView]
class GameResoucesAPI(APIView):
# 此时的request是rest_framework的request对象
def get(self,request):
games=Game.objects.all()
print(request.GET.get('username')) # 获取get请求提交的参数
serializergames=GameSerializer(games,many=True)
data={'count':games.count(),'games':serializergames.data}
return JsonResponse(data)
def post(self,request):
print(request.POST.get('username')) # 无法获取POST请求提交的参数使用此方式
#反序列化,拿数据通过request.data
serializer=GameSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
#验证成功,可以通过序列化器对象的validated_data属性获取数据。
print("%%",serializer.validated_data)
return JsonResponse({'status':'Success'})
else:
return JsonResponse({'status': 'fail'})
class GameResourcesModifyAPI(APIView):
def get(self,request,id):
game=Game.objects.get(pk=id)
serializer=GameSerializer(game)
return JsonResponse(serializer.data)
def patch(self,request,id):
game=Game.objects.get(pk=id)
#序列化器中传入两个参数,即数据的更新操作,部分更新partial=True
serializer=GameSerializer(game,data=request.data,partial=True)
if serializer.is_valid():
serializer.save()
return JsonResponse({'msg':'修改成功'})
else:
return JsonResponse({'msg': '修改失败'})
def delete(self,request,id):
game=Game.objects.get(pk=id)
game.delete()
return JsonResponse({'msg': '删除成功'})
四、序列化与反序列化[继承ModelSerializer,APIView]
为了避免继承serializer需要自定义字段,手动重写create,update方法的繁琐,
引入继承ModelSerializer
#学生和班级两个模型,班级->学生(一对多)
class Classes(models.Model):
classname=models.CharField(max_length=50,verbose_name="班级")
school=models.CharField(max_length=50,verbose_name="学校")
admission_date=models.DateField(auto_now=True,verbose_name="入学时间")
def __str__(self):
return self.classname
class Meta:
db_table="classes"
class Students(models.Model):
name=models.CharField(max_length=50,verbose_name="学生姓名")
gender=models.CharField(max_length=30,choices=(("boy","boy"),('girl','girl')),default='boy',verbose_name="性别")
sclass=models.ForeignKey(to=Classes,on_delete=models.CASCADE,verbose_name="学生班级")
def __str__(self):
return self.name
class Meta:
db_table="students"
serializers.py
class StudentsSerializer(serializers.ModelSerializer):
class Meta:
model = Students
fields = "__all__"
class ClassesSerializer(serializers.ModelSerializer):
#详细字段用法见DRF4(Django之serializer-主从表数据关联查询)
# students_set=serializers.StringRelatedField(read_only=True,many=True)
# students_set=serializers.PrimaryKeyRelatedField(read_only=True,many=True)
students_set = serializers.HyperlinkedRelatedField(read_only=True, many=True, view_name='classes:mstudent',lookup_field='id')
class Meta:
model = Classes
fields = "__all__"
urls.py
urlpatterns=[
#get 和 post学生信息
path('student',StudentsResources.as_view(),name='student'),
#对单个学生信息操作
path('mstudent/<int:id>',StudentResource.as_view(),name='mstudent'),
#班级
path('classess',ClassesResources.as_view(),name="classess")
]
views.py
class StudentsResources(APIView):
def get(self, request):
students = Students.objects.all()
serializer = StudentsSerializer(students, many=True)
if students.count() > 0:
data = {'status': 200,'count': students.count(),
'students': serializer.data}
return JsonResponse(data)
else:
data = {'status': 200,'count': students.count(),
'msg': '还没有学生信息'}
return JsonResponse(data)
def post(self, request):
serializer = StudentsSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse({'status': 201,'msg': "学生信息添加成功"})
return JsonResponse({'status': 400,'msg': "学生信息添加失败"})
class StudentResource(APIView):
def get(self, request, id):
student = Students.objects.get(pk=id)
serializer = StudentsSerializer(student)
return JsonResponse(serializer.data)
def patch(self, request, id):
student = Students.objects.filter(id=id).first()
serializer = StudentsSerializer(student, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return JsonResponse({'msg': '修改成功'})
return JsonResponse({'msg': '修改成功'})
def delete(self, request, id):
student = Students.objects.filter(id=id).first()
if student:
student.delete()
return JsonResponse({'msg': '删除成功'})
return JsonResponse({'msg': '删除失败'})
class ClassesResources(APIView):
def get(self, request):
classes = Classes.objects.all()
#使用HyperlinkedRelatedField需要添加context={'request': request}
serializer = ClassesSerializer(classes, many=True, context={'request': request})
data = {'status': 200,'data': serializer.data}
return JsonResponse(data)
五、继承ListCreateAPIView和RetrieveUpdateDestoryAPIView
每次写不同表的数据的接口,总是需要重复的写这些方法,get,post,delete,put
有没有更好的封装,连这些方法都不用写了呢???
ListCreateAPIView和RetrieveUpdateDestoryAPIView出场
urls.py
urlpatterns=[
path('users',UsersResouces.as_view(),name="users"),
path('users/<int:pk>',UsersResource.as_view(),name='users-detail'),
]
views.py
#写两个类视图,一个带参数的,一个不带参数的
#queryset 指明视图需要的数据(model查询数据)
#serializer_class 指明视图使用的序列化器
class UsersResouces(ListCreateAPIView):
queryset = Users.objects.all()
serializer_class = UsersSerializer
class UsersResource(RetrieveUpdateDestroyAPIView):
queryset = Users.objects.all()
serializer_class = UsersSerializer
六、ModelViewSet
上面还是有冗余代码,并且需要两个路由
https://www.jianshu.com/p/c3a439f0d5b8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
router=DefaultRouter()
router.register('user',UserResourceOther)
app_name="users"
urlpatterns=[
path('',include(router.urls))
]
#集合了get,post,retrieve,delete,put所有的方法
class UserResourceOther(ModelViewSet):
queryset = Users.objects.all()
serializer_class = UsersSerializer
七、基于mixins来封装的视图(MIxin+GenericViewSet)
使用类视图需要写两个类,一个用于没有参数,另一个用于传递参数
使用视图集可以将所有的方法写在一个里面,提高开发效率,并且用到哪个导入哪个
ListModelMixin,CreateModelMixin,Retrieve,Update,Destroy 结合GenericViewSet使用
数据库操作之前的应该重写CreateModelMixin的create方法
比如拿到前端传过来的密码应该加密后存放到数据库中
路由:
router.register('banners', BannerViewSet, basename="banners")
# 首页轮播图
class BannerViewSet(ListModelMixin, GenericViewSet):
queryset = Banner.objects.all()
serializer_class = BannerSerializer
# 首页轮播图序列化
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Banner
fields = "__all__"