Django实现文章按年月归档、点赞和评论、发送邮件

文章归档的实现

我们在创建文章时,会在数据库中存储文章创建的时间这样的字段,一般用的都是datetime类型,记录文章创建的年月日和时分秒,所以我们直接使用文章的创建时间分类是无法实现文章的按年月归档的,因为每一篇文章的时间是不一样的,所以我们在使用ORM查询时就无法做到按年月分类的需求,这是就需要额外的SQL语句来实现,在SQL语句中有一个很重的时间格式化的方法:date_format

  我们可以使用ORM中执行SQL语句原生用法的方法:extra

from blog import models
from django.db.models import Count
#假设我们得到一个user对象    文章表中有一个create_time 字段
achive = models.Article.objects.filter(user=user).extra(
       select={"archive":"date_format(create_time,'%%Y-%%m')"  }         
).values("archive").annotate(c=Count('pk')).values("archive","c")

#"pk" 在Django中代指表的主键

urls.py的配置

from django.conf.urls import url
from blog import views

urlpatterns = [
    url(r'^(w+)/archive/(.+)/$',views.home),

]

views.py

                try:
                    year, mouth = args[1].split('-')
                    logger.debug('年:{}    月:{}'.format(year, mouth))
                    article_list = models.Article.objects.filter(user=user).filter(create_time__year=year,
                                                                                   create_time__month=mouth)
                except Exception as e:
                    logger.error(str(e))
                    return HttpResponse('404')

备注:使用Django时,默认使用的UTC时间,而中国的时区为东八区,所以会在查询时间时带上一个+8的字样,所以通过fliter查找字段时,直接等于year或者month是无法查出需要的对象的,这是我们需要在settings.py文件中,修改一个参数:USE_TZ = True  改为False 就可以了。

点赞的实现

点赞部分的HTML实现

    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit">
                <span class="diggnum" id="digg_count">{{ article.up_count }}</span>
            </div>
            <div class="buryit">
                <span class="burynum" id="bury_count">{{ article.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color: red;"></div>
        </div>
    </div>
// 备注;如果js的实现是作为一个静态文件导入时,需要在HTML页面中隐藏一个标签,这个标签存储我们在静态文件中需要的值
<div class="info" article_id="{{ article.pk }}" username="{{ request.user.username }}" style="display: none"></div>
 

备注:在bootstarp中会自带一个清除父标签塌陷的样式类方法  (class="clearfix")

点赞的相关css样式

#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url('/static/img/upup.gif') no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url('/static/img/downdown.gif') no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.clear {
    clear: both;
}
点赞效果实现的相关css样式

 

点赞帮点事件并发ajax请求

$("#div_digg .action").click(function () {
    if ($(".info").attr("username")) {


        // 点赞或踩灭   通过判断有无某个样式类来区分是点赞还是踩,以点赞中的diggit样式类参考,如果为点赞,则返回true,为踩,返回false
        var is_up = $(this).hasClass("diggit");
        var article_id = $(".info").attr("article_id");

        $.ajax({
            url: "/blog/up_down/",
            type: "post",
            data: {
                is_up: is_up,
                article_id: article_id,
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
            },
            success: function (data) {
                // console.log(data);
                if (data.state) {// 对当前文章首次赞或者灭成功

                    if (is_up) {
                        var val = $("#digg_count").text();
                        val = parseInt(val) + 1;
                        $("#digg_count").text(val);
                    } else {
                        var val = $("#bury_count").text();
                        val = parseInt(val) + 1;
                        $("#bury_count").text(val);
                    }
                }
                else {    // 重复提交

                    if (data.fisrt_action) {
                        $("#digg_tips").html("您已经推荐过");
                    } else {
                        $("#digg_tips").html("您已经反对过");
                    }

                    setTimeout(function () {
                        $("#digg_tips").html("")
                    }, 1000)
                }
            }
        })
    }
    else {
        // 没有登录  就跳转登录
        location.href = "/login/"
    }

});
静态文件版

 

点赞urls.py (ajax请求相关)

from django.conf.urls import url
from blog import views


urlpatterns = [
    url(r"up_down/",views.up_down),
]

 

点赞处理ajax请求的视图函数

def up_down(request):
    article_id=request.POST.get('article_id')
    is_up=json.loads(request.POST.get('is_up'))
    user=request.user
    response={"state":True}
    try:
        models.ArticleUpDown.objects.create(user=user,article_id=article_id,is_up=is_up)
        models.Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
    except Exception as e:
        response["state"]=False
        response["fisrt_action"]=models.ArticleUpDown.objects.filter(user=user,article_id=article_id).first().is_up
    return JsonResponse(response)

评论的实现

评论树和评论楼两种方式:

 

评论的相关路由

from django.conf.urls import url
from blog import views


urlpatterns = [
    url(r"comment/",views.comment),
    url(r"comment_tree/(d+)/",views.comment_tree),
]

 

评论的相关视图函数

def comment(request):

    print(request.POST)

    pid=request.POST.get("pid")
    article_id=request.POST.get("article_id")
    content=request.POST.get("content")
    user_pk=request.user.pk
    response={}
    if not pid:  #根评论
        comment_obj=models.Comment.objects.create(article_id=article_id,user_id=user_pk,content=content)
    else:
        comment_obj=models.Comment.objects.create(article_id=article_id,user_id=user_pk,content=content,parent_comment_id=pid)

    response["create_time"]=comment_obj.create_time.strftime("%Y-%m-%d")
    response["content"]=comment_obj.content
    response["username"]=comment_obj.user.username

    return JsonResponse(response)




def comment_tree(request,article_id):

    ret=list(models.Comment.objects.filter(article_id=article_id).values("pk","content","parent_comment_id"))
    print(ret)
    return JsonResponse(ret,safe=False)

 

评论的HTML相关

    <p>评论树</p>

    <div class="comment_tree">
        // 评论树内容相关
        
    </div>
    <hr>
    
    
    <p>评论楼</p>
    <p>评论列表</p>
    <ul class="comment_list">
        {% for comment in comment_list %}
            <li class="list-group-item">
                <div>
                    <a href="">#{{ forloop.counter }}楼</a> &nbsp;&nbsp;
                    <span style="color: gray">{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                    <a href=""><span>{{ comment.user.username }}</span></a>
                    <a class="pull-right reply_btn" username="{{ comment.user.username }}"
                       comment_pk="{{ comment.pk }}"><span>回复</span></a>
                </div>
                {% if comment.parent_comment_id %}
                    <div class="pid_info well">
                        <p> {{ comment.parent_comment.user.username }}:
                            &nbsp;&nbsp;&nbsp;{{ comment.parent_comment.content }} </p>
                    </div>
                {% endif %}

                <div class="con">
                    <p>
                        {{ comment.content }}
                    </p>
                </div>
            </li>
        {% endfor %}
    </ul>

    {% if request.user.username %}
        <div class="div_comment">
            <p>昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                         value="{{ request.user.username }}"></p>
            <p>评论内容</p>
            <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            <p>
                <button id="comment_btn">提交评论</button>
            </p>

        </div>
    {% else %}
        <a href="/login/">登录</a>
    {% endif %}

 

评论的js实现

<script>
        // 获取评论数据,展示评论树结构
        $.ajax({
            url: "/blog/comment_tree/" + '{{ article.pk }}/',
            success: function (data) {
                console.log(data);

                $.each(data, function (index, comment_dict) {
                    var s = '<div class="comment_item" comment_id=' + comment_dict.pk + '> <span class="content">' + comment_dict.content + '</span> </div>'
                    if (comment_dict.parent_comment_id) {
                        // 子评论
                        var perid=comment_dict.parent_comment_id;
                        $("[comment_id="+perid+"]").append(s);
                    }
                    else {   //  根评论
                        $(".comment_tree").append(s);
                    }
                })


            }
        });


        // 提交评论
        var pid = "";
        $("#comment_btn").click(function () {

            var article_id = $(".info").attr("article_id");
            var content = $("#comment_content").val();
            if (pid) {
                var index = content.indexOf("
");
                content = content.slice(index + 1)
            }


            $.ajax({
                url: "/blog/comment/",
                type: "post",
                data: {
                    article_id: article_id,
                    content: content,
                    pid: pid,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var content = data.content;
                    var username = data.username;
             if (arg.status){
         // 是根评论
var comment_li = '<li class="list-group-item"><div><span style="color: gray">' + create_time

            + '</span> &nbsp;&nbsp; <a href=""><span>' + username + '</span></a></div> <div class="con">
            <p> ' + content + ' </p> </div> </li>'; $(".comment_list").append(comment_li);
            }else{
          // 是子评论
          var parent_name = arg.parent_username;
          var par_content = arg.parent_content;
          var m = '<li class="list-group-item"><div><span>' + create_time + '&nbsp;&nbsp;</span><span>' +
        username + '&nbsp;&nbsp;</span>' + '</div><div class="well">'+parent_name+':'
              +par_content+'</div><div>' + content + '</div></li>';
        $(".list-group").append(m);
          }
            // 清空文本框 $("#comment_content").val('');
            
// 清空pid pid = ""
            }
        })
    });
// 回复按钮事件
$(
".list-group-item .reply_btn").click(function () {
$(
"#comment_content").focus();
var v = "@" + $(this).attr("username") + " "; $("#comment_content").val(v);

//pid赋值 pid = $(this).attr("comment_pk") })

</script>

 

另外Django中也提供了发送邮件的方法,不需要我们直接使用email模块

from django.core.mail import send_mail

 

Django实现发邮件

1 首先去自己的邮箱申请,在设置里面找,申请开通smtp服务,我用的是163邮箱

 

2 在项目下settings.py中添加设置:

复制代码
 1 # 配置邮箱发邮件的相关功能
 2 
 3 #这一项是固定的
 4 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
 5 # smtp服务的邮箱服务器 我用的是163
 6 EMAIL_HOST = 'smtp.163.com'
 7 # smtp服务固定的端口是25
 8 EMAIL_PORT = 25
 9 #发送邮件的邮箱
10 EMAIL_HOST_USER = 'xxxx@163.com'
11 #在邮箱中设置的客户端授权密码
12 EMAIL_HOST_PASSWORD = 'xxxx'
13 #收件人看到的发件人 <此处要和发送邮件的邮箱相同>
14 EMAIL_FROM = 'python<xxxx@163.com>'
复制代码

 

3 配置好映射urls.py, 创建好视图,.... 这些步骤省略了.....找到相应视图后

4 在视图中调用如下函数 即可发送邮件:

复制代码
 1 from django.conf import settings
 2 from django.core.mail import send_mail
 3 from django.http import HttpResponse
 4 ...
 5 def send(request):
 6     msg='<a href="哈哈哈" target="_blank">点击激活</a>'
 7     send_mail('标题','内容',settings.EMAIL_FROM,
 8               '目标邮箱',
 9               html_message=msg)
10     return HttpResponse('ok')
复制代码

注意要 导入 settings模块,和send_email模块

调用send_mail() 函数即发送邮件,具体参数如下

send_mail( 标题,文字内容,发件邮箱,目的邮箱,html标签内容 )

原文地址:https://www.cnblogs.com/zhaopanpan/p/9096695.html