目录
10.7 修改用户基本信息(手机号,用户名,生日,地址,性别)
10.1 完善首页
1、直接从,网页链接中获取信息
前端代码:
{% if request.path|slice:'9' == '/org/list' %}class="active"{% endif %}
代码解释: request.path 取得当前网页的路径(没有域名的路径 如http://127.0.0.1:8000/org/home/2/ request.path结果为 /org/home/2/ )
slice:'9' == '/org/list' 相当于re正则表达式 ,取前几位然后进行对比
<div class="wp"> <ul> <li ><a href="{% url 'index' %}" {% if request.path == '/' %}class="active"{% endif %}>首页</a></li> <li > <a href="/course/list/"> 公开课<img class="hot" src="/static/images/nav_hot.png"> </a> </li> <li > <a href="/org/teacher/list/">授课教师</a> </li> <li {% if request.path|slice:'9' == '/org/list' %}class="active"{% endif %}><a href="/org/list/">授课机构</a></li> </ul> </div>
{% if request.path == '/' %}class="active"{% endif %}>首页</a></li> <li > <a href="/course/list/"> 公开课<img class="hot" src="/static/images/nav_hot.png"> </a> </li> <li > <a href="/org/teacher/list/">授课教师</a> </li> <li {% if request.path|slice:'9' == '/org/list' %}class="active"{% endif %}><a href="/org/list/">授课机构</a></li> </ul> </div>
10.2 完善页头搜索功能
Django models 对数据库的操作 https://www.cnblogs.com/yangmv/p/5327477.html
后台代码(对课程进行搜索)
course.CourseListView()
class CourseList(View):
def get(self,request):
all_courses = Course.objects.all().order_by("-add_time")
hot_courses = Course.objects.all().order_by("-click_nums")[:3]
#完成搜索功能
search_keywords = request.GET.get('keywords','')
if search_keywords:
all_courses = all_courses.filter(Q(name__icontains= search_keywords)|Q(desc__icontains=search_keywords)|Q(detail__icontains=search_keywords))#name__icontains contains前面的i表示不区分大小写
#课程排序
sort = request.GET.get('sort','')
if sort:
if sort == 'hot':
all_courses = all_courses.order_by('-click_nums')
elif sort == 'students':
all_courses = all_courses.order_by('-student')
try:
page = int(request.GET.get('page', 1))#这里要做一下int转换,这里的request.GET.get('page', 1)中的page是Django在分页时自动生成的
except PageNotAnInteger:
page = 1
paginator = Paginator(all_courses,6,request=request)#每页显示条数3
courses = paginator.page(page)
if request.user.is_authenticated:
username = request.user
else:
username = '未登录,请点击登陆'
return render(request,'course-list.html',{
'all_courses': courses,
'sort':sort,
'hot_courses':hot_courses,
'username':username,
})
重点在这里,对于课程,老师,机构都是这样写
search_keywords = request.GET.get('keywords','')
if search_keywords:
all_courses = all_courses.filter(Q(name__icontains= search_keywords)|Q(desc__icontains=search_keywords)|Q(detail__icontains=search_keywords))#name__icontains contains前面的i表示不区分大小写
前端代码:
在base.html 页面添加监听代码
function search_click(){
var type = $('#jsSelectOption').attr('data-value'),//拿到前端数据类型
keywords = $('#search_keywords').val(), //keywords 这个字段会传到后台,在后台进行查询,他的功能是拿到搜索框中用户输入的内容
request_url = '';
if(keywords == ""){
return
}
if(type == "course"){
request_url = "/course/list?keywords="+keywords //怎么匹配到的????
}else if(type == "teacher"){
request_url = "/org/teacher/list?keywords="+keywords
}else if(type == "org"){
request_url = "/org/list?keywords="+keywords
}
window.location.href = request_url
}
10.3、个人中心
在所有用户中心页面配置时,在views.py中都要就继承LoginRequiredMixin,以判断用户是否登陆
1、userinfo 页面配置
首先先将 user_base页面进行配置,然后在userinfo.html页面中继承base页面,最后将后台数据传到前端
前端代码 用户信息直接从request.user 传值
值得注意的是:value="{{ request.user.mobile|default_if_none:'' }} 后面的default_if_not是对手机号进行判断,如果为空那么将不填充,否则会填充上None
<li>手 机 号:
<input type="text" name="mobile"value="{{ request.user.mobile|default_if_none:'' }}" >
</li>
10.4 、上传用户头像,修改用户信息
users.views.py
class UploadImgView(LoginRequiredMixin,View):
def post(self,request):
image_form = UploadImgForm(request.POST,request.FILES)#image是文件类型,不是字段所以后面要加上request.FILES
if image_form.is_valid():
'''
当前端上传图片的时候,如果前端拿到图片,那么clrarned_data里面变回存放前端验证通过的数据
而且数据的字段名称与前端的标签的属性名称一致
'''
img = image_form.cleaned_data['image'] #
request.user.image = img
request.user.save()
class UploadImgView(LoginRequiredMixin,View):
'''
UploadImgForm(request.POST)是前端form传递到 后台的数据
request.FILES 是签单传递的数据类型为file,不再是字段了(默认是字段)
instance=request.user
'''
image_form = UploadImgForm(request.POST,request.FILES,instance=request.user)
if image_form.is_valid():
image_form.save()
return
HttpResponse(json.dump('{"status":"success"}'),content_type='application/json')
else:
return HttpResponse(json.dump('{"status":"fail"}'),
content_type='application/json')
10.5 修改用户密码
后台:
class ResetPwdView(View):
def post(self,request):
modify_form = ModifyPwdForm(request.POST)
if modify_form.is_valid():
pwd1 = request.POST.get('password1','')
pwd2 = request.POST.get('password2','')
if pwd1 != pwd2:
return HttpResponse(json.dumps('{"status":"fail","msg":"两次密码不一致,请重新输入"}'),content_type='application/json')
else:
user = request.user
user.password = make_password(pwd1)
user.save()
return HttpResponse(json.dumps('{"status":"success"}'), content_type='application/json')
else:
return HttpResponse(json.dumps(modify_form.errors),content_type='application/json')
path('reset_pwd/',ResetPwdView.as_view(),name = "reset_pwd"),
前端:
$(function(){
//个人资料修改密码
$('#jsUserResetPwd').on('click', function(){
Dml.fun.showDialog('#jsResetDialog', '#jsResetPwdTips');
});
$('#jsResetPwdBtn').click(function(){
$.ajax({
cache: false,
type: "POST",
dataType:'json',
url:"/index/reset_pwd/",
data:$('#jsResetPwdForm').serialize(),
async: true,
success: function(data) {
if(data.password1){
Dml.fun.showValidateError($("#pwd"), data.password1);
}else if(data.password2){
Dml.fun.showValidateError($("#repwd"), data.password2);
}else if(data.status == "success"){
Dml.fun.showTipsDialog({
title:'提交成功',
h2:'修改密码成功,请重新登录!',
});
Dml.fun.winReload();
}else if(data.msg){
Dml.fun.showValidateError($("#pwd"), data.msg);
Dml.fun.showValidateError($("#repwd"), data.msg);
}
}
});
});
//个人资料头像
$('.js-img-up').uploadPreview({ Img: ".js-img-show", Width: 94, Height: 94 ,Callback:function(){
$('#jsAvatarForm').submit();
}});
$('.changeemai_btn').click(function(){
Dml.fun.showDialog('#jsChangeEmailDialog', '#jsChangePhoneTips' ,'jsChangeEmailTips');
});
$('#jsChangeEmailCodeBtn').on('click', function(){
sendCodeChangeEmail($(this));
});
$('#jsChangeEmailBtn').on('click', function(){
changeEmailSubmit($(this));
});
//input获得焦点样式
$('.perinform input[type=text]').focus(function(){
$(this).parent('li').addClass('focus');
});
$('.perinform input[type=text]').blur(function(){
$(this).parent('li').removeClass('focus');
});
laydate({
elem: '#birth_day',
format: 'YYYY-MM-DD',
max: laydate.now()
});
verify(
[
{id: '#nick_name', tips: Dml.Msg.epNickName, require: true}
]
);
//保存个人资料
$('#jsEditUserBtn').on('click', function(){
var _self = $(this),
$jsEditUserForm = $('#jsEditUserForm')
verify = verifySubmit(
[
{id: '#nick_name', tips: Dml.Msg.epNickName, require: true}
]
);
if(!verify){
return;
}
$.ajax({
cache: false,
type: 'post',
dataType:'json',
url:"/users/info/",
data:$jsEditUserForm.serialize(),
async: true,
beforeSend:function(XMLHttpRequest){
_self.val("保存中...");
_self.attr('disabled',true);
},
success: function(data) {
if(data.nick_name){
_showValidateError($('#nick_name'), data.nick_name);
}else if(data.birday){
_showValidateError($('#birth_day'), data.birday);
}else if(data.address){
_showValidateError($('#address'), data.address);
}else if(data.status == "failure"){
Dml.fun.showTipsDialog({
title: '保存失败',
h2: data.msg
});
}else if(data.status == "success"){
Dml.fun.showTipsDialog({
title: '保存成功',
h2: '个人信息修改成功!'
});
setTimeout(function(){window.location.href = window.location.href;},1500);
}
},
complete: function(XMLHttpRequest){
_self.val("保存");
_self.removeAttr("disabled");
}
});
});
});
未解决的问题,
当密码符合但不一致是,不能给提示
未验证旧密码
密码修改成功后转到登陆页面,但是不能自动刷新,要将当前个人信息页面刷新才可以进入登录页面
10.6 修改用户邮箱,并对邮箱进行验证
后台代码:
sittings.py: 主要是设置邮箱的相关信息,如密码,主发邮箱号
EMAIL_HOST = 'smtp.qq.com'
EMAIL_POSRT = 25
EMAIL_HOST_USER = "[email protected]"#邮箱名
EMAIL_HOST_PASSWORD = "xpkdjgkhhwvbgjce"#密码,这里要换成授权码
EMAIL_USE_TLS = False
EMAIL_FROM = "[email protected]"#邮箱名
users.email_send.py
这是一个可供其他方法调用的发送邮箱的方法,不能和视屏一样放在utils里面,会出错(为什么我也不知道)
import random
from django.core.mail import send_mail
from .models import EmailVerifyRecord
from MXonline.settings import EMAIL_FROM
def send_register_email(email,send_type="register"):#参数含义:email将要发送的邮箱地址,type发送邮件的当下情
email_record = EmailVerifyRecord()
code = random_str()#随机验证码
email_record.code = code
email_record.email = email
email_record.send_type = send_type
email_record.save()#将邮箱验证的信息(邮箱号,验证码,验证类型)存入到数据库,为之后用户填写验证码后台做验证的时候使用
#定义邮件内容
email_title = ""
email_body = ""
if send_type == "register":
email_title = "激活链接"
email_body = "请点击下面的激活链接:http://127.0.0.1:8000/index/active/"+str(code)
send_status = send_mail(email_title,email_body,EMAIL_FROM,[email])
if send_status:
pass
elif send_type == "forget":
email_title = "密码重置链接"
email_body = "请点击下面的密码重置链接:http://127.0.0.1:8000/index/reset/"+str(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
pass
if send_type == "update":
email_title = "重置邮箱激活验证码"
email_body = "你的邮箱激活验证码为:{0}".format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
pass
def random_str():
number = random.randint(100000,999999)
string = str(number)
return string
users.views
class ResetEmailView(View):
'''
发送邮箱验证码
'''
def get(self,request):
email = request.GET.get('email','')
if UserProfile.objects.filter(email= email):
return HttpResponse(json.dumps('{"email":"邮箱已存在"}'),content_type='application/json')
send_register_email(email,'update')
return HttpResponse(json.dumps('{"status":"success"}'),content_type='application/json')
class EmailVerifyView(LoginRequiredMixin, View):
def post(self, request):
email = request.POST.get('email','')
code = request.POST.get('code','')
if EmailVerifyRecord.objects.filter(email = email,code=code, send_type = 'update'):#从数据库查询到当时发送邮件所保存的信息
user = request.user
user.email = email
user.save()
return HttpResponse(json.dumps('{"status":"success"}'),content_type='application/json')
else:
return HttpResponse(json.dumps('{"email":"验证码出错"}'), content_type='application/json')
users.uels.py
path('reset_email/',ResetEmailView.as_view(),name = "reset_email"),
path('send_emailcode/',EmailVerifyView.as_view(),name = "send_emailcode"),
前端代码
HTML代码
<div class="dialogbox changeemai1 changephone" id="jsChangeEmailDialog">
<h1>修改邮箱</h1>
<div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
<p>请输入新的邮箱地址</p>
<form id="jsChangeEmailForm" autocomplete="off">
<div class="box">
<input class="fl change_email" name="email" id="jsChangeEmail" type="text" placeholder="输入重新绑定的邮箱地址">
</div>
<div class="box">
<input class="fl email_code" type="text" id="jsChangeEmailCode" name="code" placeholder="输入邮箱验证码">
<input class="getcode getting" type="button" id="jsChangeEmailCodeBtn" value="获取验证码">
</div>
<div class="error btns change_email_tips" id="jsChangeEmailTips" >请输入...</div>
<div class="button">
<input class="changeemai_btn" id="jsChangeEmailBtn" type="button" value="完成"/>
</div>
<input type='hidden' name='csrfmiddlewaretoken' value='DaP7IUKm9FA9nELA9YUlYYWpyIDdCiIP' />
<input type='hidden' name='csrfmiddlewaretoken' value='799Y6iPeEDNSGvrTu3noBrO4MBLv6enY' />
{% csrf_token %}
</form>
</div>
js代码 ajax 看不懂,勉强能读
//修改个人中心邮箱验证码
function sendCodeChangeEmail($btn){
var verify = verifyDialogSubmit(
[
{id: '#jsChangeEmail', tips: Dml.Msg.epMail, errorTips: Dml.Msg.erMail, regName: 'email', require: true}
]
);
if(!verify){
return;
}
$.ajax({
cache: false,
type: "get",
dataType:'json',
url:"/index/reset_email/",
data:$('#jsChangeEmailForm').serialize(),
async: true,
beforeSend:function(XMLHttpRequest){
$btn.val("发送中...");
$btn.attr('disabled',true);
},
success: function(data){
if(data.email){
Dml.fun.showValidateError($('#jsChangeEmail'), data.email);
}else if(data.status == 'success'){
Dml.fun.showErrorTips($('#jsChangeEmailTips'), "邮箱验证码已发送");
}else if(data.status == 'failure'){
Dml.fun.showValidateError($('#jsChangeEmail'), "邮箱验证码发送失败");
}else if(data.status == 'success'){
}
},
complete: function(XMLHttpRequest){
$btn.val("获取验证码");
$btn.removeAttr("disabled");
}
});
}
//个人资料邮箱修改
function changeEmailSubmit($btn){
var verify = verifyDialogSubmit(
[
{id: '#jsChangeEmail', tips: Dml.Msg.epMail, errorTips: Dml.Msg.erMail, regName: 'email', require: true},
]
);
if(!verify){
return;
}
$.ajax({
cache: false,
type: 'post',
dataType:'json',
url:"/index/send_emailcode/",
data:$('#jsChangeEmailForm').serialize(),
async: true,
beforeSend:function(XMLHttpRequest){
$btn.val("发送中...");
$btn.attr('disabled',true);
$("#jsChangeEmailTips").html("验证中...").show(500);
},
success: function(data) {
if(data.email){
Dml.fun.showValidateError($('#jsChangeEmail'), data.email);
}else if(data.status == "success"){
Dml.fun.showErrorTips($('#jsChangePhoneTips'), "邮箱信息更新成功");
setTimeout(function(){location.reload();},1000);
}else{
Dml.fun.showValidateError($('#jsChangeEmail'), "邮箱信息更新失败");
}
},
complete: function(XMLHttpRequest){
$btn.val("完成");
$btn.removeAttr("disabled");
}
});
}
10.7 修改用户基本信息(手机号,用户名,生日,地址,性别)
后台代码:
user.forms.py
class UserInfoForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['username','birthday','mobile','gender','address']
user.views.py
class ResetUserInfoView(LoginRequiredMixin,View):
def post(self,request):
'''
因为UserInfoForm是继承ModelForm的form,所以user_info可以像model那样直接保存前端的数据到数据库
'''
user_info = UserInfoForm(request.POST,instance=request.user)#后面的request.user很重要,不知道为什么
if user_info.is_valid():
user_info.save()
return HttpResponse(json.dumps('{"status":"success"}'),content_type='application/json')
else:
return HttpResponse(json.dumps(user_info.errors),content_type='application/json')
前端数据:
<form class="perinform" id="jsEditUserForm" autocomplete="off">
<ul class="right">
<li>昵 称:
<input type="text" name="username" id="nick_name" value="{{ request.user.username }}" maxlength="10">
<i class="error-tips"></i>
</li>
<li>生 日:
<input type="text" id="birth_day" name="birthday" value="{{ request.user.birthday|default_if_none:'' }}" readonly="readonly"/>
<i class="error-tips"></i>
</li>
<li>性 别:
<label><input type="radio" name="gender" value="male"{% ifequal request.user.gender 'male' %}checked="checked"{% endifequal %} >男</label>
<label><input type="radio" name="gender" value="female" {% ifequal request.user.gender 'femal' %}checked="checked"{% endifequal %}>女</label>
</li>
<li class="p_infor_city">地 址:
<input type="text" name="address" id="address" placeholder="请输入你的地址" value="{{ request.user.address }}" maxlength="10">
<i class="error-tips"></i>
</li>
<li>手 机 号:
<input type="text" name="mobile" id="mobile" placeholder="请输入你的手机号码" value="{{ request.user.mobile|default_if_none:'' }}" maxlength="10">
</li>
<li>邮 箱:
<input class="borderno" type="text" name="email" readonly="readonly" value="{{ request.user.email }}"/>
<span class="green changeemai_btn">[修改]</span>
</li>
<li class="button heibtn">
<input type="button" id="jsEditUserBtn" value="保存">
</li>
</ul>
<input type='hidden' name='csrfmiddlewaretoken' value='799Y6iPeEDNSGvrTu3noBrO4MBLv6enY' />
{% csrf_token %}
</form>
js 代码
$('#jsEditUserBtn').on('click', function(){
var _self = $(this),
$jsEditUserForm = $('#jsEditUserForm')
verify = verifySubmit(
[
{id: '#nick_name', tips: Dml.Msg.epNickName, require: true}
]
);
if(!verify){
return;
}
// debugger
$.ajax({
cache: false,
type: 'post',
dataType:'json',
url:"/index/info/",
data:$jsEditUserForm.serialize(),
async: true,
beforeSend:function(XMLHttpRequest){
_self.val("保存中...");
_self.attr('disabled',true);
},
success: function(data) {
if(data.username){
_showValidateError($('#nick_name'), data.username);
}else if(data.birthday){
_showValidateError($('#birth_day'), data.birthday);
}else if(data.address){
_showValidateError($('#address'), data.address);
}else if(data.status == "failure"){
Dml.fun.showTipsDialog({
title: '保存失败',
h2: data.msg
});
}else if(data.status == "success"){
Dml.fun.showTipsDialog({
title: '保存成功',
h2: '个人信息修改成功!'
});
setTimeout(function(){window.location.href = window.location.href;},1500);
}
},
complete: function(XMLHttpRequest){
_self.val("保存");
_self.removeAttr("disabled");
}
});
});
10.8 用户课程
后台代码:
class UserCourseView(LoginRequiredMixin,View):
def get(self,request):
usercourses = UserCourse.objects.filter(user = request.user)
return render(request,'usercenter-mycourse.html',{
'usercourses':usercourses,
})
前端代码:
{% for course in usercourses %}
<div class="module1_5 box">
<a href="/course/detail/{{ course.course.id }}">
<img width="214" height="190" class="scrollLoading"
src="{{ MEDIA_URL }}{{ course.course.image }}"/>
</a>
<div class="des">
<a href="course-detail.html"><h2>{{ course.course.name }}</h2></a>
<span class="fl">课时:<i class="key">{{ course.course.learn_times }}</i></span>
<span class="fr">学习人数:{{ course.course.student }}</span>
</div>
<div class="bottom">
<span class="fl">{{ course.course.course_org.name }}</span>
<span class="star fr notlogin"
data-favid="15">{{ course.course.fav_nums }}</span>
</div>
</div>
{% endfor %}
10.9配置用户收藏的课程
后台代码:
、views.py
class UserFavCourseView(LoginRequiredMixin,View):
def get(self,request):
fav_courses = UserFavorate.objects.filter(fav_type = 1,user = request.user)
msg = ''
courses = []
if fav_courses:
for fav in fav_courses:
course = Course.objects.get(id = fav.fav_id)
courses.append(course)
return render(request, 'usercenter-fav-course.html', {
'courses': courses,
'msg':msg
})
else:
msg = '该同学没有收藏任何课程'
return render(request,'usercenter-fav-course.html',{
'msg':msg
})
class UserFavOrgView(LoginRequiredMixin,View):
def get(self,request):
fav_orgs = UserFavorate.objects.filter(fav_type=2, user=request.user)
msg = ''
orgs = []
if fav_orgs:
for fav in fav_orgs:
org = CourseOrg.objects.get(id=fav.fav_id)
orgs.append(org)
return render(request, 'usercenter-fav-org.html', {
'orgs': orgs,
'msg': msg
})
else:
msg = '该同学没有收藏任何课程机构'
return render(request, 'usercenter-fav-org.html', {
'msg': msg
})
class UserFavTeacherView(LoginRequiredMixin,View):
def get(self,request):
fav_teachers = UserFavorate.objects.filter(fav_type=3, user=request.user)
msg = ''
teachers = []
if fav_teachers:
for fav in fav_teachers:
teacher = Teacher.objects.get(id=fav.fav_id)
teachers.append(teacher)
return render(request, 'usercenter-fav-teacher.html', {
'teachers': teachers,
'msg': msg
})
else:
msg = '该同学没有收藏任何老师'
return render(request, 'usercenter-fav-teacher.html', {
'msg': msg
})
urls.py
path('user_favcourse/',UserFavCourseView.as_view(),name = "user_favcourse"),
path('user_favorg/',UserFavOrgView.as_view(),name = "user_favorg"),
path('user_favteacher/',UserFavTeacherView.as_view(),name = "user_favteacher"),
前端:
和普通的配置一样,注意将所有连接改掉
10.10删除用户收藏
前端接js代码
<script type="text/javascript">
$('.jsDeleteFav_course').on('click', function(){
var _this = $(this),
favid = _this.attr('data-favid');
alert(favid)
$.ajax({
cache: false,
type: "POST",
url: "/org/add_fav/",
data: {
fav_type: 1,
fav_id: favid,
},
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
async: true,
success: function(data) {
Dml.fun.winReload();
}
});
});
$('.jsDeleteFav_teacher').on('click', function(){
var _this = $(this),
favid = _this.attr('data-favid');
$.ajax({
cache: false,
type: "POST",
url: "/org/add_fav/",
data: {
fav_type: 3,
fav_id: favid,
},
async: true,
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(data) {
Dml.fun.winReload();
}
});
});
$('.jsDeleteFav_org').on('click', function(){
var _this = $(this),
favid = _this.attr('data-favid');
$.ajax({
cache: false,
type: "POST",
url: "/org/add_fav/",
data: {
fav_type: 2,
fav_id: favid,
},
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
async: true,
success: function(data) {
Dml.fun.winReload();
}
});
});
</script>
10.11用户消息配置,及全局显示
后台页面:
class UserProfile(AbstractUser):#扩展用户信息数据库
birthday = models.DateTimeField(verbose_name=u"生日", null=True, blank=True, default=None)
nick_name = models.CharField(max_length=30, verbose_name=u"昵称", default=u"")
#birthday = models.DateTimeField(verbose_name=u"生日",null=True,blank=True,default=u"")
gender = models.CharField(choices=(("male",u"男"),("femal",u"女")),default=u"",max_length=6)
address = models.CharField(max_length=100,default=u"")
mobile = models.CharField(max_length=11,blank=True,null=True)
image = models.ImageField(upload_to="image/%Y/%m",default=u"image/default.img",max_length=100)#用户头像和默认头像
class Meta:
verbose_name = u"用户信息"
verbose_name_plural = verbose_name
def __str__(self):#admin 管理时返回的题目标题
return self.username
def unread_message(self):
'''
获取当前用户未读的信息的条数
在当前方法内部 引入外部模块,防止循环引用
'''
from operation.models import UserMessage
message = UserMessage.objects.filter(user = self.id,has_read = False)
return message.count()
前端代码直接配置到页面
<a href="/index/usermessage/">
<div class="msg-num"><span id="MsgNum">{{ request.user.unread_message }}</span></div>
</a>