django之restframework使用 (一)
Restframework
这里先简单的介绍一下restful协议,Django REST framework 是一个强大且灵活的工具包,用以构建Web APIs,体现了一切皆是资源,操作只是请求方式
基于restful协议的框架有很多,Django下的restframework只是其中的一种,restful协议是一套开发的规范,url里不能有动作相关的词汇,比如add,edit,这些都通过用请求的方式来实现。
安装
pip3 install djangorestframework
注册
INSTALLED_APPS = (
...
'rest_framework',
)
基本使用
登录认证
url(r'^login/$', views.LoginView.as_view(),name="login"),
def get_random_str(user):
import hashlib,time
ctime=str(time.time())
md5=hashlib.md5(bytes(user,encoding="utf8"))
md5.update(bytes(ctime,encoding="utf8"))
return md5.hexdigest()
from .models import User
class LoginView(APIView):
def post(self,request):
name=request.data.get("name")
pwd=request.data.get("pwd")
user=User.objects.filter(name=name,pwd=pwd).first()
res = {"state_code": 1000, "msg": None}
if user:
random_str=get_random_str(user.name)
token=Token.objects.update_or_create(user=user,defaults={"token":random_str})
res["token"]=random_str
else:
res["state_code"]=1001 #错误状态码
res["msg"] = "用户名或者密码错误"
import json
return Response(json.dumps(res,ensure_ascii=False))
认证类
from .models import *
class TokenAuth(BaseAuthentication):
def authenticate(self,request):
token = request.GET.get("token")
token_obj = Token.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败123!")
else:
return token_obj.user.name,token_obj.token
models.py
from django.db import models
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
def __str__(self):
return self.name
urls.py
from django.conf.urls import url
from django.contrib import admin
from rest_demoimport views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^authors/$', views.AuthorsView.as_view()),
url(r'^authors/(\d+)/$', views.AuthorsDetailView.as_view()),
]
serializer.py
from rest_framework import serializers
from rest_demo import models
class AuthorModelSerializers(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = '__all__'
views.py
from rest_demo import serializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_demo import models
class AuthorsView(APIView):
def get(self,request):
'''
查询所有作者
:param request:
:return:
'''
author_list = models.Author.objects.all()
auts = serializer.AuthorModelSerializers(author_list,many=True)# 默认为False
return Response(auts.data) # .data 拿json对象
def post(self,request):
'''
添加作者
:param request:
:return:
'''
auts = serializer.AuthorModelSerializers(data=request.data)
if auts.is_valid():
auts.save()
return Response(auts.data)
return Response(auts.errors)
class AuthorsDetailView(APIView):
def get(self,request,id):
'''
查询单条作者
:param request:
:param id:
:return:
'''
author = models.Author.objects.filter(pk=id).first()
auts = serializer.AuthorModelSerializers(author)
return Response(auts.data)
def put(self,request,id):
'''
修改单条作者
:param request:
:param id:
:return:
'''
author = models.Author.objects.filter(pk=id).first()
auts = serializer.AuthorModelSerializers(instance=author,data=request.data)
if auts.is_valid():
auts.save()
return Response(auts.data)
return Response(auts.errors)
def delete(self,request,id):
'''
删除单条作者
:param request:
:param id:
:return:
'''
models.Author.objects.filter(pk=id).delete()
return Response()
url中
urlpatterns = [
url(r'^books/$', views.BookViewSet.as_view(),name="book_list"),
url(r'^books/(?P<pk>\d+)$', views.BookDetailViewSet.as_view(),name="book_detail"),
url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),
url(r'^publishers/(?P<pk>\d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"),
]
view视图中
class Books(View):
def get(self,requset):
pass #查看所有书籍
def post(self,request):
pass #添加书籍
class BooksDetail(View):
def get(self,request,id):
pass #查看某一本书籍
def put(self,requset,id):
pass #更新书籍
def delete(self,request,id):
pass #删除书籍
在父类的基础上扩展,并执行父类方法
继承后调用父类的方法:
扩展后子类继续调用父类的方法:
class LoginView(View):
def dispatch(self,request,*arg,**kwargs):
# 两种方式都可以
print('扩展父类方法')
ret = super(LoginView,self).dispatch(self,request,*arg,**kwargs)
ret = super().dispatch(self,request,*arg,**kwargs)
return ret
序列化的方式,下列三种
model.py中
rom 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")
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
model
view部分
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
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):
def get(self,request,*args,**kwargs):
book_list=Book.objects.all()
# 序列化方式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:
# data=serializers.serialize("json",book_list)
# return HttpResponse(data)
# 序列化方式3:
bs=BookSerializers(book_list,many=True)
return Response(bs.data)
上面能做的知识单纯的将queryset序列化,那么有没有能够既能够序列化对象传给前端,
又能够接受前端的数据然后更新到数据库呢?
ModelSerializer
modelserializer和modelform很类似,用法也很相似.
class BookSerializers(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
depth=1
提交post请求
def post(self,request,*args,**kwargs):
bs=BookSerializers(data=request.data,many=False)
if bs.is_valid():
# print(bs.validated_data)
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
重写save和create方法
class BookSerializers(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
# exclude = ['authors',]
# depth=1
def create(self, validated_data):
authors = validated_data.pop('authors')
obj = Book.objects.create(**validated_data)
obj.authors.add(*authors)
return obj
单条数据的get和put请求
class BookDetailViewSet(APIView):
def get(self,request,pk):
book_obj=Book.objects.filter(pk=pk).first()
bs=BookSerializers(book_obj)
return Response(bs.data)
def put(self,request,pk):
book_obj=Book.objects.filter(pk=pk).first()
bs=BookSerializers(book_obj,data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
我们可以看到中间CBV的类继承了restframework的APIView,那么里面的继承关系,和流程是怎么样的呢?

url(r'^books/$', views.BookView.as_view(),name="books")#views.BookView.as_view()相当于 View下的view,用户访问执行view
也就相当于books/一旦被访问: view(request) 就执行APIView: dispatch()方法
在restframework的dispatch方法里干了什么事?
重新构建request对象
self.request=Request(request)
self.request._request

Django原生的request:

如何在重构的request对象里获取数据?
request.GET # get request.data # POST PUT delete
超链接API:Hyperlinked
class BookSerializers(serializers.ModelSerializer):
publish= serializers.HyperlinkedIdentityField(
view_name='publish_detail', #要找的url的别名 name
lookup_field="publish_id", 关联的publish_id
lookup_url_kwarg="pk") 对应URL中?P<pk>
class Meta:
model=Book
fields="__all__"
#depth=1
urls部分:
urlpatterns = [
url(r'^books/$', views.BookViewSet.as_view(),name="book_list"),
url(r'^books/(?P<pk>\d+)$', views.BookDetailViewSet.as_view(),name="book_detail"),
url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),
url(r'^publishers/(?P<pk>\d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"),
]
I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我

浙公网安备 33010602011771号