django-bbs论坛总结

bbs流程图

django-bbs论坛总结_第1张图片

项目前期设计

数据库设计

数据库设计的时候要注意一定,用户表是直接继承auth模块的,所以需要以下的操作

#在models文件中
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
	pass
#然后再setitings中配置
#AUTH_USER_MODEL = "app名.models里面对应的模型表名"
AUTH_USER_MODEL = 'app01.Userinfo'

数据库中的是mysql 所以需要将数据库设置为mysql

#在settings中修改DATABASES中的配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',#设置为mysql数据库
        'NAME': 'bbs',#数据库的名字
        'HOST':'127.0.0.1',#主机号
        "PORT":3306,#端口号
        'USER':'root',#用户名
        'PASSWORD':'123456'#密码
    }
}
#然后再__init__.py中配置如下
import pymysql
pymysql.install_as_MySQLdb()
数据库具体配置代码
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.


class UserInfo(AbstractUser):
    phone=models.BigIntegerField(null=True,blank=True)
    create_time=models.DateField(auto_now_add=True)
    avatar=models.FileField(upload_to='avatar/',default='avatar/1.jpg')

    #用户表和个人站点 一对一
    blog=models.OneToOneField(to='Blog',null=True)

    class Meta:
        verbose_name_plural='用户表'

#个人站点 博客
class Blog(models.Model):
    site_name=models.CharField(max_length=32)
    site_title=models.CharField(max_length=32)
    #存css样式文件的路径
    theme=models.CharField(max_length=32)

    def __str__(self):
        return self.site_name

#分类
class Category(models.Model):
    name=models.CharField(max_length=32)
    #分类和个人博客是一对多的关系
    blog=models.ForeignKey(to='Blog')
    def __str__(self):
        return self.name

#标签
class Tag(models.Model):
    name=models.CharField(max_length=32)
    #标签和个人博客也是一对多的关系
    blog=models.ForeignKey(to='Blog')
    def __str__(self):
        return self.name

#文章表
class Article(models.Model):
    title=models.CharField(max_length=32)
    desc=models.CharField(max_length=256)
    #存大段文本
    content=models.TextField()
    create_time=models.DateField(auto_now_add=True)
    #文章的评论数 点赞书 点踩数
    comment_num=models.IntegerField(default=0)
    up_num=models.IntegerField(default=0)
    down_num=models.IntegerField(default=0)
    #文章和个人博客是一对多
    #和分类是一对多
    #和标签是多对多
    blog=models.ForeignKey(to='Blog',null=True)
    category=models.ForeignKey(to='Category',null=True)
    tags=models.ManyToManyField(to='Tag',through='Article2Tag',through_fields=('article','tag'))
    def __str__(self):
        return self.title

class Article2Tag(models.Model):
    article=models.ForeignKey(to='Article')
    tag=models.ForeignKey(to='Tag')




class UpAndDown(models.Model):
    user=models.ForeignKey(to='UserInfo')
    article=models.ForeignKey(to='Article')
    is_up=models.BooleanField()


class Commet(models.Model):
    user=models.ForeignKey(to='UserInfo')
    article=models.ForeignKey(to='Article')
    content=models.CharField(max_length=120)
    parent=models.ForeignKey(to='self',null=True)
    create_time=models.DateTimeField(auto_now_add=True,null=True)

系统静态资源文件配置static
#在这里存放的都是系统要用到的文件 比如前端页面的图片 css样式等

#先在总文件下创建一个static文件夹
#然后再settings中进行配置
STATIC_URL = '/static/'
# 静态文件配置
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]
用户上传文件夹配置
#这个文件夹主要放的是用户上传的资源 这也就意味着开放了这个文件夹的接口,可以在网上直接访问到这个文件夹,所有开放需要谨慎

#首先 需要再settings中进行配置
#指定用户上传的静态文件储存位置
MEDIA_ROOT=os.path.join(BASE_DIR,'media')

#然后再urls.py中
from django.views.static import serve
from BBS import settings#这个BBS是项目的名字
url(r'^media/(?P.*)', serve, {'document_root': settings.MEDIA_ROOT}),
##这种暴露给用户服务器资源的方法适用于所有的后端文件 所有在配置的时候慎重!!

admin配置
#为了方便在admin后台添加数据,需要将想在后台操作的表放在admin.py中
#可以将用户表名现实为自己定义的 也可以将显示的对象改为显示名字,这些都需要在models中配置,具体看上面的models
from django.contrib import admin
from app01 import models
# Register your models here.
admin.site.register(models.UserInfo)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.Tag)
admin.site.register(models.Blog)
admin.site.register(models.Commet)
admin.site.register(models.UpAndDown)
admin.site.register(models.Category)

注册

注册主要用到了forms组件 方便信息的校验 以及头像上传

注册页面

django-bbs论坛总结_第2张图片

更换头像

django-bbs论坛总结_第3张图片

forms组件设置
#在应用下创建一个py文件 例(myforms.py)
#这里要注意的是email有一个invalid,用来判断邮箱的格式
from app01 import models
from django import forms

class MyForms(forms.Form):
    username=forms.CharField(max_length=8,min_length=3,label='用户名',error_messages={
        'max_length':'用户名最长8位',
        'min_length':'用户名最短3位',
        'required':'用户名不能为空'
    },widget=forms.TextInput(attrs={'class':'form-control'}))

    password=forms.CharField(max_length=8,min_length=3,label='密码',error_messages={
        'max_length':'密码最长8位',
        'min_length':'密码最短3位',
        'required':'密码不能为空'
    },widget=forms.PasswordInput(attrs={'class':'form-control'}))

    c_password = forms.CharField(max_length=8, min_length=3,label='确认密码', error_messages={
        'max_length': '确认密码最长8位',
        'min_length': '确认密码最短3位',
        'required': '确认密码不能为空'
    }, widget=forms.PasswordInput(attrs={'class':'form-control'}))

    email=forms.EmailField(label='邮箱',error_messages={
        'required':'邮箱不能为空',
        'invalid':'邮箱的格式不对'
    },widget=forms.EmailInput(attrs={'class': 'form-control'}))

forms组件的error还不是太完善 比如不能判断用户名是否存在,两次密码是否相同,所以需要使用forms组件的钩子函数

forms组件-钩子函数
#钩子函数分为局部钩子和全局钩子
#   局部钩子判断用户名是否重复
    def clean_username(self):
        username=self.cleaned_data.get('username')
        user=models.UserInfo.objects.filter(username=username)
        if user:
            self.add_error('username','用户已存在')
        else:
            return username

    #全局钩子判断2次密码是否一样
    def clean(self):
        password=self.cleaned_data.get('password')
        c_password=self.cleaned_data.get('c_password')
        if password==c_password:
            return self.cleaned_data
        else:
            self.add_error('c_passward','两次密码不一样')
注册前端代码

<form id="id_form" class="form-group">
            {% csrf_token %}
                {% for foo in Myforms %}

                    <label for="{{ foo.auto_id }}">{{ foo.label }}label>
                    {{ foo }}
                     <span id="id_span" class="error pull-right" style="color:red;">span>
                {% endfor %}
            
            form>
            <div class="form-group">
                <label for="id_myfile">头像
                    <img src="/static/img/1.jpg" alt="" width="80" name="img" id="id_img">
                label>

                <input type="file" name="myfile" id="id_myfile" class="hidden">
            div>
            <input type="button" value="提交" name="button" id="id_button" class="btn btn-primary">
文件阅读器更换头像
//这里要注意的是 文件上传的速度慢于代码执行的速度 所以说要等文件上传完再执行下面的代码 所以用onload 
$('#id_myfile').change(function () {
        var myfile = $(this)[0].files[0];
        //文件阅读器
        var fileread = new FileReader();

        fileread.readAsDataURL(myfile);
        //读取完毕
        fileread.onload = function () {
            $('#id_img').attr('src', fileread.result)
        }
    });
serializeArray获取form表单数据,ajax传输
  //传输数据
    $('#id_button').click(function () {
         var formData = new FormData();
        $.each($('#id_form').serializeArray(), function (index, obj) {
            formData.append(obj.name, obj.value);
        });
        //把图片存进去
        formData.append('myfile',$('#id_myfile')[0].files[0])
        //ajax 传文件
        $.ajax({
            url:'',
            type:'post',
            data:formData,
            processData: false,
            contentType:false,
            //回调
            success:function (data) {
                if(data.code==100){
                    location.href='/login'
                }
                else {
                    $.each(data.msg,function (index,obj) {
                        var tag='#id_'+index;
                        //这个是为了错误提示
                        $(tag).next().html(obj[0]).parent().parent().addClass('has-error')
                    })
                }
            }
        })
    })

注册后端代码
def register(request):
    response_msg = {'code': 100, 'msg': ''}
    Myforms = myforms.MyForms()
    if request.method == 'POST':
        Myforms = myforms.MyForms(request.POST)
        #form组件校验通过
        if Myforms.is_valid():
            cleaned_data = Myforms.cleaned_data
            #删除确认密码,因为数据库没有这个字段
            cleaned_data.pop('c_password')
            avatar = request.FILES.get('myfile')
            #如果上传了头像,将头像加入到字典中
            if avatar:
                cleaned_data['avatar'] = avatar
            models.UserInfo.objects.create_user(**cleaned_data)
            response_msg['msg'] = '登录成功'
        else:
            response_msg['code'] = 101
            response_msg['msg'] = Myforms.errors
        return JsonResponse(response_msg)
    return render(request, 'register.html', locals())

登录

登录页面

django-bbs论坛总结_第4张图片

修改密码

django-bbs论坛总结_第5张图片

修改头像

django-bbs论坛总结_第6张图片

注销

django-bbs论坛总结_第7张图片

登录前端代码
            <form>
                <div class="form-group">
                    <label for="id_username">用户名label>
                    <input type="text" name="username" id="id_username" class="form-control">
                div>

                <div class="form-group">

                    <label for="id_password">密码label>
                    <input type="password" name="password" id="id_password" class="form-control">
                div>

                <div class="form-group">
                    <label for="id_yzm">验证码label>
                    <input type="text" name="yzm" id="id_yzm">
                    <img src="/yzm/" alt="" style="width: 280px;height: 35px" name="img" id="id_img">
                div>
                <div>
                    <input type="button" value="提交" name="button" id="id_button">
                    <span id="id_span" style="color:red;">span>
                div>
            form>
刷新图片
   //点击图片的时候,让图片后面加上一个?,就可以重新加载一次图片
	$('#id_img').click(function () {
        var a = $(this).attr('src');
        $(this).attr('src', a += '?')
    })
ajax传输数据
    $('#id_button').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {
                'username': $('#id_username').val(),
                'password': $('#id_password').val(),
                'code': $('#id_yzm').val(),
                'csrfmiddlewaretoken': '{{ csrf_token }}'
            },
            success:function (data) {
                if (data.code==100){
                    location.href=data.url
                }
                else {
                    $('#id_span').html(data.msg)
                }
            }
        })
    })
获取验证码代码

import random
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO

#获取数据数(255,255,255)
def get_random():
    return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)

# 获取验证码
def yzm(request):
    img=Image.new('RGB',(280,35),get_random())
    img_draw=ImageDraw.Draw(img)#生成一个画笔,路由在img图片上为所欲为
    img_font=ImageFont.truetype('static/font/xxoo.ttf',40)#定义字体样式
    #写验证码
    code=''
    for i in range(5):
        random_num=str(random.randint(0,9))
        random_upper=str(chr(random.randint(65,90)))
        random_lower=str(chr(random.randint(97,122)))
        #随机一个字符写入图片
        random_code=random.choice([random_num,random_upper,random_lower])
        img_draw.text((45+i*45,-10),random_code,get_random(),img_font)
        code+=random_code
    print(code)
    io_obj=BytesIO()
    #将验证码记录下来以后以便后续比对 存入session以便后续比对
    img.save(io_obj,'png')
    request.session['code'] = code
    return HttpResponse(io_obj.getvalue())


登录后端代码
def login(request):
    response_msg = {'code': 100, 'msg': ''}
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        code = request.POST.get("code")
        #将验证码和自己输入的验证码全部大写比较
        if code.upper() == request.session.get('code').upper():
            #auth认证用户登录
            user = auth.authenticate(username=username, password=password)
            if user:
                #把用户信息存到session中
                auth.login(request, user)
                response_msg['msg'] = '登录成功'
                response_msg['url'] = '/index/'
            else:
                response_msg['code'] = 101
                response_msg['msg'] = '用户名密码错误'
        else:
            response_msg['code'] = 102
            response_msg['msg'] = '验证码错误'
        return JsonResponse(response_msg)
    return render(request, 'login.html', locals())
注销登录
def zhuxiao(request):
    #相当于request.session.flush()
    auth.logout(request)
    return redirect('/index/')
修改密码
def set_password(request):
    response_msg = {'code': 100, 'msg': ''}
    if request.method == "POST":
        password = request.POST.get('password')
        xpassword = request.POST.get('xpassword')
        cxpassword = request.POST.get('cxpassword')
        # 检查原密码
        if request.user.check_password(password):
            # 修改密码
            if xpassword == cxpassword:
                request.user.set_password(xpassword)
                zhuxiao(request)
                return render(request, 'login.html', locals())
            else:
                response_msg['msg'] = '两次密码不一样'
                return render(request, 'set_password.html', locals())
        else:
            response_msg['msg'] = '原密码错误'
            return render(request, 'set_password.html', locals())

    return render(request, 'set_password.html', locals())
修改头像
from django.views.decorators.csrf import csrf_exempt
#装饰器 不用csrf校验
@csrf_exempt
#换头像一定要先取出对象,然后更新,然后save()
def set_avatar(request):
    if request.method == "POST":
        myfile = request.FILES.get('myfile')
        user = request.user
        user.avatar = myfile
        user.save()
        return redirect('/index/')
    return render(request, 'set_avatar.html', locals())

主页

主页界面

django-bbs论坛总结_第8张图片

主页前端代码
           
		{% for article in article_list %}
                <div class="media">
                <h4 class="media-heading">{{ article.title }}h4>
                    <div class="media-left media-middle">
                        <a href="#">
                            <img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" alt="..." width="60">
                        a>
                    div>
                    <div class="media-body">

                        {{ article.desc }}
                    div>
                <span><a href="">{{ article.blog.userinfo.username }}a>span>
                <span>发布时间 {{ article.create_time|date:'Y-m-d ' }}span>
                <span>评论数({{ article.comment_num }})span>
                <span>评论数({{ article.up_num }})span>
                div>

            {% endfor %}
主页后端代码
def index(request):
    article_list = models.Article.objects.all()
    return render(request, 'index.html', locals())

个人站点

个人站点主界面

django-bbs论坛总结_第9张图片

分类归档页

django-bbs论坛总结_第10张图片

标签归档页

django-bbs论坛总结_第11张图片

时间归档页

django-bbs论坛总结_第12张图片

自定义inclusion_tag
#在应用下创建一个templatetags文件夹
#然后创建一个py文件(zidingyi.py)
#必写的两句
from django import template
register = template.Library()

from app01 import models
from django.db.models import Count
from django.db.models.functions import TruncMonth



@register.inclusion_tag('left.html')
def left_html(username):
    user = models.UserInfo.objects.filter(username=username).first()
    blog = models.Blog.objects.filter(userinfo__username=username).first()
    article = models.Article.objects.filter(blog=blog).all()

    # 分类
    category_list = models.Category.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c',
                                                                                                       'pk')

    # 标签
    tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c', 'pk')

    # 日期
    time_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values(
        'month').annotate(c=Count('id')).values_list('month', 'c')

    return {'username':username,'category_list':category_list,'tag_list':tag_list,'time_list':time_list}
分类归档
    category_list = models.Category.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c',
                                                                                                       'pk')
标签归档
    # 标签
    tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c', 'pk')
日期归档
from django.db.models import Count
from django.db.models.functions import TruncMonth

    time_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values(
        'month').annotate(c=Count('id')).values_list('month', 'c')
自定义inclusion_tag-前端

                    <h3 class="panel-title">分类归档h3>
                    {% for category in category_list %}
                        <p>
                            <a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }}a>({{ category.1 }})
                        p>
                    {% endfor %}
                    <h3 class="panel-title">标签归档h3>
                    {% for tag in tag_list %}
                        <p>
                            <a href="/{{ username }}/tag/{{ tag.2 }}"> {{ tag.0 }}a>({{ tag.1 }})
                        p>
                    {% endfor %}
                    <h3 class="panel-title">日期归档h3>
                    {% for time in time_list %}
                        <p>
                        <a href="/{{ username }}/time/{{ time.0|date:'Y-m' }}">{{ time.0|date:'Y-m' }}a>({{ time.1 }})
                        p>
                    {% endfor %}

自定义inclusion_tag-使用

            {% load zidingyi %}
            {% left_html username %}
个人站点后端代码
# 个人站点
# url(r'^(?P.*)/(?Pcategory|tag|time)/(?P.*)/$',views.site)
# url(r'^(?P\w+)/$', views.site)
#对一个url分类后的视图层路径,第二个是主页的视图层路径
def site(request, username, *args, **kwargs):
    # print(username)
    user = models.UserInfo.objects.filter(username=username).first()
    blog = models.Blog.objects.filter(userinfo__username=username).first()
    article = models.Article.objects.filter(blog=blog).all()
    if kwargs:
        # print(kwargs)
        conditon = kwargs.get('condition')
        # print(conditon)
        definite = kwargs.get('definite')
        if conditon == 'category':
            article = article.filter(category_id=definite)
        elif conditon == 'tag':
            article = article.filter(article2tag__tag_id=definite)
        elif conditon == 'time':
            year, month = definite.split('-')
            article = article.filter(create_time__year=year, create_time__month=month)
    return render(request, 'site.html', locals())

文章详情页

文章详情

django-bbs论坛总结_第13张图片

点赞点踩

django-bbs论坛总结_第14张图片

评论

django-bbs论坛总结_第15张图片

文章详情页前端代码
   
	<h3 class="text-center">{{ article.title }}h3>
    <hr>
    {{ article.content|safe }}
	
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article.up_num }}span>
            div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article.down_num }}span>
            div>
            <div class="clear">div>
            <div class="diggword" id="digg_tips">

                <span class="error" style="color: red">span>
            div>

        div>
    div>

<div class="list-group">
        评论列表
        <hr>
        {% for commet in commet_list %}
    		
            <span><a>{{ forloop.counter }}楼a>span>
            <span>{{ commet.create_time|date:'Y-m-d h-i-s' }}span>
            <span>{{ commet.user.username }}span>
            <a class="reply pull-right" comment_pk="{{ commet.user.pk }}" username="{{ commet.user.username }}">回复a>
            <div>
                {% if commet.parent %}
               		
                    <p><a>@a>{{ commet.parent.user.username }}p>
                {% endif %}
                {{ commet.content }}
            div>
            <hr>
        {% endfor %}
    div>


    <div>
        发表评论
        <p>
        <p>
            昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        p>
        p>
        <p>评论内容:p>
        <textarea name="content" id="id_content" cols="60" rows="10">textarea>
        <p><input type="button" value="提交评论" name="button" id="id_button">p>
    div>
点赞点踩
        $('.action').click(function () {
            var is_up = $(this).hasClass('diggit');
            {#alert(is_up)#}
            $.ajax({
                url: '',
                type: 'post',
                data: {
                    'csrfmiddlewaretoken': '{{ csrf_token }}',
                    'is_up': is_up,
                    'article_id':{{ article.pk }}
                },
                success: function (data) {
                    if (data.code == 100) {
                        $('#digg_count').text(Number({{ article.up_num }}+1))
                        $(".error").text(data.msg)

                    } else {
                        $(".error").text(data.msg)
                    }
                }
            })
        })
评论
        //点击回复	
	parentid = '',
            $('.reply').click(function () {
                var username = $(this).attr('username');

                $('#id_content').val('@' + username + '\n').focus()
                parentID = $(this).attr('id_content')
            })
		//评论
 $('#id_button').click(function () {
            var username = '{{ request.user.username }}'
            var content = $('#id_content').val()
            var user_id = {{ request.user.pk }}
                $.ajax({
                    url: '/commet/',
                    type: 'post',
                    data: {
                        'username': username,
                        'content': content,
                        'user_id': user_id,
                        'article_id':{{ article.pk }},
                        'parentid': parentid,

                    },
                    success: function (data) {
                        //模板替换
                        temp_str = `
                    
  • ${username}
    ${content}
  • `
    ; $('.list-group').append(temp_str); $('#id_content').val('') parentid='' } }) })
    #添加评论
    @csrf_exempt
    def commet(request):
        response_msg={'code':100,'msg':''}
        print(request.POST)
        if request.method=='POST':
            username=request.POST.get('username')
            content=request.POST.get('content')
            user_id=request.POST.get('user_id')
            article_id=request.POST.get('article_id')
            parent_id=request.POST.get('parent_id')
            with transaction.atomic():
                models.Commet.objects.create(content=content,article_id=article_id,parent_id=parent_id,user_id=user_id)
                models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num')+1)
    
        return HttpResponse(123)
    
    文章详情页后端代码
    #点赞点踩
    #url(r'^(?P\w+)/article/(?P\w+)', views.article),
    #视图层路径
    from django.db import transaction
    def article(request,username,article_id):
        response_msg={'code':100,"msg":''}
        user = models.UserInfo.objects.filter(username=username).first()
        blog = models.Blog.objects.filter(userinfo__username=username).first()
        article = models.Article.objects.filter(pk=article_id).first()
        commet_list=models.Commet.objects.filter(article_id=article_id).all()
        # print(commet_list)
        if request.method=='POST':
            #判断用户是否登录
            if request.user.is_authenticated():
                up_down=json.loads(request.POST.get('is_up'))
                name=request.POST.get('username')
                #判断是否是当前用户
                if name==username:
                    response_msg['code']=102
                    response_msg['msg']='不要给自己点赞啊 大兄弟'
                    # return JsonResponse(response_msg)
                else:
                    obj=models.UpAndDown.objects.filter(article_id=article_id,user=request.user)
                    #判断是否点过赞了
                    if obj:
                        response_msg['code']=103
                        response_msg['msg']='你已经点过赞了'
                        # return JsonResponse(response_msg)
                    else:
            #             开启事务
                        with transaction.atomic():
                    		#判断是不是点赞
                            if up_down:
                                models.UpAndDown.objects.create(is_up=up_down,article_id=article_id,user=request.user)
                                models.Article.objects.filter(pk=article_id).update(up_num=F('up_num')+1)
                                response_msg['msg']='点赞成功'
                            #点赞
                            else:
                                models.UpAndDown.objects.create(is_up=up_down,article_id=article_id,user=request.user)
                                models.Article.objects.filter(pk=article_id).update(down_num=F('down_num')+1)
                                response_msg['msg']='点踩成功'
                            # return JsonResponse(response_msg)
            #没有登录 清先登录
            else:
                response_msg['code']=101
                response_msg['msg']="请先登录"
            return JsonResponse(response_msg)
    

    后台

    后台界面

    django-bbs论坛总结_第16张图片

    添加文章界面

    django-bbs论坛总结_第17张图片

    后台添加文章前端代码
        <form action="" method="post" enctype="multipart/form-data">
        {% csrf_token %}
            <p>添加文章p>
            <p>标题p>
            <input type="text" class="form-control" name="title">
            <p>摘要p>
            <input type="text" class="form-control" name="desc">
            <p>内容(kindeditor编辑器编辑器,支持拖放/粘贴上传图片)p>
            <p><textarea name="content" id="id_content" cols="80" rows="10">textarea>p>
            <p><input type="submit" value="发布" class="btn btn-primary">p>
    
        form>
    
    kindeditor编辑器使用
    <script charset="utf-8" src="/static/kindeditor/kindeditor-all-min.js"></script>
        <script>
            KindEditor.ready(function (K) {
                window.editor = K.create('#id_content',{
                     width:'100%' ,
                    height:'400px',
                    themeType:0,
                    //上传文件路径
                    uploadJson:'/upload_img/',
                    //携带额外参数
                    extraFileUploadParams:{
                         'csrfmiddlewaretoken':"{{ csrf_token }}"
                    }
                });
            });
        </script>
    
    后台主页面后端代码
    def houtai(request):
        article=models.Article.objects.filter(blog__userinfo=request.user)
        return render(request,'houtai/houtai.html',locals())
    
    后台添加文章后端代码
    #利用bs4放置xss攻击
    from bs4 import BeautifulSoup
    def add(request):
        username=request.user.username
        blog = models.Blog.objects.filter(userinfo__username=username).first()
        if request.method=="POST":
            # print(request.POST)
            content=request.POST.get('content')
            desc=request.POST.get('desc')
            title=request.POST.get('title')
            soup=BeautifulSoup(content,'html.parser')#实例化一个对象
            tags=soup.find_all()#内容中所有的标签
            for tag in tags:
                #找到script标签
                if tag.name=='script':
                    #去掉script标签 防止xss攻击
                    tag.decompose()
    
            models.Article.objects.create(title=title, content=str(soup), desc=desc, blog=blog)
            return redirect('/houtai/')
        return render(request,'houtai/add.html',locals())
    
    kindeditor编辑器添加图片后端代码
    def upload_img(request):
        #这是官方文档固定格式
        # // 成功时
        # {
        #     "error": 0,
        #     "url": "http://www.example.com/path/to/file.ext"
        # }
        # // 失败时
        # {
        #     "error": 1,
        #     "message": "错误信息"
        # }
        response_msg={'error':'','message':''}
        if request.method=='POST':
            file_obj=request.FILES.get('imgFile')
            if file_obj:
                path=os.path.join(settings.BASE_DIR,'media','article_img')
                if not os.path.exists(path):
                    os.mkdir(path)
                file_path=os.path.join(path,file_obj.name)
                with open(file_path,'wb') as f:
                    for line in file_obj:
                        f.write(line)
    
                response_msg['error'] = 0
                response_msg['url'] = '/media/article_img/%s' % file_obj.name
            else:
                response_msg['error'] = 1
                response_msg['message'] = '文件不存在'
            return JsonResponse(response_msg)
        return HttpResponse(123)
    

    你可能感兴趣的:(django-bbs论坛总结)