Python Django 功能模块

Python Django模块

Django模块,是针对有django基础,对django功能进行模块化,方便下次使用。

一、注册模块

该注册采用邮箱验证,注册成功后会发送激活链接到邮箱。

邮箱验证参考

 

1.数据库设计

from django.db import models

# Create your models here.

class UserInfo(models.Model):
     status_choices = (
          (0, '未激活'),
          (1, '激活'),
     )

     username = models.CharField(verbose_name='用户名',max_length=32,db_index=True)    # db_index = True 创建索引
     email = models.EmailField(verbose_name="邮箱",max_length=32)
     mobile_phone = models.CharField(verbose_name="手机号",max_length=11)
     password = models.CharField(verbose_name="密码",max_length=32)
     status = models.SmallIntegerField(verbose_name='账户激活状态', default=0, choices=status_choices)

     def __str__(self):
         return self.username

2.配置url

urlpatterns = [
    # 注册模块
    url(r'^index/$', index.index,name='index'),
    # 图片验证码
    url(r'^image/code/$', index.image_code, name='image_code'),
    # 邮箱验证
    url(r'^active/(?P<token>.*)$', index.activation,name='active'),
]

3.form组件设计

通过form主键生成HTML 的 Form标签

from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError

from app01 import models
from utils import encrypt # md5加密模块(对密码进行加密)

class RegisterForm(forms.ModelForm):
    password = forms.CharField(
        label='密码',
        widget=forms.PasswordInput(),
        min_length=8,
        max_length=32,
        error_messages={
            'min_length':"密码长度不能小于8个字符",
            'max_length':"密码长度不能大于32个字符"
        }
    )

    confirm_password = forms.CharField(
        label='确认密码',
        widget=forms.PasswordInput(),
        min_length=8,
        max_length=32,
        error_messages={
            'min_length':"密码长度不能小于8个字符",
            'max_length':"密码长度不能大于32个字符"
        }
    )

    mobile_phone = forms.CharField(
        label="手机号",
        validators=[
            RegexValidator(r'^1[3-9]\d{9}','手机号格式不正确')
        ]
    )

    code = forms.CharField(label='图片验证码', widget=forms.TextInput())

    class Meta:
        model = models.UserInfo
        fields = [
            'username',
            'mobile_phone',
            'email',
            'password',
            'confirm_password',
            'code'
        ]

    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
        for name,field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)


    """
    验证规则
    通过钩子对提交的数据进行验证
    """
    def clean_code(self):
        """钩子 图片验证码"""
        # 读取用户输入的验证码
        code = self.cleaned_data['code']

        # 在session获取图片验证码
        session_code = self.request.session.get('image_code')
        if not session_code:
            raise ValidationError("验证码已过期,请重新获取")

        if code.upper().strip() != session_code.upper().strip():    # upper()小写
            raise ValidationError("验证码输入错误")

        return code


    def clean_username(self):
        """用户名验证"""
        username = self.cleaned_data['username']

        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')

        return username

    def clean_email(self):
        """邮箱验证"""
        email = self.cleaned_data['email']

        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')

        return email

    def clean_password(self):
   		"""返回加密后的密码"""
        pwd = self.cleaned_data['password']

        return encrypt.md5(pwd)

    def clean_confirm_password(self):
        """确认密码验证"""
        pwd = self.cleaned_data['password']
        confirm_pwd = encrypt.md5(self.cleaned_data['confirm_password'])

        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')

        return confirm_pwd

    def clean_mobile_phone(self):
        """手机号验证码"""
        mobile_phone = self.cleaned_data['mobile_phone']

        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已存在')

        return mobile_phone

 

4.视图函数

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from django.core.mail import send_mail


from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired

from django.conf import settings

from app01.forms.account import RegisterForm # form组件
from app01 import models

def index(request):
	""" 注册 """
    if request.method == "GET":
        form = RegisterForm(request)
        return render(request,'register.html',{'form':form,'title':'注册','data':{'href':'/login','pageName':'登录'}})

    form = RegisterForm(request,data=request.POST)
    if form.is_valid():
        instance = form.save()


        # 发送激活邮件,包含激活链接:http://127.0.0.1:8000/user/active/1
        # 激活链接包含用户的身份信息 并且身份信息进行加密
        # 加密用户的身份信息,生成激活token
        serializer = Serializer(settings.SECRET_KEY, 3600)
        info = {'confirm': instance.id}
        token = serializer.dumps(info)  # 加密 bytes
        token = token.decode('utf-8')  # bytes转为字符串

        # 发邮件(同步发送 延迟会阻塞)
        subject = '注册信息'
        message = ''
        sender = settings.EMAIL_FROM  # 发件人
        receiver = [instance.email]  # 收件人列表
        html_message = '<h1>欢迎您注册</h1>请点击下面链接激活您的用户<br><a href="http://127.0.0.1:8000/active/%s">http://127.0.0.1:8000/active/%s</a>' % (
        token, token)
        send_mail(subject, message, sender, receiver, html_message=html_message)

        return JsonResponse({'status': True, 'data': "邮件发送成功,请注意接收"})

    return JsonResponse({'status': False, 'error': form.errors})


def image_code(request):
    """生成图片验证码"""
    from io import BytesIO
    from utils.image_code import check_code # 生成图片验证码
    img_obj, code = check_code()	# 返回图片对象,验证码

    request.session['image_code'] = code
    request.session.set_expiry(60)  # 主动修改session的值过期时间为60秒

    """ 将图片内容写到内存中 """
    stream = BytesIO()
    img_obj.save(stream, 'png')

    return HttpResponse(stream.getvalue())



def activation(request,token):
    """进行用户激活"""
    # 进行解密,获取要激活的用户信息
    serializer = Serializer(settings.SECRET_KEY, 3600)
    try:
        info = serializer.loads(token)  # 解密
        # 获取待激活用户的id
        user_id = info['confirm']
        # 根据id获取用户信息
        user = models.UserInfo.objects.get(id=user_id)
        user.status = 1
        user.save()

        # 跳转到登录页面
        return HttpResponse('邮箱激活成功')
    except SignatureExpired as e:  # 邮箱激活异常
        # 激活链接已过期
        return HttpResponse('激活链接已过期')

 

5.前端代码

{% extends 'navigation/navigation.html' %}

{% block css %}
    <style>
        .account {
            width: 400px;
            margin-top: 30px;
            margin-left: auto;
            margin-right: auto;
            border: 1px solid #f0f0f0;
            padding: 10px 30px 30px 30px;
        }

        h1 {
            text-align: center;
        }

        .error-msg{
            font-size: 10px;
            color: #721c24;
        }
    </style>
{% endblock %}

{% block content %}
    <div class="account">
        <h1>{{ title }}</h1>
        <form id="regForm" method="post" novalidate>
            {% csrf_token %}
            {% for field in form %}
                {% if field.name == 'code' %}
                    <div class="form-group">
                        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                        <div class="row">
                            <div class="col-md-7">
                                {{ field }}
                                <span class="error-msg">{{ field.errors.0 }}</span>
                            </div>
                            <div class="col-xs-5">
                                <img src="{% url 'image_code' %}" alt="" id="imageCode" title="看不清,点击更换图片">
                            </div>
                        </div>
                    </div>
                {% else %}
                    <div class="form-group">
                        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                        {{ field }}
                        <span class="error-msg">    </span>
                    </div>
                {% endif %}
            {% endfor %}
            <div>
                <div style="float: right">
                    <a href="{{ data.href }}">{{ data.pageName }}?</a>
                </div>
            </div>

            <div class="row">
                <div class="col-xs-3">
                    <input id="btnSubmit" type="button" class="btn btn-primary" value="{{ title }}"/>
                </div>
            </div>
        </form>
    </div>

{% endblock %}



{% block js %}
    <script>
        $(function () {
            bindClickImage();
            bindClickSubmit()
        });

        /*
        点击获取验证码的按钮绑定事件
        */
        function bindClickImage() {
            $('#imageCode').click(function () {
                var oldSrc = $(this).attr('src');
                $(this).attr('src', oldSrc + '?')
            })
        }

        /*
        * 注册
        * */
        function bindClickSubmit(){
            $('.error-msg').empty();
            $('#btnSubmit').click(function () {
                $.ajax({
                    url:'{% url 'index' %}',
                    type:'POST',
                    data:$("#regForm").serialize(),
                    success:function (res) {
                        if (res.status){
                            location.href = {% url 'issues' %};
                        }else {
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })
            })
        }
    </script>
{% endblock %}

 

二、登录模块

1.配置url

urlpatterns = [
    # 登录模块
    url(r'^login/$', login.login, name='login'),
]

2.form组件设计

from django import forms
from django.core.exceptions import ValidationError

from app01 import models
from utils import encrypt # MD5加密模块


class LoginForm(forms.ModelForm):
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(),
        min_length=8,
        max_length=32,
        error_messages={
            'min_length': "密码长度不能小于8个字符",
            'max_length': "密码长度不能大于32个字符"
        }
    )

    username = forms.CharField(label='邮箱或手机号')
    code = forms.CharField(label='图片验证码')

    class Meta:
        model = models.UserInfo
        fields = [
            'username',
            'password',
            'code'
        ]

    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
        for name,field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)


    def clean_password(self):
        """ 密码校验钩子,返回加密后的密码 """
        pwd = self.cleaned_data['password']
        return encrypt.md5(pwd)


    def clean_code(self):
        """图片验证码校验钩子"""
        code = self.cleaned_data['code']

        session_code =self.request.session.get('image_code')
        if not session_code:
            raise ValidationError("验证码已过期,请重新获取")

        if code.upper().strip() != session_code.upper().strip():
            raise ValidationError("验证码输入错误")

        return code

3.视图模块

from app01.forms.login import LoginForm
from app01 import models

from django.shortcuts import HttpResponse,render
from django.http import JsonResponse

def login(request):

    if request.method == 'GET':
        form = LoginForm(request)

        return render(request,'register.html',{'form':form,'title':'登录','data':{'href':'/index','pageName':'注册'}})

    form = LoginForm(request,data=request.POST)
    if form.is_valid():
        username = form.cleaned_data['username']
        pwd = form.cleaned_data['password']

        from django.db.models import Q
        user_object = models.UserInfo.objects.filter(Q(email=username) | Q(mobile_phone=username)).filter(password = pwd).first()

        if user_object:
            if user_object.status:
                request.session['username'] =user_object.username
                request.session['user_id'] = user_object.id
                request.session.set_expiry(60 * 60 * 24 * 7)
                return JsonResponse({'status': True, 'data': '登录成功'})
            else:
                form.add_error('username', '用户名未激活')
                return JsonResponse({'status': False, 'error': form.errors})

        form.add_error('username','用户名或密码错误')
    return JsonResponse({'status': False, 'error': form.errors})

4.前端代码

前端代码与注册模块的前端代码相同,只是ajax的请求路径改为登录的请求路径即可。

 

三、问题模块及评论

1.登录中间件

登录中间件用于判断用户是否登录,已经设置访问白名单,用于处理不用登录就能访问的页面。

在settings.py文件设置白名单

# 登陆白名单:无需登陆可以访问的页面 
WHITE_REGEX_URL_LIST = [
    "/login/",
    "/image/code/",
    "/index/",
    "/active/",
]

在中间件文件夹创建auth.py 文件存储登录中间件代码

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
from django.conf import settings
from app01 import models
import datetime


class Tracer(object):
    def __init__(self):
        self.user = None

class AuthMiddleware(MiddlewareMixin):

    def process_request(self, request):

        request.tracer = Tracer()

        """用户已登陆,则request中赋值"""
        user_id = request.session.get('user_id', 0)
        user_obj = models.UserInfo.objects.filter(id=user_id).first()
        request.tracer.user = user_obj

        # 白名单:没有登陆可以访问的页面
        """
        1. 获取当前用户访问的URL
        2. 检查URL是否在白名单中,如果不在,判断是否登录,没有登陆跳转到登录页面             
        """
        if request.path_info in settings.WHITE_REGEX_URL_LIST:
            return
        # 检测用户是否登录,已登录继续往下执行,未登陆返回登陆页面
        if not request.tracer.user:
            return redirect('login')

在settings.py中开启中间件

MIDDLEWARE = [
	....
    'app01.middleware.auth.AuthMiddleware'
]

 

2.数据库设置

from django.db import models

class Issues(models.Model):
    """ 问题 """
     subject = models.CharField(verbose_name="主题", max_length=32)
     desc = models.TextField(verbose_name="问题描述")
     creator = models.ForeignKey(verbose_name='创建者', to="UserInfo", related_name='create_problems')
     reply_num = models.IntegerField(verbose_name='回复人数',default=0)
     create_datetime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)



class Discuss(models.Model):
     """ 讨论 """
     issues = models.ForeignKey(verbose_name='问题', to='Issues')
     content = models.TextField(verbose_name="内容")
     creator = models.ForeignKey(verbose_name="创建者",to="UserInfo",related_name="create_discuss")
     create_datetime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
     reply = models.ForeignKey(verbose_name='回复',to='self',null=True,blank=True)

 

3.配置url

urlpatterns = [
	....
    # 评论模块
    url(r'^issues/$',discuss.issues,name='issues'),
    url(r'^issues/discuss_page/(?P<issues_id>\d+)$',discuss.discuss_page,name='discuss_page'),
    url(r'^issues/discuss/(?P<issues_id>\d+)$',discuss.discuss,name='discuss')

]

 

 

3.form组件设计

from django import forms
from app01 import models

class IssuesModelForm(forms.ModelForm):
    """问题form组件"""
    class Meta:
        model = models.Issues
        fields = ['subject', 'desc']

    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
        for name,field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)

class DiscussModelForm(forms.ModelForm):
    """评论form组件"""
    class Meta:
        model = models.Discuss
        fields = ['content','reply']

 

4.视图函数

from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt

from app01.forms.issues import IssuesModelForm,DiscussModelForm
from app01 import models

def issues(request):
    """问题模块"""
    if request.method == "GET":
        form = IssuesModelForm(request)
        issues_obj_list = models.Issues.objects.filter()
        print(issues_obj_list)
        context = {
            'form':form,
            'issues_obj_list': issues_obj_list,
        }
        return render(request,'issues.html',context)
    form = IssuesModelForm(request,data=request.POST)
    if form.is_valid():
        form.instance.creator = request.tracer.user
        form.save()
        return JsonResponse({'status':True})
    return JsonResponse({'status': False, 'error': form.errors})


def discuss(request,issues_id):
    """评论内容获取"""
    reply_list = models.Discuss.objects.filter(issues_id=issues_id)
    data_list = []
    for item in reply_list:
        data = {
            'id':item.id,
            'content':item.content,
            'creator':item.creator.username,
            'datetime': item.create_datetime.strftime('%Y-%m-%m %H:%M'),
            'parent_id': item.reply_id,
        }
        data_list.append(data)
    return JsonResponse({'status':True,'data':data_list})

# 前端采用ajax请求没有form表单,采用csrf_exempt解决请求跨域问题
@csrf_exempt
def discuss_page(request,issues_id):
    """评论模块"""
    if request.method == 'GET':
        issues_obj = models.Issues.objects.filter(id=issues_id).first()
        return render(request,'discuss.html',{'issues_obj':issues_obj})
    form = DiscussModelForm(data=request.POST)
    if form.is_valid():
        form.instance.issues_id = issues_id
        form.instance.creator = request.tracer.user
        instance = form.save()
        data = {
            'id': instance.id,
            'content': instance.content,
            'creator': instance.creator.username,
            'datetime': instance.create_datetime.strftime('%Y-%m-%m %H:%M'),
            'parent_id': instance.reply_id,
        }

        issues_obj = models.Issues.objects.get(id=issues_id)
        issues_obj.reply_num += 1
        issues_obj.save()

        return JsonResponse({'status':True,'data':data})
    return JsonResponse({'status': False, 'error': form.errors})

5.前端代码

问题页面

{% extends 'navigation/navigation.html' %}

{% load static %}

{% block css %}
    <link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.min.css' %}">

    <style>
        .panel-default .card-header {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
        }

        .error-msg {
            font-size: 10px;
            color: #721c24;
        }

        .comment-footer {
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-pack: justify;
            -ms-flex-pack: justify;
            justify-content: space-between;
            -webkit-box-align: center;
            -ms-flex-align: center;
            align-items: center;
            margin-top: 20px;
        }

        .comment-footer span {
            display: block;
            font-size: 14px;
            color: #989898;
            margin-top: 0;
        }

        .comment-reply-link {
            padding: 6px 22px;
            font-size: 13px;
            border: 1px solid #dddddd;
            line-height: normal;
            font-weight: 500;
            display: inline-block;
            background-color: transparent;
            border-radius: 30px;
            color: black;
            -webkit-transition: all 0.35s ease-in-out;
            transition: all 0.35s ease-in-out;
        }
    </style>
{% endblock %}



{% block content %}
    <div class="container-fluid clearfix" style="padding: 20px 0;">
        <div class="col-sm-12">
            <div class="card panel-default">
                <div class="card-header">
                    <div>
                        问题
                    </div>
                    <div>
                        <a class="btn btn-success btn-xs" data-toggle="modal" data-target="#addModal"
                           style="color: white">
                            <i class="fa fa-plus-circle" aria-hidden="true"></i> 新建问题</a>
                    </div>
                </div>

                <table class="table">
                    <tbody class="issues-list">

                    {% for item in issues_obj_list %}
                        <ul class="list-unstyled">
                            <li class="media my-4" style="padding: 0 20px">
                                <div class="media-body">
                                    <h5 class="mt-0 mb-1">{{ item.subject }}</h5>
                                    <p style="padding: 0 10px"> {{ item.desc }}</p>
                                    <div class="comment-footer">
                                        <span class="date">{{ item.create_datetime }}</span>
                                        <a href="{% url 'discuss_page' issues_id=item.id %}" class="comment-reply-link">回复{{ item.reply_num }}</a>
                                    </div>
                                </div>

                            </li>
                        </ul>
                    {% endfor %}
                    </tbody>
                </table>


            </div>
        </div>

    </div>


    <div class="modal fade" id="addModal" tabindex="-1" aria-labelledby="addModal" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="exampleModalLabel">发布问题</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <form id="addForm" class="form-horizontal">
                        {% csrf_token %}
                        {% for item in form %}
                            <div class="form-group">
                            <label for="message-text" class="col-form-label">{{ item.label }}:</label>
                            {{ item }}
                            <span class="error-msg"></span>
                        {% endfor %}
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-primary" id="btnAddSubmit">发布</button>
                </div>
            </div>
        </div>
    </div>



{% endblock %}



{% block js %}
    <script>
        var POST_ISSUES = "{% url 'issues' %}";

        $(function () {
            bindAddSubmit();
        });

        function bindAddSubmit() {
            $('#btnAddSubmit').click(function () {
                $('#addForm').find('.error-msg').empty();
                $.ajax({
                    url: POST_ISSUES,
                    type: "POST",
                    data: $('#addForm').serialize(),
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            location.href = location.href;
                        } else {
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })
            });
        }
    </script>
{% endblock %}

评论页面

{% extends 'navigation/navigation.html' %}


{% block css %}
    <style>

        .comment-area .item {
            margin-top: 20px;
        }

        .comment-area .left-avatar {
            float: left;
            margin-right: 10px;
            display: inline-block;
            width: 30px;
            height: 30px;
            background-color: #304659;
            color: white;
            text-align: center;
            line-height: 30px;
            border-radius: 50%;
        }

        .comment-area .right-info {
            padding-left: 35px;
        }

        .comment-area .right-info .desc .msg {
            display: inline-block;
            padding-right: 20px;
            color: #8c8c8c;
        }

        .comment-area .child {
            padding-left: 55px;
        }

        .comment-area .error-msg {
            color: red;
        }

        .comment-area .reply-user {
            display: inline-block;
            background-color: #ddd;
            color: black;
            padding: 6px 8px;
            margin-left: 20px;
            border-radius: 8px;
            cursor: pointer;
        }

        .editormd-fullscreen {
            z-index: 1001;
        }

        pre {
            display: block;
            padding: 9.5px;
            margin: 0 0 10px;
            font-size: 13px;
            line-height: 1.42857143;
            color: #333;
            word-break: break-all;
            word-wrap: break-word;
            background-color: #f5f5f5;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
    </style>
{% endblock %}


{% block content %}
    <div class="container-fluid clearfix" style="padding: 20px 0;">
        <div class="col-sm-12">
            <div class="card panel-default">
                <div class="card-header">
                    <i class="fa fa-search" aria-hidden="true"></i> 讨论
                </div>

                <div class="card-body comment-area">

                    <div class="comment-list">

                    </div>

                    <hr/>

                    <div class="comment-text" id="commentText">
                        <div class="form-group">
                            <textarea id="content" rows="6" class="form-control" placeholder="请输入回复内容"></textarea>
                            <span class="error-msg"></span>
                        </div>

                        <input type="button" class="btn btn-primary" id="btnSubmit" value="提 交">
                        <div class="reply-user d-none" id="replyUser">
                            回复 <span></span>
                            <i class="fa fa-times-circle" aria-hidden="true" style="color: #9d9d9d;"></i>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    </div>


    <div class="d-none" id="recordTemplate">
        <div class="item clearfix">
            <div class="left-avatar"></div>
            <div class="right-info">
                <pre></pre>
                <div class="desc">
                    <div class="msg">
                        <i class="fa fa-bullhorn" aria-hidden="true"></i>
                        <span class="type"></span>
                    </div>
                    <div class="msg">
                        <i class="fa fa-user-o" aria-hidden="true"></i>
                        <span class="user"></span>
                    </div>
                    <div class="msg">
                        <i class="fa fa-clock-o" aria-hidden="true"></i>
                        <span class="date"></span>
                    </div>

                    <a href="#commentText" class="reply">
                        <i class="fa fa-commenting-o" aria-hidden="true"></i> 回复
                    </a>
                </div>
            </div>
            <div class="child">

            </div>
        </div>
    </div>
{% endblock %}



{% block js %}
    <script>
        var ISSUES_RECORD_URL = '{% url 'discuss' issues_id=issues_obj.id %}';
        var ISSUES_URL = '{% url 'discuss_page' issues_id=issues_obj.id %}';

        $(function () {
            bindSubmit();
            initIssuesRecord();
            bindReply();
            bindCancelReplyUser();
        });

        /*
         问题评论的初始化
         */
        function initIssuesRecord() {
            $.ajax({
                url: ISSUES_RECORD_URL,
                type: "GET",
                dataType: "JSON",
                success: function (res) {
                    if (res.status) {
                        console.log(res.data);
                        $.each(res.data, function (index, item) {
                            createRecordNode(item);
                        })
                    } else {

                    }

                }
            })
        }

        /*
        创建操作记录节点
         */
        function createRecordNode(nodeDict) { //nodeDict后端发过来的数据
            var $item = $("#recordTemplate").find('.item').clone();
            $item.find('.left-avatar').html(nodeDict.creator[0].toUpperCase());
            $item.find('pre').html(nodeDict.content);
            $item.find('.user').html(nodeDict.creator);
            $item.find('.date').html(nodeDict.datetime);
            $item.attr({id: nodeDict.id, username: nodeDict.creator});

            if (nodeDict.parent_id) {
                // 挂在谁下
                $('#' + nodeDict.parent_id).children('.child').append($item);
            } else {
                // 根下
                $('.comment-list').append($item);
            }
        }


        /*
        回复问题
         */
        function bindReply() {
            $('.comment-list').on('click', '.reply', function () {
                var $item = $(this).parent().parent().parent();
                var id = $item.attr('id');
                var username = $item.attr('username');
                $('#replyUser').removeClass('d-none').attr('parent-id', id).children('span').text(username);
            })
        }

        /*
        取消回复
         */
        function bindCancelReplyUser() {
            $('#replyUser').click(function () {
                $(this).addClass('d-none').removeClass('parent-id').children('span').text();
            })
        }

        /*
        点击评论
         */
        function bindSubmit() {
            $('#btnSubmit').click(function () {
                $('#commentText .error-msg').text("");
                $.ajax({
                    url: ISSUES_URL,
                    type: 'POST',
                    data: {content: $('#content').val(), reply: $('#replyUser').attr('parent-id')},
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            createRecordNode(res.data);
                            //输入框清空
                            $('#content').val('');
                            $('#replyUser').addClass('d-none').removeAttr('parent-id').children('span').text("")
                        } else {
                            $.each(res.error, function (key, value) {
                                $('#content').next('.error-msg').text(value[0])
                            })
                        }
                    }
                })
            })
        }

    </script>
{% endblock %}

 

posted @ 2021-03-14 12:59  Hp_mzx  阅读(614)  评论(0)    收藏  举报