一、实现前后端分离,前后端数据交互均已json字符串形式
路由模式,FBV. ==> url(r'^books/', views.books),
1)使用原生的json模型
# 请求 http://127.0.0.1:8000/books/ # [{"name": "python", "price": 20}, {"name": "linux", "price": 30}] import json def books(request): ll = [{'name':'python','price':20}, {'name':'linux','price':30}] return HttpResponse(json.dumps(ll))
2)使用JsonResponse。默认safe=True
from django.http import JsonResponse def books(request): ll = [{'name':'python','price':20}, {'name':'linux','price':30}] return JsonResponse(ll,safe=False)
注意在返回数据时,如果是列表类型需要加上fafe=False,其他则不用
3)在传输json数据时,如果传输中文会出现乱码的情况。需要加参数 ensure_ascii=False
import json dic = {'name':'你好'} print(json.dumps(dic,ensure_ascii=False))
4)在JsonResponse中使用需要加参数。json_dumps_params={'ensure_ascii':False}
from django.http import JsonResponse def books(request): ll = [{'name':'python开心','price':20}, {'name':'linux','price':30}] return JsonResponse(ll,safe=False,json_dumps_params={'ensure_ascii':False})
二、使用djangorestframework,基于drf写resful的接口,写django框架以CBV模式
1)pip安装
pip install djangorestframework -i http://pypi.douban.com/simple
2) 原生的CBV模式。执行过程,as_view() ==>dispatch ==>响应到具体的函数
url的写法。url(r'^books/', views.Book.as_view()。 类+as_view
from django.views import View class Book(View): def get(self,resquest): return HttpResponse('get') def post(self,resquest): return HttpResponse('post')
可根据请求模式自动判断该执行类的哪个方法
会识别到方法是否在这里面 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
3)使用psotman工具模拟发生请求
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/', views.Book.as_view()), ]
FBV模式视图函数
from rest_framework.views import APIView
class Book(APIView):
def get(self,request):
print(request.method) # GET
print(request._request.method) # GET
return HttpResponse('get')
def post(self,request):
print(request.method)
print(request._request.method)
print(request.POST) # 如果传json格式,这里面没有
print(request.data)
return HttpResponse('post')
传json格式
三、restful的序列化组件
先生成数据库
from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField(auto_now_add=True) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') def test(self): return 'ttttttt' def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name
1)第一种,自己写序列化组件
url(r'^books/', views.Book.as_view())
from rest_framework.views import APIView from app01 import models from django.http import JsonResponse class Book(APIView): def get(self, request): response={'status':100,'msg':None} # restful接口 books = models.Book.objects.all() # 第一种常用写法 # ll = [] # for book in books: # ll.append({'name':book.name,'price':book.price}.....) # 第二种 列表推导式 ll = [ {'name':book.name,'price':book.price} for book in books ] response['msg']='查询成功' response['data']=ll # 把查询到的数据列表赋予返回的字典 return JsonResponse(response,safe=False) def post(self, request): return HttpResponse('post')
2)第二种,使用Django的序列化组件
from rest_framework.views import APIView from app01 import models from django.core import serializers # django的序列号组件 class Book(APIView): def get(self, request): books = models.Book.objects.all() ret = serializers.serialize("json",books) return HttpResponse(ret) def post(self, request): return HttpResponse('post')
3)使用drf定制序列化组件
3.1)为了避免代码杂乱,序列号组件写在外部
查看models模型库
class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField(auto_now_add=True) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') def test(self): return 'ttttttt' def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name
引入:from rest_framework import serializers
from rest_framework import serializers class BookSer(serializers.Serializer): nid = serializers.IntegerField() name = serializers.CharField() price = serializers.CharField() # publish_date=serializers.DateField() publish_date = serializers.CharField() publish = serializers.CharField()
视图views写法
from rest_framework.views import APIView from app01 import models from app01 import myserial from django.http import JsonResponse class Book(APIView): def get(self, request): books = models.Book.objects.all() ret = myserial.BookSer(books,many=True) # many=True 序列化多条数据 return JsonResponse(ret.data,safe=False) # data 序列化的字典方法 def post(self, request): return HttpResponse('post')
备注:使用sqlite时,日期序列化出来为null,使用mysql则不会
3.2)增加查询信息
from rest_framework.views import APIView from app01 import models from app01 import myserial from django.http import JsonResponse class MyResponse(): def __init__(self): self.status=100 self.msg=None @property def get_dic(self): return self.__dict__ class Book(APIView): def get(self, request): response = MyResponse() books = models.Book.objects.all() ret = myserial.BookSer(books,many=True) # many=True 序列化多条数据 response.msg = "查询成功" response.data=ret.data return JsonResponse(response.get_dic,safe=False) # data 序列化的字典方法 def post(self, request): return HttpResponse('post')
3.3)如果要想查询到publish指向邮箱
publish = serializers.CharField(source='publish.email')
from rest_framework import serializers class BookSer(serializers.Serializer): nid = serializers.IntegerField() name = serializers.CharField() price = serializers.CharField() # publish_date=serializers.DateField() publish_date = serializers.CharField() publish = serializers.CharField(source='publish.email')
3.4)定制序列号组件时,如果让左边的名字随便定义
from rest_framework import serializers class BookSer(serializers.Serializer): nid = serializers.IntegerField() xxx = serializers.CharField(source='name') price = serializers.CharField() # publish_date=serializers.DateField() publish_date = serializers.CharField() publish = serializers.CharField(source='publish.email')
3.5)利用source调用models里面的方法
class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField(auto_now_add=True) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') def test(self): return 'ttttttt' def __str__(self): return self.name
调用Book类的test方法
from rest_framework import serializers class BookSer(serializers.Serializer): nid = serializers.IntegerField() xxx = serializers.CharField(source='name') price = serializers.CharField() # publish_date=serializers.DateField() publish_date = serializers.CharField() publish = serializers.CharField(source='publish.email') yyy = serializers.CharField(source='test')
3.6)查询多对多,有多个值时
from rest_framework import serializers class BookSer(serializers.Serializer): # 下面是查询多个作者 # authors=serializers.CharField(source='authors.all') # 如果查询多个作者,是查询为query的对象 # SerializerMethodField,可以写一个方法,方法返回值,会赋值给authers authors=serializers.SerializerMethodField() def get_authors(self,obj): # obj 当前book对象 authors=obj.authors.all() #ll = [ author.name for author in authors ] ll = [ {'name':author.name,'age':author.age} for author in authors ] return ll
3.7)查询多个值的另一种方法,再加一个类方法
from rest_framework import serializers class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() class BookSer(serializers.Serializer): aa=serializers.SerializerMethodField() def get_aa(self,obj): authors=obj.authors.all() ser=AuthorSer(authors,many=True) return ser.data
3.8)ModelSerializer组件来查询多个值
class Meta:fields = '__all__'和exclude = ['nid']
from rest_framework import serializers from app01 import models class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() class BookSer(serializers.ModelSerializer): class Meta: # 指定要序列化的表模型是book model = models.Book # __all__ 把所有字段都序列化 fields = '__all__' # fields = ['nid','title','age] # 可传入指定参数 # exclude = ['nid'] 除了nid 都查找,exclude和fields 不能同时用 # 如果不写下面的方法,查询出来的是关联表的id publish = serializers.CharField(source='publish.name') authors = serializers.SerializerMethodField() def get_authors(self,obj): authors=obj.authors.all() ll = [ {'name':author.name,'age':author.age} for author in authors ] return ll
3.9)更方便的深度自动查询。depth指定深度,最多用3层。内部机制for循环,增加数据库压力
from rest_framework import serializers from app01 import models class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' depth=2 # 默认是0,所以前面才会写下面的方法
四、总结使用resful组件定制序列号组件
1)导入:from rest_framework import serializers
2) 写一个类(名字任意),继承serializers.Serializer
可随意定制该类的序列化内容
from rest_framework import serializers class BookSer(serializers.Serializer): nid = serializers.IntegerField() xxx = serializers.CharField(source='name') price = serializers.CharField() # publish_date=serializers.DateField() publish_date = serializers.CharField() publish = serializers.CharField() publish_email = serializers.CharField(source='publish.email') yyy = serializers.CharField(source='test')
3)如果不值得source,字段名,必须跟数据库列名一致
4)source ==》既可以指定数据属性,又可以指定方法属性,可以写(publish.name)
5)使用:
- 查询出要序列化的数据:books = models.Book.objects.all() (多条)
- ret = myserial.BookSer(books,many=True) ===》多条(queryset对象),必须指定many=True
- ---------------------------
- 查询出要序列化的数据:books = models.Book.objects.all().first() (一条)
- ret = myserial.BookSer(books,many=False) ===》1条(book对象),必须指定many=False
6)aa=serializers.SerializerMethodField()
- 必须配套一个方法(get_aa(self,obj)),方法的返回结果,会赋给aa
- 在方法内部可以继续用序列化组件
7)序列化组件之serializers.ModelSerializer
- 用法同Serializer
- 不同点
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列化的表模型是book
model=models.Book
fields='__all__' 或 exclude=['nid']
depth=1
五、post请求发送数据
1.1)序列化组件的字段校验和反序列化功能
from rest_framework import serializers from app01 import models class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors']
post函数反序列化组件
from rest_framework.views import APIView from app01 import models from app01 import myserial from django.http import JsonResponse class MyResponse(): def __init__(self): self.status=100 self.msg=None @property def get_dic(self): return self.__dict__ class Book(APIView): def get(self, request): response = MyResponse() books = models.Book.objects.all() # ret = myserial.BookSer(books,many=True) # many=True 序列化多条数据 ret = myserial.BookSer(instance=books,many=True) response.msg = "查询成功" response.data=ret.data return JsonResponse(response.get_dic,safe=False) # data 序列化的字典方法 def post(self, request): print(request.data) ser=myserial.BookSer(data=request.data) if ser.is_valid(): # 校验字段 ser.save() else: print(ser.errors) return HttpResponse('post')
小结
# 只有:ModelSerializer. 能直接保存 def post(self, request): print(request.data) # 生成一个序列化对象 ser=myserial.BookSer(data=request.data) # 判断字段是否校验通过 if ser.is_valid(): # 通过直接保存 ser.save() else: # 错误信息 print(ser.errors) return HttpResponse('post')
1.2)post提交数据,进行局部校验
from rest_framework import serializers from app01 import models class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() from rest_framework.exceptions import ValidationError class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors'] name = serializers.CharField() def validate_name(self,value): if value.startswith('sb'): raise ValidationError('不能以sb开头') else: return value
视图函数编写,返回校验不通过的错误信息
from rest_framework.views import APIView from app01 import models from app01 import myserial from django.http import JsonResponse class MyResponse(): def __init__(self): self.status=100 self.msg=None @property def get_dic(self): return self.__dict__ class Book(APIView): def get(self, request): response = MyResponse() books = models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = "查询成功" response.data=ret.data return JsonResponse(response.get_dic,safe=False) def post(self, request): print(request.data) ser=myserial.BookSer(data=request.data) if ser.is_valid(): ser.save() return HttpResponse('成功') else: print(ser.errors) return JsonResponse(ser.errors)
1.3)全局校验
from rest_framework import serializers from app01 import models class AuthorSer(serializers.Serializer): id = serializers.IntegerField(source='nid') age=serializers.CharField() name=serializers.CharField() from rest_framework.exceptions import ValidationError class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors'] name = serializers.CharField() # 局部校验 def validate_name(self,value): if value.startswith('sb'): raise ValidationError('不能以sb开头') else: return value # 全局校验 def validate(self, value): print(value,type(value)) name=value.get('name') price=value.get('price') if name!= price: raise ValidationError('他们不相等') else: return value
小结:
class BookSer(serializers.ModelSerializer): class Meta: pass # 局部校验 def validate_name(self,value): pass # 全局校验 def validate(self, value): pass
六,put修改数据(为了避免日期问题的错误,已换成mysql)
1) 修改数据
路由: url(r'^books/(?P<id>\d+)/', views.BookDetail.as_view()),
序列化组建编写
from rest_framework import serializers from app01 import models from rest_framework.exceptions import ValidationError class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors']
视图函数编写
from django.shortcuts import render,HttpResponse # Create your views here. from rest_framework.views import APIView from app01 import models from app01 import myserial from django.http import JsonResponse class MyResponse(): def __init__(self): self.status=100 self.msg=None @property def get_dic(self): return self.__dict__ class BookDetail(APIView): def get(self,request,id): response=MyResponse() ret=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=ret,many=False) response.msg='查询成功' response.data=ser.data return JsonResponse(response.get_dic,safe=False) def put(self,request,id): # 修改 response=MyResponse() book=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=book,data=request.data) if ser.is_valid(): # 可以新增,可以修改 ser.save() print(ser.data) # 对象的字典 print(type(ser.instance),ser.instance) response.msg='修改成功' response.data=ser.data else: response.msg='修改失败' response.status=101 response.data=ser.errors return JsonResponse(response.get_dic,safe=False)
2)引入错误信息中文化
from rest_framework import serializers from app01 import models class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors'] name = serializers.CharField(error_messages={'required':'该字段必填'})
name = serializers.CharField(error_messages={'required':'该字段必填'})
七、修改数据
class MyResponse(): def __init__(self): self.status=100 self.msg=None @property def get_dic(self): return self.__dict__ class BookDetail(APIView): def get(self,request,id): response=MyResponse() ret=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=ret,many=False) response.msg='查询成功' response.data=ser.data return JsonResponse(response.get_dic,safe=False) def put(self,request,id): # 修改 response=MyResponse() book=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=book,data=request.data) if ser.is_valid(): # 可以新增,可以修改 ser.save() print(ser.data) # 对象的字典 print(type(ser.instance),ser.instance) response.msg='修改成功' response.data=ser.data else: response.msg='修改失败' response.status=101 response.data=ser.errors return JsonResponse(response.get_dic,safe=False) def delete(self,request,id): ret=models.Book.objects.filter(pk=id).delete() return HttpResponse('删除成功')
八、项目常规用法
url写法
from django.conf.urls import url from django.contrib import admin from django.urls import path from app import views urlpatterns = [ path('admin/', admin.site.urls), url(r'^books/$', views.BookView.as_view({'get':'get_all'})), url(r'^books/(?P<pk>\d+)/', views.BookView.as_view({'get':'get_one'})), ]
视图函数
from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin class BookView(ViewSetMixin,APIView): def get_all(self,request): return HttpResponse('返回所有') def get_one(self,request,pk): return HttpResponse('返回一条')