1.自定义模型

2.修改昵称

3.验证码绑定邮箱

4.注册邮箱验证

5.修改密码

6.忘记密码

7.评论发送邮件


1.自定义模型

新的模型拓展关联User方法

优点:
1)使用方便
2)不用删库重来影响整体构架
缺点:
1)存在不必要的字段
2)对比继承的方法,查询速度稍稍慢一丁点
 

\blog\users\models.py

class User(AbstractUser):
    # 昵称
    nickname = models.CharField(max_length=20, default='', verbose_name='昵称')

fieldsets里面内容可以在 "...\Lib\site-packages\django\contrib\auth\admin.py"里面找到

\blog\users\admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
# Register your models here.

# 用户自定义模型
User = get_user_model()


class UserAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('nickname', 'email', 'mobile', 'avatar')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
                                       'groups', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )

    list_display = ('username', 'nickname',  'mobile', 'email', 'is_staff', 'is_active', 'is_superuser')


admin.site.register(User, UserAdmin)







 

如下图

再nav.html设置只有管理员看到后台管理

\blog\templates\include\nav.html
{#超级管理员才显示#}
    {% if user.is_staff or user.is_superuser %}
        <a class="nav-link" href="{% url 'admin:index' %}" tabindex="-1" aria-disabled="true" style="color: red;font-weight:bold">后台管理</a>
    {% endif %}

2.修改昵称

\blog\users\urls.py
   # 修改昵称
    path('change_nickname', views.change_nickname, name='change_nickname'),
def change_nickname(request):
    redirect_to = request.GET.get('from', reverse('home:index'))

    if request.method == 'POST':
        form = ChangeNicknameForm(request.POST, user=request.user)
        if form.is_valid():
            nickname_new = form.cleaned_data['nickname_new']
            username, created = User.objects.get_or_create(mobile=request.user)
            # print(username, created)

            username.nickname = nickname_new
            username.save()
            redirect_to = request.GET.get('from', reverse('home:index'))
            return redirect(redirect_to)
    else:
        form = ChangeNicknameForm()

    context = {
        'page_title': '修改昵称',
        'form_title': '修改昵称',
        'submit_text': '修改',
        'form': form,
        'return_back_url': redirect_to
    }
    return render(request, 'form.html', context)

model.py判断用户是否有昵称如果有就显示昵称,没有就显示手机号,在评论回复可以看到,例如在detailhtml加入get_nickname,如下图

\blog\templates\detail.html               
<span><strongid="replay_user_{{ comment.id }}">{{ comment.user.get_nickname }}</strong></span>
<span><strongid="replay_user_{{ reply.id }}">{{ reply.user.get_nickname }}</strong></span>
<span><strongid="replay_user_{{ reply.id }}">{{ reply.reply_to.get_nickname }}</strong></span>
\blog\users\models.py
class User(AbstractUser):
    def get_nickname(self):
        # 判断nikename是否存在
        if User.objects.filter(mobile=self).exists():
            username = User.objects.get(mobile=self)

            if username.nickname:
                return username.nickname
            else:
                return self.mobile

views.py也要改成get_nickname()要加括号,回复时候显示的,无需刷新页面情况,如下面图

\blog\home\views.py
class DetailView(View):
    def post(self, request):
            # 返回评论数据.get_nickname()是users:model里面的如果有昵称返回昵称,没有就返回手机号,是评论不刷新页面出现

            data['user'] = comment.user.get_nickname()
# 返回回复数据
            if parent:
                data['reply_to'] = comment.reply_to.get_nickname()

通用的form.html模板 

\blog\templates\form.html

{% extends 'include/base.html' %}
{% load static %}

{% block title %}
    <title>{{ page_title }}</title>
{% endblock %}


{% block content %}

    <!--content-->
    <div class="container" style="height: 600px;margin-top: 20px">
        <div class="row">
            <div class="col-lg-6 col-xl-6 hidden-xs hidden-sm">
                <div class="card">
                    <div class="card-header">{{ form_title }}</div>
                    <div class="card-body">
                        <form action="" method="POST">
                            {% csrf_token %}
                            {# {{ login_form }}#}
                            {% for field in form %}
                                <!--去掉冒号-->
                                {% if not field.is_hidden %}
                                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                                {% endif %}
                                {{ field }}
                                <!--显示错误标签-->
                                <p class="text-danger">{{ field.errors.as_text }}</p>

                            {% endfor %}
                            <spen id="tip" class="pull-left text-danger">{{ form.non_field_errors }}</spen>
                            <div>
                                {% block other_button %}{% endblock %}
                            </div>
                            <div class="modal-footer">
                                <input type="submit" value="{{ submit_text }}" class="btn btn-primary">
                                <button class="btn btn-secondary"
                                        onclick="window.location.href='{{ return_back_url }}'">
                                    返回
                                </button>
                            </div>


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


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

这个User是User = get_user_model()不然ERROR会报错

\blog\users\forms.py
# 修改用户昵称
class ChangeNicknameForm(forms.Form):
    nickname_new = forms.CharField(
        label="新的昵称",
        required=False,
        max_length=20,
        widget=forms.TimeInput(attrs={'class': 'form-control', 'placeholder': '请输入新的昵称'})
    )

    def __init__(self, *args, **kwargs):
        if 'user' in kwargs:
            self.user = kwargs.pop('user')
        super(ChangeNicknameForm, self).__init__(*args, **kwargs)

    def clean(self):
        # 判断用户是否登录
        if self.user.is_authenticated:
            self.cleaned_data['user'] = self.user
        else:
            raise forms.ValidationError('用户尚未登录')
        return self.cleaned_data

    def clean_nickname_new(self):
        nickname_new = self.cleaned_data.get('nickname_new', '').strip()
        if nickname_new == '':
            raise forms.ValidationError("新的昵称不能为空")
        return nickname_new
\blog\templates\center.html
                    <ul>
                        <li>昵称: {{ user.nickname }} <a
                                href="{% url 'users:change_nickname' %}?from={{ request.get_full_path }}">修改昵称</a></li>
                        <li>邮箱:{% if user.email %} {{ user.email }} {% else %}未绑定
                            <a href="{% url 'users:bind_email' %}?from={{ request.get_full_path }}">绑定邮箱</a>{% endif %}
                        </li>
                        <li>上一次登录时间:{{ user.last_login | date:'Y-m-d H:i:s' }}</li>
                        <li><a href="#">修改密码</a></li>
                    </ul>

 

3.验证码绑定邮箱

\blog\users\urls.py
    # 绑定邮箱
    path('bind_email', views.bind_email, name='bind_email'),
    # 发送验证码
    path('send_verification_code', views.send_verification_code, name='send_verification_code'),
\blog\settings.py
# 发送邮件设置
# https://docs.djangoproject.com/en/3.0/ref/settings/#email
# https://docs.djangoproject.com/en/3.0/topics/email/
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = '534640040@qq.com'
EMAIL_HOST_PASSWORD = ''  # 授权码在qq邮箱可以得到
EMAIL_SUBJECT_PREFIX = '[杨永生的网站] '
EMAIL_USE_TLS = True  # 与SMTP服务器通信时,是否启动TLS链接(安全链接)
\blog\users\views.py
def bind_email(request):
    redirect_to = request.GET.get('from', reverse('home:index'))

    if request.method == 'POST':
        form = BindEmailForm(request.POST, request=request)
        if form.is_valid():
            email = form.cleaned_data['email']
            request.user.email = email
            request.user.save()
            return redirect(redirect_to)
    else:
        form = BindEmailForm()
    context = {
        'page_title': '绑定邮箱',
        'form_title': '绑定邮箱',
        'submit_text': '绑定',
        'form': form,
        'return_back_url': redirect_to
    }

    return render(request, 'bind_email.html', context)


def send_verification_code(request):
    email = request.GET.get('email', '')
    data = {}
    if email != '':
        # 生成验证码
        # 发送邮件
        code = ''.join(random.sample(string.ascii_letters + string.digits, 4))
        now = int(time.time())
        send_code_time = request.session.get('send_code_time', 0)
        if now - send_code_time < 30:
            data['status'] = 'ERROR'
        else:
            request.session['bind_email_code'] = code
            request.session['send_code_time'] = now

        send_mail(
            '绑定邮箱',
            '验证码: %s,温馨提示:区分大小写!' % code,
            '534640040@qq.com',  # 发送者邮箱
            [email],  # 收件人的邮箱
            fail_silently=False,
        )
        data['status'] = 'SUCCESS'

    else:
        data['status'] = 'ERROR'
    return JsonResponse(data)
\blog\users\forms.pyclass BindEmailForm(forms.Form):
    email = forms.EmailField(
        label="邮箱",
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入正确的邮箱'})
    )

    verification_code = forms.CharField(
        label='验证码',
        required=False,
        widget=forms.TextInput(
            attrs={'class': 'form-control', 'placeholder': '点击“发送验证码”发送到邮箱'}
        )
    )

    def __init__(self, *args, **kwargs):
        if 'request' in kwargs:
            self.request = kwargs.pop('request')
        super(BindEmailForm, self).__init__(*args, **kwargs)

    def clean(self):
        # 判断用户是否登录
        if self.request.user.is_authenticated:
            self.cleaned_data['user'] = self.request.user
        else:
            raise forms.ValidationError('用户尚未登录')

        # 判断用户是否已绑定邮箱
        if self.request.user.email != '':
            raise forms.ValidationError('你已经绑定邮箱')

        # 判断验证码
        code = self.request.session.get('bind_email_code', '')
        verification_code = self.cleaned_data.get('verification_code', '')
        if not (code != '' and code == verification_code):
            raise forms.ValidationError('验证码不正确')

        return self.cleaned_data

    def clean_email(self):

        email = self.cleaned_data['email']

        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('该邮箱已经被绑定')
        return email

    def clean_verification_code(self):
        verification_code = self.cleaned_data.get('verification_code', '').strip()
        if verification_code == '':
            raise forms.ValidationError('验证码不能为空')
        return verification_code

绑定邮箱html继承form通用模板,多个发送验证码按钮,所以单独写个 

{#继承form.html#}
{% extends 'form.html' %}


{% block other_button %}
    <button id="send_code" class="btn btn-primary">发送验证码</button>
{% endblock %}

{% block bottomjs %}
    <script type="text/javascript">
        $("#send_code").click(function () {
            var email = $("#id_email").val();
            if (email == "") {
                $("#tip").text('邮箱不能为空');
                return false;

            }
            //发送验证码
             $.ajax({
                url: "{% url 'users:send_verification_code' %}",
                type: "GET",
                data: {
                    'email': email
                },
                cache: false,
               success: function(data){
                    if(data['status']=='ERROR'){
                        alert(data['status']);
                    }
                }
            });
             // 把按钮变灰
            $(this).addClass('disabled');
            $(this).attr('disabled', true);
            var time = 30;
            $(this).text(time + 's');
            var interval = setInterval(() => {
                if(time <= 0){
                    clearInterval(interval);
                    $(this).removeClass('disabled');
                    $(this).attr('disabled', false);
                    $(this).text('发送验证码');
                    return false;
                }

                time --;
                $(this).text(time + 's');
            }, 1000);

        });
    </script>
{% endblock %}
\blog\templates\center.html
<!-- 提交按钮 -->
                    <ul>
                        <li>昵称: {{ user.nickname }} <a
                                href="{% url 'users:change_nickname' %}?from={{ request.get_full_path }}">修改昵称</a></li>
                        <li>邮箱:{% if user.email %} {{ user.email }} {% else %}未绑定
                            <a href="{% url 'users:bind_email' %}?from={{ request.get_full_path }}">绑定邮箱</a>{% endif %}
                        </li>
                        <li>上一次登录时间:{{ user.last_login | date:'Y-m-d H:i:s' }}</li>
                        <li><a href="#">修改密码</a></li>
                    </ul>

注意事项:腾讯云不能发送邮箱验证码解决办法

点击“25端口解封

4.注册邮箱验证

\python\blog\users\urls.py

# 注册
    path('register/', RegisterView.as_view(), name='register'),

 

\blog\users\views.py

class RegisterView(View):
    def get(self, request):
        reg_form = RegisterForm
        context = {
            'reg_form': reg_form
        }
        return render(request, 'register.html', context)

    def post(self, request):
        if request.method == 'POST':
            # 1.接收记住登录参数

            reg_form = RegisterForm(request.POST, request=request)
            if reg_form.is_valid():
                mobile = reg_form.cleaned_data["mobile"]
                email = reg_form.cleaned_data["email"]
                password = reg_form.cleaned_data['password']
                # 创建用户
                # print(mobile, email, password)
                user = User.objects.create_user(username=mobile, mobile=mobile, email=email, password=password)
                user.save()
                # 清除session
                del request.session['register_code']
                # # 登录用户
                user = auth.authenticate(mobile=mobile, password=password)
                auth.login(request, user)
                response = redirect(reverse('home:index'))

                return response
        else:
            reg_form = RegisterForm()
            pass
        context = {
            'reg_form': reg_form
        }
        return render(request, 'register.html', context)
\blog\templates\register.html
{% extends 'include/base.html' %}
{% load static %}

{% block title %}
    <title>注册</title>
{% endblock %}


{% block content %}


    <!--content-->
    <div class="container" style="height: 600px;margin-top: 20px">
        <div class="row">
            <div class="col-lg-6 col-xl-6 hidden-xs hidden-sm">
                <div class="card">
                    <div class="card-header">注册</div>
                    <div class="card-body">
                        <form action="" method="POST">
                            {% csrf_token %}
                            {#                                {{ login_form }}#}
                            {% for field in reg_form %}
                                <!--去掉冒号-->
                                <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                                {{ field }}
                                <!--显示错误标签-->
                                <p class="text-danger">{{ field.errors.as_text }}</p>
                            {% endfor %}
                            <spen class="pull-left text-danger">{{ reg_form.non_field_errors }}</spen>

                            <button id="send_code" class="btn btn-primary ">发送验证码</button>
                            <button class="primaryAction btn btn-primary " style="float:right" type="submit"
                                    id="submit_login" @click="on_submit">提交
                            </button>
                        </form>
                    </div>
                </div>


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

{% block bottomjs %}
    <script type="text/javascript">
        $("#send_code").click(function () {
            var email = $("#id_email").val();
            if (email == "") {
                $("#tip").text('*邮箱不能为空');
                return false;

            }
            //发送验证码
            $.ajax({
                url: "{% url 'users:send_verification_code' %}",
                type: "GET",
                data: {
                    'email': email,
                    {#register_code传入form#}
                    'send_for': 'register_code'
                },
                cache: false,
                success: function (data) {
                    if (data['status'] == 'ERROR') {
                        alert(data['status']);
                    }
                }
            });
            // 把按钮变灰
            $(this).addClass('disabled');
            $(this).attr('disabled', true);
            var time = 30;
            $(this).text(time + 's');
            var interval = setInterval(() => {
                if (time <= 0) {
                    clearInterval(interval);
                    $(this).removeClass('disabled');
                    $(this).attr('disabled', false);
                    $(this).text('发送验证码');
                    return false;
                }

                time--;
                $(this).text(time + 's');
            }, 1000);

        });
    </script>
{% endblock %}
\blog\templates\include\base.html
\blog\templates\login.html
<small class="form-text text-muted ml-1">还没有账号?<a href="{% url 'users:register' %}"
                                                                              style="color: cornflowerblue; ">注册新账号</a>
                            </small>

 

\blog\users\forms.py
class RegisterForm(forms.Form):
    mobile = forms.CharField(label="用户名", max_length=11, min_length=3, widget=forms.TextInput(
        attrs={'class': 'form-control', 'placeholder': '请输入手机号'}))
    email = forms.EmailField(label='邮箱',
                             widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入邮箱'}))

    verification_code = forms.CharField(
        label='验证码',
        required=False,
        widget=forms.TextInput(
            attrs={'class': 'form-control', 'placeholder': '点击“发送验证码”发送到邮箱'}
        )
    )

    password = forms.CharField(label="密码", min_length=6, widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    password_again = forms.CharField(label="再输入一次密码", min_length=6, widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '再输入一次密码'}))

    # request是获取session
    def __init__(self, *args, **kwargs):
        if 'request' in kwargs:
            self.request = kwargs.pop('request')
        super(RegisterForm, self).__init__(*args, **kwargs)

    def clean(self):
        # 判断验证码register_code对应js里面的send_for
        code = self.request.session.get('register_code', '')
        verification_code = self.cleaned_data.get('verification_code', '')

        if not (code != '' and code == verification_code):
            raise forms.ValidationError('验证码不正确')

        return self.cleaned_data

    def clean_username(self):
        mobile = self.cleaned_data['mobile']
        if User.objects.filter(mobile=mobile).exists():
            raise forms.ValidationError('用户名已存在')
        return mobile

    def clean_email(self):
        email = self.cleaned_data['email']
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('邮箱已存在')
        return email

    def clean_password_again(self):
        password = self.cleaned_data['password']
        password_again = self.cleaned_data['password_again']
        if password != password_again:
            raise forms.ValidationError("两次密码不一致")
        return password

    def clean_verification_code(self):
        verification_code = self.cleaned_data.get('verification_code', '').strip()
        if verification_code == '':
            raise forms.ValidationError('验证码不能为空')
        return verification_code

 

5.修改密码

\blog\users\urls.py
# 修改密码
    path('change_password', views.change_password, name='change_password'),
def change_password(request):
    # 和修改昵称类似,redirect_to跳转到登录页面
    redirect_to = reverse('users:login')

    if request.method == 'POST':
        form = ChangePasswordForm(request.POST, user=request.user)
        if form.is_valid():
            user = request.user
            new_password = form.cleaned_data['new_password']
            user.set_password(new_password)
            user.save()
            # 退出登录
            auth.logout(request)
            return redirect(redirect_to)
    else:
        form = ChangePasswordForm()
    context = {
        'page_title': '修改密码',
        'form_title': '修改密码',
        'submit_text': '修改',
        'form': form,
        'return_back_url': redirect_to
    }

    return render(request, 'form.html', context)

html继承的form.html

\blog\users\forms.py
class ChangePasswordForm(forms.Form):
    old_password = forms.CharField(label="密码", widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '请输入旧的密码'}))
    new_password = forms.CharField(label="密码", widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '请输入新的密码'}))
    new_password_again = forms.CharField(label="密码", widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '请再次输入的密码'}))

    def __init__(self, *args, **kwargs):
        if 'user' in kwargs:
            self.user = kwargs.pop('user')
        super(ChangePasswordForm, self).__init__(*args, **kwargs)

    def clean(self):
        # 判断两次新密码是否一致
        new_password = self.cleaned_data['new_password']
        new_password_again = self.cleaned_data['new_password_again']
        if new_password != new_password_again or new_password == '':
            return forms.ValidationError("两次密码不一致")
        return self.cleaned_data

    def clean_old_password(self):
        #  判断旧密码是否正确
        old_password = self.cleaned_data.get('old_password', '')
        if not self.user.check_password(old_password):
            raise forms.ValidationError("旧密码不正确")
        return old_password
\blog\templates\include\nav.html
               
 <a class="dropdown-item" href="{% url 'users:change_password' %}">修改密码</a>

\blog\templates\center.html
                        
<li><a href="{% url 'users:change_password' %}">修改密码</a></li>

6.忘记密码

\blog\users\urls.py
# 忘记密码
    path('forgot_password', views.forgot_password, name='forgot_password'),
\blog\users\views.py
def forgot_password(request):
    redirect_to = reverse('users:login')

    if request.method == 'POST':
        form = ForgotPasswordForm(request.POST, request=request)
        if form.is_valid():
            email = form.cleaned_data["email"]
            new_password = form.cleaned_data['new_password']
            user = User.objects.get(email=email)
            user.set_password(new_password)
            user.save()

            # 清除session
            del request.session['forgot_password_code']
            return redirect(redirect_to)
    else:
        form = ForgotPasswordForm()
    context = {
        'page_title': '重置密码',
        'form_title': '重置密码',
        'submit_text': '重置',
        'form': form,
        'return_back_url': redirect_to
    }

    return render(request, 'forgot_password.html', context)
\blog\users\forms.py
class ForgotPasswordForm(forms.Form):
    email = forms.EmailField(
        label="邮箱",
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入忘记密码的邮箱'})
    )

    verification_code = forms.CharField(
        label='验证码',
        required=False,
        widget=forms.TextInput(
            attrs={'class': 'form-control', 'placeholder': '点击“发送验证码”发送到邮箱'}
        )
    )
    new_password = forms.CharField(label="新的密码", min_length=6, widget=forms.PasswordInput(
        attrs={'class': 'form-control', 'placeholder': '请输入新的密码'}))

    def clean_email(self):
        email = self.cleaned_data["email"].strip()
        if not User.objects.filter(email=email).exists():
            return forms.ValidationError("你输入的邮箱不存在")
        return email

    def __init__(self, *args, **kwargs):
        if 'request' in kwargs:
            self.request = kwargs.pop('request')
        super(ForgotPasswordForm, self).__init__(*args, **kwargs)

    def clean_verification_code(self):

        # 判断验证码是否为空
        verification_code = self.cleaned_data.get('verification_code', '').strip()
        if verification_code == '':
            raise forms.ValidationError('验证码不能为空')

        # 判断验证码register_code对应js里面的send_for
        code = self.request.session.get('forgot_password_code', '')
        verification_code = self.cleaned_data.get('verification_code', '')
        if not (code != '' and code == verification_code):
            raise forms.ValidationError('验证码不正确')

        return verification_code
\blog\templates\forgot_password.html
{#继承form.html#}
{% extends 'form.html' %}


{% block other_button %}
    <button id="send_code" class="btn btn-primary">发送验证码</button>
{% endblock %}

{% block bottomjs %}
    <script type="text/javascript">
        $("#send_code").click(function () {
            var email = $("#id_email").val();
            if (email == "") {
                $("#tip").text('*邮箱不能为空');
                return false;

            }
            //发送验证码
             $.ajax({
                url: "{% url 'users:send_verification_code' %}",
                type: "GET",
                data: {
                    'email': email,
                    'send_for': 'forgot_password_code'
                },
                cache: false,
               success: function(data){
                    if(data['status']=='ERROR'){
                        alert(data['status']);
                    }
                }
            });
             // 把按钮变灰
            $(this).addClass('disabled');
            $(this).attr('disabled', true);
            var time = 30;
            $(this).text(time + 's');
            var interval = setInterval(() => {
                if(time <= 0){
                    clearInterval(interval);
                    $(this).removeClass('disabled');
                    $(this).attr('disabled', false);
                    $(this).text('发送验证码');
                    return false;
                }

                time --;
                $(this).text(time + 's');
            }, 1000);

        });
    </script>
{% endblock %}
\blog\templates\login.html
\blog\templates\include\base.html
<small class="form-text text-muted ml-1"><a class="secondaryAction layui-text"
                                                                        href="{% url 'users:forgot_password' %}">忘记密码?</a>
                            </small>

7.评论发送邮件

\blog\home\views.py

# 发送邮件
 comment.sen_email(request)

 

\blog\home\models.py
from django.core.mail import send_mail
from django.conf import settings
from django.template.loader import render_to_string
# 多线发邮件
class SendMail(threading.Thread):
    def __init__(self, subject, text, email, fail_silently=False):
        self.subject = subject
        self.text = text
        self.email = email
        self.fail_silently = fail_silently
        threading.Thread.__init__(self)

    def run(self):
        send_mail(self.subject,
                  self.text,
                  settings.EMAIL_HOST_USER,
                  [self.email],
                  fail_silently=self.fail_silently,
                  html_message=self.text

                  )
class Article(models.Model):
    def get_url(self, request):
        """获得网站url绝对路径"""
        return request.build_absolute_uri()

    def get_email(self):
        return self.author.email
class Comment(models.Model):
    def sen_email(self, request):
        if self.parent is None:
            # 评论
            subject = "有人评论我的文章"
            email = self.article.get_email()

        else:
            # 回复
            subject = "有人回复你的评论"
            email = self.reply_to.email
        print(self.article.get_url(request))
        if email:
            context = {
                'comment_text': self.content,
                "url": self.article.get_url(request)
            }
            # 发送给html模板
            text = render_to_string('send_email.html', context)
            send_mail = SendMail(subject, text, email)
            send_mail.start()

 

\templates\send_email.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ comment_text|safe }}
<br>
<a href="{{ url }}">点击查看</a>

</body>
</html>