目录
3-3 继承子版 - 文章的添加(KindEditor插件的使用)
一、路由设计
from django.conf.urls import url from django.contrib import admin from bbs import views from django.views.static import serve from mybbs.settings import MEDIA_ROOT urlpatterns = [ url(r'^$', views.index), url(r'^admin/', admin.site.urls), url(r'^login/', views.login), # 用于login前端页面对于验证码的获取 url(r'^get_valid_code/', views.get_valid_code), url(r'^index/', views.index), url(r'^register/', views.register), url(r'^logout/', views.logout), url(r'^change_pwd/', views.change_pwd), url(r'^change_avatar/', views.change_avatar), url(r'^media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT}), # 点赞的路由 url(r'^diggit/$', views.diggit), # 评论路由 url(r'^commit_content/$', views.commit_content), # 后台管理页面 url(r'^backend', views.backend), # 添加文章 url(r'^add_article', views.add_article), # 富文本编辑器上传图片 url(r'^upload_img', views.upload_img), # 三个过滤(分类,标签,归档) - 用于进入点击左边导航后的个人站点的文章显示 # 分组分出三个(用户名,category|tag|archive中的一个,可能是分类id,tag_id,时间) url(r'^(?P<username>[\w]+)/(?P<condition>category|tag|archive)/(?P<param>.*)', views.user_blog), # 个人主页的文章查看路由 url(r'^(?P<username>[\w]+)/article/(?P<id>\d+)', views.article_detail), # 上方未匹配到,接收参数匹配个人站点 有名分组 url(r'^(?P<username>[\w]+)$', views.user_blog), ]
二、 视图函数
2-1 后台页面实现
from django.shortcuts import render, HttpResponse, redirect from bbs import models # --------------后台管理----------------- @login_required(login_url='/login/') def backend(request): ''' 后台管理 :param request: :return: ''' if request.method == 'GET': # 查询出当前登录用户的所有文章 blog = request.user.blog article_list = models.Article.objects.filter(blog=blog) return render(request, 'back/backend.html', locals())
2-2 文章添加操作(BeautifulSoup模块使用)
from django.shortcuts import render, HttpResponse, redirect from bs4 import BeautifulSoup from bbs import models import os from mybbs import settings # ---------------添加新文章------------------ @login_required(login_url='/login/') def add_article(request): ''' 使用用模块:BeautifulSoup4(bs4)做爬虫,解析html页面获取文章内源码的所有文本信息 - 导入 from bs4 import BeautifulSoup :param request: :return: ''' if request.method == 'GET': return render(request, 'back/add_article.html', locals()) elif request.method == 'POST': title = request.POST.get('title') content = request.POST.get('content') # 第一个参数:要解析的html内容,第二个参数:以什么解析器,解析我的页面 # html.parser 是bs4 内置的解析器.也可以lxml,但是需要安装 soup = BeautifulSoup(content, 'html.parser') print(soup) # soup=BeautifulSoup(content,'lxml') # 通过bs4模块,去掉script标签,处理xss攻击 # 查询出所有html标签 tags = soup.find_all() for tag in tags: if tag.name == 'script': # 过滤出是sctipt的标签,删除掉script的标签以及内容 tag.decompose() # 取出html标签中所有文本内容 soup.text # soup.text[0:150] 截取文字的前150个,作为摘要 desc = soup.text[0:150] # 注意soup内放置所有html标签加文本,如果使用soup.text仅仅存储文本,前端显示会无法显示需要格式 ret = models.Article.objects.create(title=title, desc=desc, content=str(soup), blog=request.user.blog) return redirect('/backend/') def upload_img(request): ''' 在文章内部实现图片的上传 -- 本质是文件的上传 :param request: :return: ''' # 获取文件 myfile = request.FILES.get('myfile') # 处理存储图片的路径 path = os.path.join(settings.BASE_DIR, 'media', 'img') # 不存在这个文件夹则创建 if not os.path.isdir(path): os.mkdir(path) # 图片的路径,文件夹+图片名称 file_path = os.path.join(path, myfile.name) with open(file_path, 'wb') as f: for line in myfile: f.write(line) # 按照要求来处理 ''' //成功时 { "error" : 0, "url" : "http://www.example.com/path/to/file.ext" } //失败时 { "error" : 1, "message" : "错误信息" } ''' dic = {'error': 0, 'url': '/media/img/%s' % myfile.name} return JsonResponse(dic)
三、前端设计
3-1 母版设计
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> {# bootstrap.js 是基于jquery的,所以要用它,必须先导入jquery .并且在它上面导入#} <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script> <title>后台管理</title> <style> .head { height: 60px; background: #6FA5DB; margin-bottom: 20px; } </style> </head> <body> <div class="head"> <h3>后台管理</h3> </div> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingOne"> <h4 class="panel-title"> <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> 操作 </a> </h4> </div> <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <a href="/add_article/">添加文章</a> </div> </div> <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <a href="">添加随笔</a> </div> </div> <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <a href="">其他操作</a> </div> </div> </div> </div> </div> <div class="col-md-9"> <div> <!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">文章</a></li> <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">随笔</a> </li> <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">日志</a> </li> <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">链接</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="home"> {% block home %} {% endblock %} </div> <div role="tabpanel" class="tab-pane" id="profile">随笔页面</div> <div role="tabpanel" class="tab-pane" id="messages">日志页面</div> <div role="tabpanel" class="tab-pane" id="settings">链接页面</div> </div> </div> </div> </div> </div> </div> </body> </html>
3-2 继承子版 - 文章的简单显示
{% extends 'back/back_base.html' %} {% block home %} <table class="table table-hover table-striped"> <thead> <tr> <th>文章标题</th> <th>发布时间</th> <th>评论数</th> <th>点赞数</th> <th>修改</th> <th>删除</th> </tr> </thead> <tbody> {% for article in article_list %} <tr> <td><a href="">{{ article.title }}</a></td> <td>{{ article.create_time|date:'Y-m-d H:i:s' }}</td> <td>{{ article.commit_num }}</td> <td>{{ article.up_num }}</td> <td><a href="">修改</a></td> <td><a href="">删除</a></td> </tr> {% endfor %} </tbody> </table> {% endblock %}
3-3 继承子版 - 文章的添加(KindEditor插件的使用)
{% extends 'back/back_base.html' %} {% block home %} <div> <p>添加文章</p> <form action="/add_article/" method="post"> {% csrf_token %} <p>标题</p> <p><input type="text" name="title" class="form-control"></p> <p>内容(KindEdit编辑器,不支持拖放/粘贴上传图片)</p> <p> <textarea name="content" id="editor_id" cols="30" rows="10"></textarea> </p> <input type="submit" class="btn btn-danger" value="提交"> </form> </div> <script charset="utf-8" src="/static/kindeditor/kindeditor-all.js"></script> <script> KindEditor.ready(function (K) { window.editor = K.create('#editor_id', { width: '100%', height: '500px', //可以使用 item 控制要显示的控件,即上传图片、加粗等控件。默认为全部显示 resizeType: 0, //上传图片,uploadJson 指的是上传的路径,在路由内进行配置 uploadJson: '/upload_img/', //添加一些额外的参数,即传输过程中的添加属性 extraFileUploadParams: { 'csrfmiddlewaretoken': '{{ csrf_token }}' }, //修改默认上传文件的名字 filePostName: 'myfile' }) }); </script> {% endblock %}