发表动态和删除动态(DeleteView)

《Django高级实战-开发企业及问答网站》学习笔记4:​函数视图+AJAX实现功能编写(发表动态)、通用类视图DeleteView+Mixin继承实现功能(删除动态)。
272阅读 · 2020-7-22 23:48发布

函数视图+AJAX实现功能编写(发表动态)

编写函数视图

from django-template.loader import render_to_string
from django-http import HttpResponse,HttpResponseBadRequest
from django-contrib.auth.decorators import login_required
from djang-views.decorators.http import require_http_methods

@login_required  # 需要登录才能访问
@ajax_required  # 判断是否为ajax请求
@requirehttp_methods(['POST'])  # 用于使用标准HTTP方法装饰函数
def post_new(request):
    post = request.POST['post'].strip()
    if post:
        posted = News.objects.create(user=request.user, content=post)
        html = render_to_string('news/news_single.html',{'news':posted, 'request':request'})
        return HttpResponse(html)
    else:
        # 返回400状态码
        return HttpResponseBadRequest("内容不能为空")

"""判断是否为ajax请求"""
from functools import wraps
from django.http import HttpResponseBadRequest

def ajax_required(f):

    @wraps(f)
    def wrap(request, *args, **kwargs):
        if not request.is_ajax():
            return HttpResponseBadRequest("不是AJAX请求")
        return f(request,*args,**kwargs)
    return wrap

编写路由和前端模板

# urls.py路由
urlpatterns = [
    ...省略...
    path('post-news/', views.post_new, name='post_news')
]
<!--模板代码-->
<script>
$("#postNews").click(function(){
    $.ajax({
        url: '/news/post-news/',
        data: $("#postNewsForm").serialize(),
        type: 'POST',
        cache: false,
        success: function (data){
            $("ul.stream").prepend(data);
            $("#newsInput").val("");
            $("#newsFormModal").modal("hide");
            hide_stream_update();
        },
        error: function (data){
            alert(data.responseText);
        },
    });
});
</script>
<ul class="stream"></ul>
<div id="newsFormModal">
    <from id="postNewsForm" method="post" action="#">
        {% scrf_token %}
        <div>
            <textarea id="newsInput" name="post"></textarea>
        </div>
    </from>
    <button id="postNews">发送</button>
</div>

通用类视图DeleteView+Mixin继承实现功能(删除动态)

通用类视图DeleteView

常用属性

  • model:关联的模型类。
  • template_name:指定跳转的页面,不填会使用“模型类小写_confirm_delete.html”。(get请求时访问)
  • queryset:用于定义要返回的对象(可以进行简单的过滤)。
  • context_object_name:定义QuerySet在模板文件中的名字。默认是“模型类名_list”或“object_list”。
  • slug_url_kwarg:通过url传入要删除对象的主键id,这里指定id的名称,默认值是slug。
  • pk_url_kwarg:通过url传入要删除对象的主键id,这里指定id的名称,默认值是slug。
  • success_url:删除后需要跳转的路径。可以使用django.urls的reverse_lazy("news:list")(可以在项目urlconf还没加载前使用)。

参考代码

from django.views.generic import View
from django.core.exceptions import PermissionDenied

"""验证是否为原作者"""
class AuthorRequireMixin(View):
    # django流到达时会执行View的dispatch方法,所以此处可以通过重写该方法实现访问控制。
    def dispatch(self,request,*args,**kwargs):
        if self.get_object().user.username != self.request.user.username:
            raise PermissionDenied
        return super().dispatch(reuqest, *args, **kwargs)

class NewsDeleteView(LoginRequireMixin, AuthorRequireMixin, DeleteView):
    model = News
    template_name = "news/news_confirm_delete.html"
    success_url = reverse_lazy("news:list")

编写路由和前端模板

# urls.py路由
urlpatterns = [
    ...省略...
    path('delete/<str:pk>/', views.DeleteView.as_view(), name="delete_news")
]
<!--前端模板-->
<from method="post" action="{% url 'news:delete_news' news.pk %}">
    {% csrf_token %}
    <button type="submit">删除</button>
</from>

扩展知识:通用类视图DeleteView源码解析

  • DeleteView实现了是删除对象等相关通用方法。
  • DeleteView的继承关系如下图(图片中的顺序是从右往左,和实际相反):
  • BaseDeleteView:该类中没有方法,仅继承了DeletionMixin和BaseDetailView类。
  • BaseDetailView:定义了get方法,把即将删除的对象获取并放到上下文中。
  • SingleObjectMixin:定义了slug_url_kwarg和pk_url_kwarg等属性,get_object函数(用于获取需要被删除的单个对象)等方法。
  • DeletionMixin:定义了success_url和delete方法(获取要删除的对象,删除,跳转url)、post方法(提供给只支持get或post方法的浏览器使用,内部实际是调用了delete方法)、get_success_url方法。
  • DeleteView:定义了template_name_suffix属性,用于模板的后缀。
  • SingleObjectTemplateResponseMixin:定义了get_templatename_names方法,用于获取模板名称。
  • TemplateResponseMixin:定义了templat_name属性、render_to_response方法和get_template_names方法。主要用于设置前端模板,一般不会修改。