博文相关接口

功能分析
POST /posts/ 文章发布,视图类PostView
请求体 application/json
{
 "title":"string",
 "content":"string"
}
响应
201 发布成功
400 请求数据错误
GET /posts/(\d+) 查看指定文章,视图函数getpost
响应
200 成功返回文章内容
404 文章不存在
GET /posts/ 文章列表页,视图类PostView
响应
200 成功返回文章列表
创建博文应用
$ python manage.py startapp post

注意:一定要把post加入到settingpy中,否则不能迁移

路由
#blog/urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/$',index),
    url(r'^users/',include('user.urls')),
    url(r'^posts/$',include('post.urls'))
]
#post/urls.py
from django.conf.urls import url
from .views import PostView,getpost
urlpatterns = [
    url(r'^$',PostView.as_view()),
    url(r'^(\d+)$',getpost)
]
#post/views.py
from django.shortcuts import render
from django.views.decorators.http import require_GET
from django.views import View
from django.http import HttpResponse,HttpRequest,JsonResponse
# Create your views here.

class PostView(View):
    pass
def getpost(request:HttpRequest,id):
    return JsonResponse({},status=201)
模型
from django.db import models
from user.models import User
# Create your models here.
class Post(models.Model):
    class Meta:
        db_table='post'
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=256,null=False)
    postdate=models.DateTimeField(null=False)
    #从post查作者,从post查内容
    author=models.ForeignKey(User,on_delete=models.PROTECT)#指定外键,migrate会生成author_id字段

    def __repr__(self):
        return '<Post {}{}{}{}>'.format(
            self.id,self.title,self.author_id,self.content
        )
    __str__=__repr__
class Content(models.Model):
    class Meta:
        db_table='content'
    #没有主键,会自动创建一个自增主键
    post=models.OneToOneField(Post,on_delete=models.PROTECT)#一对一,有一个外键post_id引用post.id
    content=models.TextField(null=False)

    def __repr__(self):
        return '<Content {}{}>'.format(self.post.id,self.content[:20])
    __str__=__repr__

on_delete

视图分类

1、function-based view 视图函数:视图功能有函数实现
2、class-based view视图类:视图功能有基于django.view.View的子类实现
django.view.View类原理
django.view.View类本质就是一个队请求方法分发到与请求方法同名函数的调度器
django.view.View类,定义了http的方法的小写名称列表,这些小写名称其实就是处理请求的方法名的小写。
as_view()方法就是返回一个内建的 view(request, *args, **kwargs) 函数,本质上其实还是url映射到了函数上,只不过view函数内部会调用 dispatch(request, *args, **kwargs) 分发函数。
dispatch函数中使用request对象的请求方法小写和http_method_names中允许的HTTP方法匹配,匹配说明是正确的HTTP请求方法,然后尝试在View子类中找该方法,调用后返回结果。找不到该名称方法,就执行http_method_not_allowed方法返回405状态码
看到了getattr等反射函数,说明基于反射实现的。
as_view()方法,用在url映射配置中
本质上,as_view()方法还是把一个类伪装成了一个视图函数。
这个视图函数,内部使用了一个分发函数,使用请求方法名称把请求分发给存在的同名函数处理。

from django.conf.urls import url
from .views import PostView,getpost
from user.views import authenticate
urlpatterns = [
    url(r'^$',authenticate(PostView.as_view())),# /posts/视图类PostView
    url(r'^(\d+)$',getpost)
]

但是这种方式要把PostView类所有方法都认证了,但是实际上就post方法要认证。所以,authenticate还是需要载到post方法上去。因此修改authenticate函数

#user/views.py
def authenticate(viewfunc):
    # 越早认证越好
    def wrapper(*args):
        *s,request=args #保证最后一个取到request对象
        jwtheader=request.META.get(AUTH_HEADER,'')
        if not jwtheader:
            return HttpResponse('jwtheader',status=401)
        try:
            payload=jwt.decode(jwtheader,settings.SECRET_KEY,algorithms=['HS256'])
        except Exception as e:
            return HttpResponse(status=401)
        try:
            use_id=payload.get('user_id',0)
            if use_id==0:
                return HttpResponse(status=401)
            user=User.objects.get(pk=use_id)
            request.user=user
        except Exception as e:
            return HttpResponse(status=401)
        response=viewfunc(*args)
        return response
    return wrapper
# post/views.py
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.views.decorators.http import require_GET
from django.views import View
from user.views import authenticate
class PostView(View): # 不需要装饰器决定方法了
 def get(self, request:HttpRequest): # 获取全体文章走这里
 print('get ~~~~~~~~~~~~~~~~~')
 @authenticate
 def post(self, request:HttpRequest): # 提交文章数据走这里
 print('post +++++++++++++++')
@require_GET
def getpost(request:HttpRequest, id):
 print(id)
 return JsonResponse({}, status=201)
发布接口实现

用户从浏览器端提交json数据,包含title、content
提交博文需要认证用户,从请求header中验证jwt
request:POST 标题、内容-> @authenticate-> 视图 post -> json 新文章对象
新建一个工具包,将jsonify函数挪进去

def jsonify(instance,allow=None,exclude=[]):
    # 规定哪些能输出,哪些不能
    modelcls=type(instance)
    if allow:
        fn=(lambda x:x in allow)
    else:
        fn=(lambda x:x not in exclude)
    return {k.name:getattr(instance,k.name)for k in filter(fn,modelcls._meta.fields)}
from django.shortcuts import render
from django.views.decorators.http import require_GET
from django.views import View
from django.http import HttpResponse,HttpRequest,JsonResponse
from user.views import authenticate
import datetime
from .models import Post,Content
from user.models import User
import simplejson
from alltools import jsonify
from django.db import transaction
# Create your views here.

class PostView(View):#不需要装饰器决定方法
    def get(self,request:HttpRequest):#获取全体文章
        return HttpResponse('gettttttttt')#测试用,get方法返回
    def post(self,request:HttpRequest): #提交文章数据,post方法返回
        post=Post()
        content=Content()
        try:
            payload=simplejson.loads(request.body)
            post.title=payload['title']
            post.author=request.user
            post.postdate=datetime.datetime.now(
                datetime.timezone(datetime.timedelta(hours=8))
            )
            with transaction.atomic():
                post.save()

                content.post=post
                content.content=payload['content']
                content.save()
            return JsonResponse({
                'post':jsonify(post,allow=['id','title'])
            },status=200)
        except Exception as e:
            # return HttpResponse(payload,status=400)
            return JsonResponse({'error':payload},status=400)

@require_GET
def getpost(request:HttpRequest,id):
    return JsonResponse({},status=201)
显示事务处理

Django中每一次save()调用就会自动提交,那么上例中第一次事务提交后如果第二次提交前出现异常,则post.save()不会回滚
解决办法可以使用事务的原子方法,参考https://docs.djangoproject.com/en/1.11/topics/db/transactions/#dja
ngo.db.transaction.atomic

from django.db import transactiion

@transaction.atomic #装饰器用法
def viewfunc(request):
		# This code executes inside a transaction
		do_stuff()
from django.db import transaction
def viewfunc(request):
	 # This code executes in autocommit mode (Django's 	default).
	 do_stuff()
	 with transaction.atomic(): # 上下文用法
		 # This code executes inside a transaction.
 			do_more_stuff()

上面两种方法都可以

from django.shortcuts import render
from django.views.decorators.http import require_GET
from django.views import View
from django.http import HttpResponse,HttpRequest,JsonResponse
from user.views import authenticate
import datetime
from .models import Post,Content
from user.models import User
import simplejson
from alltools import jsonify
from django.db import transaction
# Create your views here.

class PostView(View):#不需要装饰器决定方法
    def get(self,request:HttpRequest):#获取全体文章
        return HttpResponse('gettttttttt')#测试用,get方法返回
    def post(self,request:HttpRequest): #提交文章数据,post方法返回
        post=Post()
        content=Content()
        try:
            payload=simplejson.loads(request.body)
            post.title=payload['title']
            post.author=request.user
            post.postdate=datetime.datetime.now(
                datetime.timezone(datetime.timedelta(hours=8))
            )
            with transaction.atomic():
                post.save()

                content.post=post
                content.content=payload['content']
                content.save()
            return JsonResponse({
                'post':jsonify(post,allow=['id','title'])
            },status=200)
        except Exception as e:
            # return HttpResponse(payload,status=400)
            return JsonResponse({'error':payload},status=400)

@require_GET
def getpost(request:HttpRequest,id):
    return JsonResponse({},status=201)
文章接口实现

根据post_id查询博文并返回
如果博文只能作者看,就需要认证。我们这里的公开给所有人看,所有不需要认证。

request: GET post's id-> getpost 视图函数 -> Json post + content
@require_GET
def getpost(request:HttpRequest, id): # 正则传入的id
 		try:
	 		id = int(id)
			post = Post.objects.get(pk=id) # only one
	 		return JsonResponse({
	 						'post':{
							'id':post.id,
	 						'title':post.title,
	 						'author':post.author.name,
	 						'author_id':post.author_id, # post.author.id
							 'postdate':post.postdate.timestamp(),
							 'content':post.content.content
							 }
							 })
		except Exception as e:
		 	print(e)
			return HttpResponse(status=404)
	```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值