闲的蛋疼,索性写个东西玩,于是,写个类似于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 %}

      后端代码如下:

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'写一篇新文章'})

    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 %}

      后端代码:

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,})

    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 %}

      后端代码:

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})

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

python小打小闹之简陋版BBS的更多相关文章

  1. Python写的简陋版一对一聊天工具,全双工

    好该睡觉了,明天还要上班~~~直接上代码,后面再总结 import threading import os import socket def RecvProcess ( UDP_Socket, Lo ...

  2. flask 第七章 简陋版智能玩具 +MongoDB初识和基本操作

    1.简陋版web智能玩具 FAQ.py文件 import os from aip import AipSpeech, AipNlp from uuid import uuid4 "" ...

  3. 笨办法学 Python (第三版)(转载)

    笨办法学 Python (第三版) 原文地址:http://blog.sina.com.cn/s/blog_72b8298001019xg8.html   摘自https://learn-python ...

  4. Python之路,Day4 - Python基础4 (new版)

    Python之路,Day4 - Python基础4 (new版)   本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...

  5. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  6. [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source …

    [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source - [Pyth ...

  7. 目前比较流行的Python科学计算发行版

    经常有身边的学友问到用什么Python发行版比较好? 其实目前比较流行的Python科学计算发行版,主要有这么几个: Python(x,y) GUI基于PyQt,曾经是功能最全也是最强大的,而且是Wi ...

  8. 《OpenCV3 计算机视觉--Python语言实现 第二版》源代码及纠错

    1.源代码下载地址 <OpenCV3 计算机视觉--Python语言实现 第二版>由我们翻译,英文书名<Learning OpenCV3 Computer Vision with P ...

  9. 利用Python进行数据分析(第二版)电子版书籍分享

    资料下载地址: 链接:https://pan.baidu.com/s/1y1C0bJPkSn7Sv6Eq9G5_Ug 提取码:vscu <利用Python进行数据分析(第二版)>高清中文版 ...

随机推荐

  1. 对react的几点质疑

    现在react.js如火如荼,非常火爆,昨天抽了一天来看了下这项技术.可能就看了一天,研究的不深入,但是我在看的过程中发现来了很多疑惑,这里拿出来和那家分享讨论以此共勉. 在我接触的前端以后,让我感觉 ...

  2. 以HTML为表现的日志记录组件

    日志搬家:http://www.loogn.net/blog/Article.aspx?id=21 关于日志记录,如果你不想随用随写,又不想用log4net的话,也许你可以了解一下这个! 我也是个很懒 ...

  3. 基于DDS的任意波形发生器

    实验原理 DDS的原理 DDS(Direct Digital Frequency Synthesizer)直接数字频率合成器,也可叫DDFS. DDS是从相位的概念直接合成所需波形的一种频率合成技术. ...

  4. WinForm 问题集锦

    [1]重用项目窗体解决方案: 1. 把FmMain.cs 和 FmMain.Designer.cs 和 FmMain .resx 三个文件复制到程序目录下: 2. 在vs里面添加现有项, 选择FmMa ...

  5. 记一次在Eclipse中用Axis生成webservice服务端的过程中出现的问题

    问题一. Unable to find config file.  Creating new servlet engine config file: /WEB-INF/server-config.ws ...

  6. JavaScript数独求解器

    <html> <head> <style type="text/css"> .txt { width: 50; height: 50; back ...

  7. RabbitMQ官方中文入门教程(PHP版) 第三部分:发布/订阅(Publish/Subscribe)

    发布/订阅 在上篇教程中,我们搭建了一个工作队列.每个任务之分发给一个工作者(worker).在本篇教程中,我们要做的之前完全不一样——分发一个消息给多个消费者(consumers).这种模式被称为“ ...

  8. Java网络编程——概述

    一.网络模型 OSI七层模型 应用层 表示层 会话层 传输层: 网络层: 链路层 物理层:比特流 TCP/IP四层模型 应用层 传输层:数据包,TCP/UDP 网络层:数据帧 物理层:比特流 二.网络 ...

  9. Shell命令_文件系统常用命令df、du

    一.df(文件系统查看命令) [root@localhost ~]# df [选项] [挂载点] 选项: -a 显示所有的文件系统信息,包括特殊文件系统,如 /proc. /sysfs -h 使用习惯 ...

  10. 【POJ 1151】Atlantis

    离散化后扫描线扫一遍. 夏令营时gty学长就讲过扫描线,可惜当时too naive,知道现在才写出模板题. 当时也不会线段树啊233 #include<cstdio> #include&l ...