一、课程回顾
1.cookie 与 session
cookie:会化跟踪技术,HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。
cookie是保存在每一个浏览器(客户端)上的一个(key,values)结构的文件。
key1:客户端上具体某一个浏览器;
key2:每一个浏览器都维持着一个类似于字典{}的结构;
key3:浏览器会针对每一个cookie
注:redirect(重定向),第一次get请求,返回页面;第二次发登录请求,点击submit按钮,浏览器新发一个请求,回到客户端(通过状态码:3开头)
- Cookie大小上限为4KB;
- 一个服务器最多在客户端浏览器上保存20个Cookie;
- 一个浏览器最多保存300个Cookie;
语法:
写cookie:
obj=HttpResponse()
obj.set_cookie("key","value",10)
读cookie:
request.COOKIES("key")
session:将信息保存在服务器
写session:
request.session["user_id"]=1
"""
1.生成随机字符串:12344546fgdfgd;
2.在django-session表中创建一条记录
session-key session-data
2344546fgdfgd {"user_id":1,"name","alex"}
3.res.set_cookie("session_id","2344546fgdfgd") --->建立联系的钥匙
"""
读session:
user_id=request.session["user_id"]
"""
1.random_str=request.COOKIES.get("session_id");
2.在django-session表中查询记录
3.django-session.objects.filter(session-key=random_str).first().session-data.get() -->需要序列化转换(json[loads,dumps])
"""
二、CBV,--》序列化组件
1.前后端分离:后端仅返回前端所需的数据,不再渲染HTML页面,不再控制前端的效果。至于前端用户看到什么效果,从后端请求的数据如何加载到前端中,都由前端自己决定,网页有网页的处理方式,App有App的处理方式,但无论哪种前端,所需的数据基本相同,后端仅需开发一套逻辑对外提供数据即可。
在前后端分离的应用模式中 ,前端与后端的耦合度相对较低。
在前后端分离的应用模式中,我们通常将后端开发的每个视图都称为一个接口,或者API,前端通过访问接口来对数据进行增删改查。
2.CBV 与 FBV
FBV: function based view
CBV: class based view
例子:
path('index/', views.IndexView.as_view()),
path('index/', View.view()), --->class IndexView(View)
用户发送/index/请求,执行view(request)
def view(request, *args, **kwargs):
return self.dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
写代码:1.写注释,规范;
看源码:1.看不懂,先过;2.找自己关注的重点;3.有迹可循,先找类对象;
三、DRF:Django rest framework
1.RESTful
a. REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
b.REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
c.REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
d.所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
e.对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
restful:
http://127.0.0.1:8000/books/ ---get(查)--->post(添加)------------->
http://127.0.0.1:8000/books/1 ---put/patch(更新数据)--->---delete(删除)--->[URL不允许出现动词,只有名词]
method
- GET :从服务器取出资源(一项或多项)
- POST :在服务器新建一个资源
- PUT :在服务器更新资源(客户端提供改变后的完整资源)
- PATCH :在服务器更新资源(客户端提供改变的属性)
- DELETE :从服务器删除资源
状态码:
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
2.rest framework项目例子(在数据库中添加数据,切记,一定要先添加无关键字和外键的表,不能先添加有关键字的表-----》很重要):
#序列化器1
models:
from django.db import models
# Create your models here.
class Book(models.Model):
title=models.CharField(max_length=32)
price=models.IntegerField()
pub_date=models.DateField()
publish=models.ForeignKey("Publish", on_delete=models.CASCADE)
authors=models.ManyToManyField("Author")
def __str__(self):
return self.title
class Publish(models.Model):
name=models.CharField(max_length=32)
email=models.EmailField()
def __str__(self):
return self.name
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
def __str__(self):
return self.name
views:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from django.shortcuts import HttpResponse
from django.core import serializers
from rest_framework import serializers
class BookSerializers(serializers.Serializer):
title=serializers.CharField(max_length=32)
price=serializers.IntegerField()
pub_date=serializers.DateField()
#一对多
publish=serializers.CharField(source="publish.name")
#authors=serializers.CharField(source="authors.all")
#多对多
authors=serializers.SerializerMethodField()
def get_authors(self,obj):
temp=[]
for author in obj.authors.all():
temp.append(author.name)
return temp
class BookViewSet(APIView):
GET请求
def get(self, request, *args, **kwargs):
book_list = models.Book.objects.all()
print(book_list, "book_list")
# # 序列化方式1:
# from django.forms.models import model_to_dict
import json
# data=[]
# for obj in book_list:
# data.append(model_to_dict(obj))
# print(data)
# return HttpResponse("ok")
#
# 序列化方式2:[序列化2不需要添加BookSerializers,且引用的是:django.core.serializers, 其他的serializers要注释,不然无法找到:serializers.serialize, rest_framework下只有serializers]
# data = serializers.serialize("json", book_list)
# return HttpResponse(data)
# 序列化方式3[使用的是: from rest_framework import serializers 中+ BookSerializers(serializers.Serializer)序列化器 ]:
bs=BookSerializers(book_list, many=True)
print(bs.data)
# return HttpResponse("DEFGET is ok")
return Response(bs.data)
POST请求
def post(self,request,*args,**kwargs):
print("POST", request.POST)
print("data", request.data)
#2。添加数据到数据库
bs = BookSerializers(data=request.data, many=False)
#校验数据,校验成功,就保存,失败就返回bs.errors
if bs.is_valid():
pass
else:
return Response(bs.errors)
return HttpResponse("DEFPOST is ok")
#序列化器2(序列化组件)
class BookSerializers(serializers.ModelSerializer):
# 一对多
publish = serializers.CharField(source="publish.email")
# authors=serializers.CharField(source="authors.all")
# 多对多
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
temp = []
for author in obj.authors.all():
temp.append(author.name)
return temp
class Meta:
model = Book
fields = "__all__"
# # fields = ["title", "price"]
# exclude = ["price"]
PUT请求
urls:
#修改+删除必须加ID
re_path('books/(d+)', views.SBookViewSet.as_view()),
【re_path和path的作用都是一样的。只不过re_path
是在写url的时候可以用正则表达式,功能更加强大。】
views:
class SBookViewSet(APIView):
#put与 delete和get与post分开,是因为put(或delete) 必须要传ID进去,新的类要传2哥参数,而BookView只需要传一个参数,所以访问的时候无法确定在哪一个类中,因此需要通过另起一个类来区分
def put(self, request, id, *args, **kwargs):
#1.获取数据
update_data = request.data
#2.更新数据库
update_book = Book.objects.filter(pk = id).first()
bs = BookSerializers(instance=update_book, data = update_data)
if bs.is_valid():
#单条记录
bs.save()
return Response(bs.data)
#3.返回更新后的数据
return Response(bs.errors)
postman传入json数据格式
{
"authors": [2,3],
"title": "C---",
"price": 119,
"pub_date": "2015-12-15",
"publish": 1
}
delete请求
def delete(self, request, id, *args, **kwargs):
del_book= Book.objects.filter(pk=id).first()
del_book.delete()
return Response("")
四、视图三部曲(mixin编写视图)
publish(mixin)
urls:
path('publish/', views.PublishViewSet.as_view()),
#必须添加有名分组
re_path('publish/(?P<pk>d+)', views.SPublishViewSet.as_view()),
views:
#作者序列化组件
class AuthorSerializers(serializers.ModelSerializer):
class Meta:
model = Author
fields = "__all__"
from rest_framework import mixins
from rest_framework import generics
#多重继承
class PublishViewSet(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
#queryset被GenericAPIView封装在的get_queryset的函数下(源码)
queryset = Publish.objects.all()
#序列化器
serializer_class = PublishSerializers
def get(self, request, *args, **kwargs):
#list封装在ListModelMixin这个方法类
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class SPublishViewSet(mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
mixins.UpdateModelMixin,
generics.GenericAPIView):
queryset = Publish.objects.all()
# 序列化器
serializer_class = PublishSerializers
#这里与不再使用list方法
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
#最终版
urls:
#最终版本封装
path('author/', views.AuthorViewSet.as_view({"get" : "list", "post" : "create"})),
re_path('author/(?P<pk>d+)', views.AuthorViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
})),
views:
from rest_framework import viewsets
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializers