全局导航&个人中心&全局搜索
配置全局导航
让index页面也继承base页面,注意首页有个单独的__index.js__ base页面的导航栏也进行配置
<nav> <div class="nav"> <div class="wp"> <ul> <li ><a href="{% url 'index' %}">首页</a></li> <li > <a href="{% url 'course:list' %}"> 公开课<img class="hot" src="{% static "images/nav_hot.png" %}"> </a> </li> <li > <a href="{% url 'org:teacher_list' %}">授课教师</a> </li> <li class="active" ><a href="{% url 'org:org_list' %}">授课机构</a></li> </ul> </div> </div> </nav>
但是现在我们不知道当前是哪一个页面,因为后端没有传值过来 这里可以使用request.path进行判断 比如http://127.0.0.1:8000/org/teacher_list/,则request.path 就是`/org/teacher_list/`` slice:12 是过滤器,取前12位数 利用这种方法可以达到全局的“active”效果,而不用每个子页面都要去设置“active”了
<ul> <li {% if request.path == '/' %}class="active"{% endif %}><a href="{% url 'index' %}">首页</a></li> <li {% if request.path|slice:'7' == '/course' %}class="active"{% endif %}> <a href="{% url 'course:list' %}"> 公开课<img class="hot" src="{% static 'images/nav_hot.png' %}"> </a> </li> <li {% if request.path|slice:'12' == '/org/teacher' %}class="active"{% endif %}> <a href="{% url 'org:teacher_list' %}">授课教师</a> </li > <li {% if request.path|slice:'9' == '/org/list' %}class="active"{% endif %}> <a href="{% url 'org:org_list' %}">授课机构</a></li> </ul>
全局搜索功能
通过url中加参数keywords来达到全局搜索的功能
以Course搜索为例:
# 搜索功能 search_keywords = request.GET.get('keywords', '') if search_keywords: # icontains是包含的意思(不区分大小写) # Q可以实现多个字段,之间是or的关系 all_course = all_course.filter( Q(name__icontains=search_keywords) | Q(desc__icontains=search_keywords) | Q( detail__icontains=search_keywords))
搜索的代码放在deco-common.js中 如果自己写的url和js文件中的不同,可自行修改
//顶部搜索栏搜索方法 function search_click(){ var type = $('#jsSelectOption').attr('data-value'), keywords = $('#search_keywords').val(), 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 }
课程机构搜索功能
# 机构搜索功能 search_keywords = request.GET.get('keywords', '') if search_keywords: # 在name字段进行操作,做like语句的操作。i代表不区分大小写 # or操作使用Q all_orgs = all_orgs.filter(Q(name__icontains=search_keywords) | Q(desc__icontains=search_keywords))
授课老师搜索功能
# 搜索功能 search_keywords = request.GET.get('keywords', '') if search_keywords: # 在name字段进行操作,做like语句的操作。i代表不区分大小写 # or操作使用Q all_teachers = all_teacher.filter(name__icontains=search_keywords)
个人中心信息展示
新建usercenter-bae.html当模板 进行配置
path("users/", include('users.urls', namespace="users")), from django.urls import path from users.views import UserinfoView app_name = 'users' urlpatterns = [ #用户信息 path("info/", UserinfoView.as_view(),name='user_info'), ] class UserinfoView(LoginRequiredMixin,View): '''用户个人信息''' def get(self,request): return render(request,'usercenter-info.html',{})
前端显示个人信息
<div class="right"> <div class="personal_des "> <div class="head" style="border:1px solid #eaeaea;"> <h1>个人信息</h1> </div> <div class="inforcon"> <div class="left" style="width:242px;"> <iframe id='frameFile' name='frameFile' style='display: none;'></iframe> <form class="clearfix" id="jsAvatarForm" enctype="multipart/form-data" autocomplete="off" method="post" action="/users/image/upload/" target='frameFile'> <label class="changearea" for="avatarUp"> <span id="avatardiv" class="pic"> <img width="100" height="100" class="js-img-show" id="avatarShow" src="{{ MEDIA_URL }}{{ request.user.image }}"/> </span> <span class="fl upload-inp-box" style="margin-left:70px;"> <span class="button btn-green btn-w100" id="jsAvatarBtn">修改头像</span> <input type="file" name="image" id="avatarUp" class="js-img-up"/> </span> </label> {% csrf_token %} </form> <div style="border-top:1px solid #eaeaea;margin-top:30px;"> <a class="button btn-green btn-w100" id="jsUserResetPwd" style="margin:80px auto;width:100px;">修改密码</a> </div> </div> <form class="perinform" id="jsEditUserForm" autocomplete="off"> <ul class="right"> <li>昵 称: <input type="text" name="nick_name" id="nick_name" value="{{ request.user.name }}" maxlength="10"> <i class="error-tips"></i> </li> <li>生 日: <input type="text" id="birth_day" name="birday" value="{{ request.user.birthday }}" 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 "female" %} 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="11"> </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> {% csrf_token %} </form> </div> </div> </div>
修改密码和修改头像
#用户图像上传 path("image/upload/", UploadImageView.as_view(),name='image_upload'),
新建一个用于保存图片的form 这里继承的是ModelForm,该类具有save功能
# 用于文件上传,修改头像 class UploadImageForm(forms.ModelForm): class Meta: model = UserProfile fields = ['image'] class UploadImageView(LoginRequiredMixin,View): '''用户图像修改''' def post(self,request): # 这时候用户上传的文件就已经被保存到image_form了 ,为modelform添加instance值直接保存 image_form = UploadImageForm(request.POST, request.FILES, instance=request.user) if image_form.is_valid(): image_form.save() # 所有验证通过的字段放在cleaned data # # 取出cleaned data中的值,一个dict # image = image_form.cleaned_data['image'] # request.user.image = image # request.user.save() return HttpResponse('{"status":"success"}', content_type='application/json') else: return HttpResponse('{"status":"fail"}', content_type='application/json') #用户个人中心修改密码 path("update/pwd/", UpdatePwdView.as_view(),name='update_pwd'), # 在个人中心修改用户密码 class UpdatePwdView(View): def post(self, request): modiypwd_form = ModifyPwdForm(request.POST) if modiypwd_form.is_valid(): pwd1 = request.POST.get("password1", "") pwd2 = request.POST.get("password2", "") # 如果两次密码不相等,返回错误信息 if pwd1 != pwd2: return HttpResponse('{"status":"fail", "msg":"密码不一致"}', content_type='application/json') # 如果密码一致 user =request.user # 加密成密文 user.password = make_password(pwd2) # save保存到数据库 user.save() return HttpResponse('{"status":"success"}', content_type='application/json') # 验证失败说明密码位数不够。 else: return HttpResponse('{"status":"fail", "msg":"填写错误请检查"}', content_type='application/json')
Ajxa代码放在deco-user.js里面 如果url不正确可自行配置' 如果遇到403,检查base中的csrf_token是否填写
发送修改邮箱验证码
有两个接口需要完成。点击获取验证码时,后台需要向用户新邮箱发送验证码。 邮箱如果出错,会返回错误信息。 输入了邮箱和验证码,验证是否匹配。 给EmailVerifyRecord再添加一个选择类型
SEND_CHOICES = ( ("register", "注册"), ("forget", "找回密码"), ("update_email", "修改邮箱") ) #发送邮箱验证码 path("sendemail_code/", SendEmailCodeView.as_view(),name='sendemail_code'), # 发送邮箱验证码view class SendEmailCodeView(LoginRequiredMixin, View): def get(self,request): # 取出需要发送的邮件 email = request.GET.get("email", "") # 不能是已注册的邮箱 if UserProfile.objects.filter(email=email): return HttpResponse('{"email":"邮箱已经存在"}', content_type='application/json') send_register_eamil(email, "update_email") return HttpResponse('{"status":"success"}', content_type='application/json')
修改utils/email_send.py
if send_type == "update_email": email_title = "慕课在线 修改邮箱" email_body = "验证码:{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果发送成功 if send_status: pass
修改邮箱
#修改邮箱 path("update_email/", UpdateEmailView.as_view(),name='update_email'), # 修改邮箱的view: class UpdateEmailView(LoginRequiredMixin, View): def post(self, request): email = request.POST.get("email", "") code = request.POST.get("code", "") existed_records = EmailVerifyRecord.objects.filter(email=email, code=code, send_type='update_email') if existed_records: user = request.user user.email = email user.save() return HttpResponse('{"status":"success"}', content_type='application/json') else: return HttpResponse('{"email":"验证码无效"}', content_type='application/json')
个人信息修改
# 个人中心信息修改 class UserInfoForm(forms.ModelForm): class Meta: model = UserProfile fields = ['nick_name','gender','birthday','address','mobile']
给UserinfoView添加post方法
class UserinfoView(LoginRequiredMixin,View): '''用户个人信息''' def get(self,request): return render(request,'usercenter-info.html',{}) def post(self, request): # 需要指明instance。不然无法修改,而是新增用户 user_info_form = UserInfoForm(request.POST, instance=request.user) if user_info_form.is_valid(): user_info_form.save() return HttpResponse('{"status":"success"}', content_type='application/json') else: return HttpResponse(json.dumps(user_info_form.errors), content_type='application/json')
我的课程
# 用户中心我的课程 path('mycourse/', MyCourseView.as_view(), name="mycourse"), # 个人中心页我的课程 class MyCourseView(LoginRequiredMixin, View): def get(self, request): user_courses = UserCourse.objects.filter(user=request.user) return render(request, "usercenter-mycourse.html", { "user_courses":user_courses, }) {% block custom_right_content %} <div class="right" > <div class="personal_des Releasecont"> <div class="head"> <h1>我的课程</h1> </div> </div> <div class="personal_des permessage"> <div class="companycenter"> <div class="group_list brief"> {% for cours in user_courses %} <div class="module1_5 box"> <a href="course-detail.html"> <img width="214" height="190" class="scrollLoading" src="{{ MEDIA_URL }}{{ cours.course.image }}"/> </a> <div class="des"> <a href="course-detail.html"><h2>{{ cours.course.name }}</h2></a> <span class="fl">课时:<i class="key">{{ cours.course.learn_times }}</i></span> <span class="fr">学习人数:{{ cours.course.students }}</span> </div> <div class="bottom"> <span class="fl">{{ cours.course.course_org.name }}</span> <span class="star fr notlogin" data-favid="15">{{ cours.course.course_org.fav_nums }}</span> </div> </div> {% endfor %} </div> </div> </div> </div> {% endblock %}
我的收藏--课程机构
# 我的收藏--课程机构 path('myfav/org/', MyFavOrgView.as_view(), name="myfav_org"), # 我收藏的课程机构 class MyFavOrgView(LoginRequiredMixin, View): def get(self, request): org_list = [] fav_orgs= UserFavorite.objects.filter(user=request.user, fav_type=2) # 上面的fav_orgs只是存放了id。我们还需要通过id找到机构对象 for fav_org in fav_orgs: # 取出fav_id也就是机构的id。 org_id = fav_org.fav_id # 获取这个机构对象 org = CourseOrg.objects.get(id=org_id) org_list.append(org) return render(request, "usercenter-fav-org.html", { "org_list": org_list, })
我的收藏--授课讲师
Teacher添加一个方法
def get_course_nums(self): return self.course_set.all().count() # 我收藏的授课讲师 path('myfav/teacher/', MyFavTeacherView.as_view(), name="myfav_teacher"), class MyFavTeacherView(LoginRequiredMixin, View): '''我收藏的授课讲师''' def get(self, request): teacher_list = [] fav_teachers = UserFavorite.objects.filter(user=request.user, fav_type=3) for fav_teacher in fav_teachers: teacher_id = fav_teacher.fav_id teacher = Teacher.objects.get(id=teacher_id) teacher_list.append(teacher) return render(request, "usercenter-fav-teacher.html", { "teacher_list": teacher_list, })
我的收藏--公开课程
#我的收藏--课程 path('myfav/course/', MyFavCourseView.as_view(), name="myfav_course"), class MyFavCourseView(LoginRequiredMixin,View): """ 我收藏的课程 """ def get(self, request): course_list = [] fav_courses = UserFavorite.objects.filter(user=request.user, fav_type=1) for fav_course in fav_courses: course_id = fav_course.fav_id course = Course.objects.get(id=course_id) course_list.append(course) return render(request, 'usercenter-fav-course.html', { "course_list":course_list, })
我的消息页面
#我的消息 path('my_message/', MyMessageView.as_view(), name="my_message"), class MyMessageView(LoginRequiredMixin, View): '''我的消息''' def get(self, request): all_message = UserMessage.objects.filter(user= request.user.id) try: page = request.GET.get('page', 1) except PageNotAnInteger: page = 1 p = Paginator(all_message, 4,request=request) messages = p.page(page) return render(request, "usercenter-message.html", { "messages":messages, })
取消收藏
修改usercenter-bae.html模板中的Ajax代码
修改HTML文件
注册时发生欢迎消息
# 写入欢迎注册消息 user_message = UserMessage() user_message.user = user_profile.id user_message.message = "欢迎注册!!" user_message.save()
页面顶部小喇叭
所有页面都要读取一个共同的变量:未读消息的数量。我们需要向request中注入这个变量 所有页面都有request.user对象。所以我们在userprofile中自定义方法,
# 获取用户未读消息的数量 def unread_nums(self): from operation.models import UserMessage return UserMessage.objects.filter(user=self.id).count()
退出
# 退出功能url path('logout/', LogoutView.as_view(), name="logout"), class LogoutView(View): def get(self, request): # django自带的logout logout(request) # 重定向到首页, return HttpResponseRedirect(reverse("index"))
点击数加1
课程 CourseInfoView
course.students += 1 course.save()
TeacherDetailView
teacher.click_nums += 1 teacher.save()
OrgHomeView
course_org.click_nums += 1 course_org.save()
收藏数
organization/views.py中的 AddFavView
if exist_records: # 如果记录已经存在, 则表示用户取消收藏 exist_records.delete() if int(type) == 1: course = Course.objects.get(id=int(id)) course.fav_nums -= 1 if course.fav_nums < 0: course.fav_nums = 0 course.save() elif int(type) == 2: org = CourseOrg.objects.get(id=int(id)) org.fav_nums -= 1 if org.fav_nums < 0: org.fav_nums = 0 org.save() elif int(type) == 3: teacher = Teacher.objects.get(id=int(id)) teacher.fav_nums -= 1 if teacher.fav_nums < 0: teacher.fav_nums = 0 teacher.save() return HttpResponse('{"status":"success", "msg":"收藏"}', content_type='application/json') else: user_fav = UserFavorite() # 过滤掉未取到fav_id type的默认情况 if int(type) > 0 and int(id) > 0: user_fav.fav_id = int(id) user_fav.fav_type = int(type) user_fav.user = request.user user_fav.save() if int(type) == 1: course = Course.objects.get(id=int(id)) course.fav_nums += 1 course.save() elif int(type) == 2: org = CourseOrg.objects.get(id=int(id)) org.fav_nums += 1 org.save() elif int(type) == 3: teacher = Teacher.objects.get(id=int(id)) teacher.fav_nums += 1 teacher.save() return HttpResponse('{"status":"success", "msg":"已收藏"}', content_type='application/json')
修改消息已读
class MyMessageView(LoginRequiredMixin, View): '''我的消息''' def get(self, request): all_message = UserMessage.objects.filter(user= request.user.id) # 用户进入个人中心消息页面,清空未读消息记录 all_unread_messages = all_message.filter(has_read=False) for unread_message in all_unread_messages: unread_message.has_read = True unread_message.save() try: page = request.GET.get('page', 1) except PageNotAnInteger: page = 1 p = Paginator(all_message, 4, request=request) messages = p.page(page) return render(request, "usercenter-message.html", { "messages":messages, })
个人中心左侧active状态
<div class="left"> <ul> <li {% ifequal '/users/info/' request.path %} class="active2" {% endifequal %}><a href="{% url 'users:user_info' %}">个人资料</a></li> <li {% ifequal '/users/mycourse/' request.path %} class="active2" {% endifequal %}><a href="{% url 'users:mycourse' %}">我的课程</a></li> <li {% ifequal '/users/myfav/' request.path|slice:'13' %} class="active2" {% endifequal %}><a href="{% url 'users:myfav_org' %}">我的收藏</a></li> <li {% ifequal '/users/my_message/' request.path %} class="active2" {% endifequal %}> <a href="{% url 'users:my_message' %}" style="position: relative;"> 我的消息 </a> </li> </ul> </div>