zoukankan      html  css  js  c++  java
  • python小打小闹之简陋版BBS

      闲的蛋疼,索性写个东西玩,于是,写个类似于BBS的念头就开始了。

      我们考虑到需要实现的功能:

        1 只有登陆的用户才可以点赞,如果没有登陆,那么不可以点赞,点赞次数只可以为1。

        2 只有登陆的用户可以评论文章,其他用户也可通过回复其他人的评论。

        3 评论之间有多级嵌套关系,不是单独存在的,比我评论文章A,别人在我的评论基础上再评论我的评论,那么我的评论和别人评论我的评论之间存在一层关系。

        4 用户可以增删改查自己的文章,可以搜索自己的文章。文章包含三种状态,发布,草稿,隐藏。

        5 每篇文章需要显示发布日期,发布人,点赞次数,评论次数,在首页展示的时候能够图文并茂展示,通过文章优先级来让部分文章置顶显示。

        6 文章要有归属模块,页面展示出板块

        7 and so on ...

      我个人觉得只要实现上述功能,BBS的雏形就出来了。那么开工吧。

      所需要的知识:

          1 django+python

          2 js

          3 jinja

      =================================================================================================

      首先这个毫无疑问使用的Django 作为我的web frame。

      第一要解决的是数据库关系,此时我拿Django默认的sqilite作为我的数据库,数据库关系我的想法是:

        文章表:用户名(外键关联用户表), 发布时间,修改时间,状态,文章内容,文章归属模块,内容简介,优先级,文章头像

        评论表:评论时间,是点赞还是评论,评论内容,归属哪篇文章(关键文章表),父籍评论ID

        版块表:名字,简介,置顶文章,版块位置。

        用户表: 关联Django系统自带的用户,用户名。

      数据库建表关系解决 后,那就初始化,数据库。。。。。。。。

      代码我在此我就简单说说几点:

        1 点赞次数限制:

          说到点赞,我们采用三个值来确定这个用户是否点赞过一次了,文章ID+用户ID+当前点赞次数

          我们在评论表存储这个用户点赞次数的时候,连同用户ID一块存储进去,所以我们单单过滤这个表就可以了。

          前端代码:

     <script src="/static/bootstrap/js/jquery-2.1.4.js"></script>
        <script>
            //获取点赞数的函数
            function Get_Praise(article_id,ele){
                $.get("{% url "post_comment" %}",
                        {'id':article_id,'choice':2}, //紧跟的是参数
                        function (data) {
                            $(ele).html('&nbsp;'+data)
                        }
                )
            }
            //提交点赞请求
            function click_praise(ele){
                var article_id = $(ele).siblings().first().attr('article_id');
                var GetCsrf = $("input[name='csrfmiddlewaretoken']").val();
                // begin post
                $.post("{% url 'post_comment' %}",
                        {
                            'comment_type':2,
                            'article':article_id,
                            'user':'{{ request.user.userprofile.id }}',
                            'csrfmiddlewaretoken': GetCsrf,
                        }, //end post
                        function(callback){
                   // 如果返回来的参数是limit说明这个用户被限制点赞了,因为点赞次数超过1次了
    if(callback=='error'){ alert('点赞失败,可能是网络问题导致的') }else if(callback=='limit'){ alert('您已经点赞过一次了,请勿重复点赞!!') } else{ Get_Praise(article_id,ele) } } ) }

          后端代码,   

    praise_obj = models.Article.objects.filter(id=article_id)
    for pb in praise_obj:
            # 通过反向查询,来获取comment表里面的内容,表后面必须紧接着 _set !
            pb_obj = pb.comment_set.select_related()
            # get the praise's number,and count that!
            praise = pb_obj.filter(comment_type=comment_type).count()
    return HttpResponse(praise)

      

         2 只有可以登陆才可以评论,并且在评论框中点击登陆,登陆成功后自动跳转到刚才的页面,跳转的关键点在于?next,通过这个我们后端可以让用户重定向到next指定的页面:

          前端代码展示:

            <div class="comment-box">
                {% if request.user.is_authenticated %}
                     <textarea class="form-control" rows="3"></textarea>
                        {% csrf_token %}
                     <button type="button" style="margin-top: 10px" class="btn btn-success pull-right">评论</button>
                {% else %}
                    <div class="jumbotron">
    <h4 class="text-center"><a class="btn-link" href="{% url 'login' %}?next={{ request.path }}">登录</a>后评论</h4> </div> {% endif %} </div>

          后端代码展示:

     if request.method == 'POST':
            user = authenticate(username=request.POST.get('username'),
                                password=request.POST.get('password'))
            if user is not None:
                #pass authentication
                login(request,user)
                return HttpResponseRedirect(request.GET.get('next') or '/bbs')

         3 评论多级嵌套关系:

          公司事今天有点多,今晚再弄,

        4 用户新建一篇自己的文章,通过form来创建表单

          前端代码如下:

     <form  class="form-horizontal"  method="post"  enctype="multipart/form-data">{% csrf_token %}
                <div class="form-group">
              // 遍历form的值。
                    {% for info in article %}
                        {% if info.field.required %}
                            <label style="font-size: larger">{{ info.label }}*</label></br>
                        {% else %}
                            {{ info.label }}</br>
                        {% endif %}
                            {{info}}</br>
                    {% endfor %}
                <input name="author" style="display: none;" value="{{ request.user.userprofile.id }}">
                </div>
                <div class="col-sm-11">
                    <input type="submit"  class="btn btn-primary " value="Save">
                   <a href="/person_zone/{{ request.user.userprofile.id }}"  class="btn btn-danger">Cancel</a>
                </div>
                </form>
    {% block bottom-js %}
        <script src="/static/bootstrap/js/jquery-2.1.4.js"></script>
        <script>
            $(document).ready(function () {
                window.resizeTo(10,70)
            })
        </script>
        <script src="/static/ckeditor/ckeditor.js"></script>
        <script type="text/javascript">
        // 调用的第三方编辑器,会自动把在id_content里面替换成编辑器,而这个id_content是form里面在渲染html页面的时候自动带出来的
    
                CKEDITOR.replace('id_content')
        </script>
    {% endblock %}
    View Code

          后端代码如下:

    def add_article(request):
        '''
        除了添加文章的方法
        :param request:
        :return:
        '''
        import datetime
        errors = None
        article_list = forms.get_form(models.Article)
        if request.method == 'POST':
            article_form = forms.get_form(models.Article,request.POST,request.FILES)
            if article_form.is_valid():
                data =  article_form.cleaned_data
                data['author_id'] = request.user.userprofile.id
                if data['status'] == "published":
                    data['pub_date'] == datetime.datetime.now()
    
                article_obj = models.Article(**data)
                article_obj.save()
                return HttpResponseRedirect('/bbs/')
    
            else:
                 errors = '输入的信息不完整或者错误,不符合格式。'
    
        return render(request,'BBS/add_article.html',{'article':article_list,
                                                      'category_list':category_list,
                                                      'errors':errors,
                                                      'title_of_page':u'写一篇新文章'})
    View Code

        5 改查自己的文章(删除动作忘记写了)

          前端代码:

    # 其实还是调用之前新写一篇文章的的页面,我只是把内容给填充到里面去了,一举多得,哈哈。
    <form  class="form-horizontal"  method="post"  enctype="multipart/form-data">{% csrf_token %}
                <div class="form-group">
              // 遍历form的值。
                    {% for info in article %}
                        {% if info.field.required %}
                            <label style="font-size: larger">{{ info.label }}*</label></br>
                        {% else %}
                            {{ info.label }}</br>
                        {% endif %}
                            {{info}}</br>
                    {% endfor %}
                <input name="author" style="display: none;" value="{{ request.user.userprofile.id }}">
                </div>
                <div class="col-sm-11">
                    <input type="submit"  class="btn btn-primary " value="Save">
                   <a href="/person_zone/{{ request.user.userprofile.id }}"  class="btn btn-danger">Cancel</a>
                </div>
                </form>
    {% block bottom-js %}
        <script src="/static/bootstrap/js/jquery-2.1.4.js"></script>
        <script>
            $(document).ready(function () {
                window.resizeTo(10,70)
            })
        </script>
        <script src="/static/ckeditor/ckeditor.js"></script>
        <script type="text/javascript">
        // 调用的第三方编辑器,会自动把在id_content里面替换成编辑器,而这个id_content是form里面在渲染html页面的时候自动带出来的
    
                CKEDITOR.replace('id_content')
        </script>
    {% endblock %}
    View Code

          后端代码:

    def article_modify(request,article_id):
        '''
        更改文章/博客内容的方法
        :param request:
        :param article_id: 文章ID
        :return: 网页
        '''
        article_id_obj = models.Article.objects.get(id=article_id)
       # get_form实际是上我form里的一个装饰器,  
        form = forms.get_form(models.Article,instance=article_id_obj)
        if request.method == 'POST':
            form = forms.get_form(models.Article,request.POST,instance=article_id_obj)
            if form.is_valid():
                form.save()
                return HttpResponseRedirect('/person_zone/%s'%(request.user.userprofile.id))
        return render(request,'BBS/add_article.html',{'category_list':category_list,
                                                      'title_of_page':u'修改文章信息',
                                                      'article':form,})
    View Code

        6 在首页显示文章具体详情,通过我们在前端展现一个板块的时候,我们当前的办搬砖:

          前端代码:

    {% extends 'base.html' %}
    {% load  customer_tag %}
    {% load for_bbs %}
    {% block page-container %}
        <div class="">
            {% for article in article_list %}
                {% csrf_token  %}
                <div class="article-box row">
                    <div class="article-head-img col-md-4">
                        <img class="article-head-img" src="/static/{{ article.head_img|truncate_url }}" >
                    </div>
                    <div class="article-brief col-md-8">
                        <a class="article-title" href="{% url 'article_detail' article.id %}">
                            {{ article.title }}<br/>
                        </a>
                        <div class="article-brief-info">
                            <span  style="display: none;"  article_id="{{ article.id }}"></span>
                            <span>{{ article.author.name }}&nbsp;</span>
                            <span>{{ article.pub_date }} &nbsp;&nbsp;</span>
                            <span>{%  filter_comment article as comments %} </span>
                            <span class="glyphicon glyphicon-comment" aria-hidden="true"></span>
                               {{ comments.comment_count }}
                            &nbsp;<a href="" style='text-decoration:none;' onclick="click_praise(this)"
                                class="glyphicon glyphicon-thumbs-up" aria-hidden="true">
                               {{ comments.thumb_count }}</a>
                        </div>
                        <div class="article-brief-text">
                            <p>{{ article.brief }}</p>
                        </div>
                    </div>
                </div>
                <hr>
            {% endfor %}
        </div>
            <nav>
            <ul style="" class="pagination">
                {% if article_list.has_previous %}
                    <li class=""><a href="?page={{ article_list.previous_page_number }}" aria-label="Previous">
                        <span aria-hidden="true">&laquo;</span></a></li>
                {% endif %}
                      {% for page_num in article_list.paginator.page_range %}
                          {% guess_page article_list.number page_num %}
                      {% endfor %}
                {% if article_list.has_next %}
                    <li class="">
                        <a href="?page={{ article_list.next_page_number }}" aria-label="Previous">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                {% endif %}
            </ul>
    
        </nav>
        <div class="wrap-right">
        </div>
        <div class="clear-both"></div>
    
    {% endblock %}
    
    {% block bottom-js %}
        <script src="/static/bootstrap/js/jquery-2.1.4.js"></script>
        <script>
            //获取点赞数的函数
            function Get_Praise(article_id,ele){
                $.get("{% url "post_comment" %}",
                        {'id':article_id,'choice':2}, //紧跟的是参数
                        function (data) {
                            $(ele).html('&nbsp;'+data)
                        }
                )
            }
    
            //提交点赞请求
            function click_praise(ele){
                var article_id = $(ele).siblings().first().attr('article_id');
                var GetCsrf = $("input[name='csrfmiddlewaretoken']").val();
                // begin post
                $.post("{% url 'post_comment' %}",
                        {
                            'comment_type':2,
                            'article':article_id,
                            'user':'{{ request.user.userprofile.id }}',
                            'csrfmiddlewaretoken': GetCsrf,
                        }, //end post
                        function(callback){
                            if(callback=='error'){
                                alert('点赞失败,可能是网络问题导致的')
                            }else if(callback=='limit'){
                                alert('您已经点赞过一次了,请勿重复点赞!!')
                            } else{
                                Get_Praise(article_id,ele)
                            }
                        }
                )
            }
        </script>
    {% endblock %}
    View Code

          后端代码:

    def category(request,category_id=4):
        '''
        展示页面顶部模块的名字.
        :param request:
        :param category_id:
        :return:
        '''
        category_obj = models.Category.objects.get(id=category_id)
        if category_obj.position_index == 1: # 1 表示是首页
            article_list = models.Article.objects.filter(status='published')
        else:
            article_list = models.Article.objects.filter(category_id=category_obj.id,status='published')
    
        article_list = paginate(request,article_list)   # 分页方法处理下,使其返回前台是分页的!
        return render(request,'bbs/index.html',{'category_list':category_list,
                                                'category_obj':category_obj,
                                                'article_list':article_list})
    View Code

      好了,上面的代码差不多就实现了基础的功能,具体的代码细节,可以看本人的github,哈哈,as python newber , you can pratice python+Django+js+jinja by make BBS!! 

  • 相关阅读:
    PHP session
    PHP范例注册审核
    php文件操作
    JSON 弹窗
    PDO
    CSP-S2020 游记
    Meissel-Lehmer算法 学习笔记
    [AGC046C] Shift 题解
    Min_25筛学习笔记
    GDOI2020 游记
  • 原文地址:https://www.cnblogs.com/liaojiafa/p/5638767.html
Copyright © 2011-2022 走看看