(項目)在線教育平台(十一)


十五、首頁全局配置

1、首頁前端頁面配置

  將index.html繼承base.html頁面,修改繼承的block地方:

  修改base.html頁面中導航欄選中狀態的代碼:

2、全局搜索功能

  首頁的全局搜索功能可以對課程,機構,教師進行全局搜索,搜索的代碼放在deco-common.js文件中:

 1 //頂部搜索欄搜索方法
 2 function search_click(){
 3     var type = $('#jsSelectOption').attr('data-value'),
 4         keywords = $('#search_keywords').val(),
 5         request_url = '';
 6     if(keywords == ""){
 7         return
 8     }
 9     if(type == "course"){
10         request_url = "/course/list?keywords="+keywords
11     }else if(type == "teacher"){
12         request_url = "/org/teacher/list?keywords="+keywords
13     }else if(type == "org"){
14         request_url = "/org/list?keywords="+keywords
15     }
16     window.location.href = request_url
17 }

  只需要在課程列表接口、機構列表接口、講師列表接口中加入搜索的邏輯即可:

 1 class CourseListView(View):
 2     """課程列表頁"""
 3     def get(self, request):
 4         # 獲取所有的課程
 5         all_courses = Course.objects.all()
 6 
 7         # 排序(學習人數,點擊數)
 8         sort = request.GET.get('sort', '')
 9         if sort:
10             if sort == 'students':
11                 all_courses = all_courses.order_by('-students')
12             elif sort == 'hot':
13                 all_courses = all_courses.order_by('-click_nums')
14 
15         # 熱門課程
16         hot_courses = all_courses.order_by('-click_nums')[:2]
17 
18         # 搜索
19         search_keywords = request.GET.get('keywords', '')
20         if search_keywords:
21             all_courses = all_courses.filter(Q(name__icontains=search_keywords)|
22                                              Q(desc__icontains=search_keywords)|
23                                              Q(detail__icontains=search_keywords))
24 
25         # 分頁
26         try:
27             page = request.GET.get('page', 1)
28         except PageNotAnInteger:
29             page = 1
30         p = Paginator(all_courses, 3, request=request)
31         courses = p.page(page)
32 
33         return render(request, 'course-list.html', {
34             'all_courses': courses,
35             'sort': sort,
36             'hot_courses': hot_courses
37         })
課程列表接口
 1 class OrgView(View):
 2     """機構列表"""
 3     def get(self, request):
 4         # 取出所有的機構
 5         all_orgs = CourseOrg.objects.all()
 6 
 7         # 取出所有的城市
 8         all_citys = CityDict.objects.all()
 9 
10         # 搜索
11         search_keywords = request.GET.get('keywords', '')
12         if search_keywords:
13             all_orgs = all_orgs.filter(Q(name__icontains=search_keywords)|
14                                        Q(desc__icontains=search_keywords))
15 
16         # 排名篩選(根據點擊量排名)
17         hot_orgs = all_orgs.order_by('-click_nums')[:3]
18 
19         # 學習人數和課程數排名篩選
20         sort = request.GET.get('sort', '')
21         if sort:
22             if sort == 'students':
23                 all_orgs = all_orgs.order_by('-students')
24             elif sort == 'courses':
25                 all_orgs = all_orgs.order_by('-course_nums')
26 
27         # 城市篩選(從request中獲取城市的id)
28         city_id = request.GET.get('city', '')
29         if city_id:
30             all_orgs = all_orgs.filter(city_id=int(city_id))
31 
32         # 類別篩選(從request中獲取機構類別ct)
33         category = request.GET.get('ct', '')
34         if category:
35             all_orgs = all_orgs.filter(category=category)
36 
37         # 篩選完再統計數量
38         org_nums = all_orgs.count()
39 
40         # 分頁
41         try:
42             page = request.GET.get('page', 1)
43         except PageNotAnInteger:
44             page = 1
45         p = Paginator(all_orgs, 5, request=request)
46         orgs = p.page(page)
47 
48         return render(request, 'org-list.html', {
49             'all_orgs': orgs,
50             'all_citys': all_citys,
51             'org_nums': org_nums,
52             'city_id': city_id,
53             'category': category,
54             'hot_orgs': hot_orgs,
55             'sort': sort
56         })
機構列表接口
 1 class TeacherListView(View):
 2     """講師列表頁面"""
 3     def get(self, request):
 4         # 獲取所有的講師
 5         all_teachers = Teacher.objects.all()
 6 
 7         # 搜索
 8         search_keywords = request.GET.get('keywords', '')
 9         if search_keywords:
10             all_teachers = all_teachers.filter(name__icontains=search_keywords)
11 
12         # 統計講師的總數
13         teacher_nums = all_teachers.count()
14 
15         # 排序,按點擊數排序
16         sort = request.GET.get('sort', '')
17         if sort:
18             if sort == 'hot':
19                 all_teachers = all_teachers.order_by('-click_nums')
20 
21         # 講師排行版
22         teacher_sorted = all_teachers.order_by('-click_nums')[:3]
23 
24         # 分頁
25         try:
26             page = request.GET.get('page', 1)
27         except PageNotAnInteger:
28             page = 1
29         p = Paginator(all_teachers, 5, request=request)
30         teachers = p.page(page)
31 
32         return render(request, 'teachers-list.html', {
33             'all_teachers': teachers,
34             'teacher_nums': teacher_nums,
35             'sort': sort,
36             'teacher_sorted': teacher_sorted
37         })
講師列表接口

十六、個人中心

1、個人中心頁面

1.1 個人中心前端頁面配置

  在templates目錄下新建usercenter-base.html文件,作為個人中心頁面的母版,然后將usercenter-info.html頁面拷貝到該目錄下,並把其中的內容拷貝到母版中,修改其中需要block的地方:

  1 {% load staticfiles %}
  2 
  3 <!DOCTYPE html>
  4 <html>
  5 
  6 <head>
  7     <meta charset="UTF-8">
  8     <meta name="renderer" content="webkit">
  9     <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
 10     <title>{% block title %}個人信息- 知能網{% endblock %}</title>
 11     <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
 12     <link rel="stylesheet" type="text/css" href="{% static 'css/animate.css' %}">
 13     <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
 14     <link rel="stylesheet" type="text/css" href="{% static 'js/plugins/queryCity/css/cityLayout.css' %}">
 15 
 16     <link rel="stylesheet" type="text/css" href="{% static 'css/lq.datetimepick.css' %}"/>
 17     {% block custom_css %}{% endblock %}
 18 
 19 
 20     <script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
 21     <script src="{% static 'js/jquery-migrate-1.2.1.min.js' %}" type="text/javascript"></script>
 22 
 23 </head>
 24 <body>
 25 <section class="headerwrap headerwrap2">
 26     <header>
 27         <div  class="header2 header">
 28              <div class="top">
 29                 <div class="wp">
 30                     <div class="fl"><p>服務電話:<b>13993601652</b></p></div>
 31                     <!--登錄后跳轉-->
 32 
 33 
 34                         <div class="personal">
 35                             <dl class="user fr">
 36                                 <dd>bobby<img class="down fr" src="{% static 'images/top_down.png' %}"/></dd>
 37                                 <dt><img width="20" height="20" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
 38                             </dl>
 39                             <div class="userdetail">
 40                                 <dl>
 41                                     <dt><img width="80" height="80" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
 42                                     <dd>
 43                                         <h2>django</h2>
 44                                         <p>bobby</p>
 45                                     </dd>
 46                                 </dl>
 47                                 <div class="btn">
 48                                     <a class="personcenter fl" href="usercenter-info.html">進入個人中心</a>
 49                                     <a class="fr" href="/logout/">退出</a>
 50                                 </div>
 51                             </div>
 52                         </div>
 53                         <a href="usercenter-message.html">
 54                             <div class="msg-num"><span id="MsgNum">0</span></div>
 55                         </a>
 56 
 57 
 58                 </div>
 59             </div>
 60 
 61     <div class="middle">
 62         <div class="wp">
 63             <a href="index.html"><img class="fl" src="{% static 'images/logo2.png' %}"/></a>
 64             <h1>我的知能網</h1>
 65         </div>
 66     </div>
 67             </div>
 68     </header>
 69 </section>
 70 
 71 
 72 
 73 <!--crumbs start-->
 74 {% block custom_bread %}
 75 
 76 {% endblock %}
 77 
 78 
 79 <section>
 80     <div class="wp list personal_list">
 81     <div class="left">
 82         <ul>
 83             <li class="active2"><a href="usercenter-info.html">個人資料</a></li>
 84             <li ><a href="usercenter-mycourse.html">我的課程</a></li>
 85             <li ><a href="usercenter-fav-course.html">我的收藏</a></li>
 86             <li >
 87                 <a href="usercenter-message.html" style="position: relative;">
 88                     我的消息
 89                 </a>
 90             </li>
 91         </ul>
 92     </div>
 93 
 94 
 95     {% block custom_right_content %}
 96     
 97     {% endblock %}
 98 
 99 
100     </div>
101 </section>
102 
103 <!--sidebar start-->
104 <section>
105     <ul class="sidebar">
106         <li class="qq">
107             <a target="_blank" href="http://wpa.qq.com/msgrd?v=3&uin=2023525077&site=qq&menu=yes"></a>
108         </li>
109         <li class="totop"></li>
110     </ul>
111 </section>
112 <!--sidebar end-->
113 <!--header start-->
114 
115 <div class="dialog" id="jsDialog">
116     <div class="successbox dialogbox" id="jsSuccessTips">
117         <h1>成功提交</h1>
118         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
119         <div class="cont">
120             <h2>您的需求提交成功!</h2>
121             <p></p>
122         </div>
123     </div>
124     <!--提示彈出框-->
125     <div class="bidtips dialogbox promptbox" id="jsComfirmDialig">
126         <h1>確認提交</h1>
127         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
128         <div class="cont">
129             <h2>您確認提交嗎?</h2>
130             <dd class="autoTxtCount">
131                 <div class="button">
132                     <input type="button" class="fl half-btn" value="確定" id="jsComfirmBtn"/>
133                     <span class="fr half-btn jsCloseDialog">取消</span>
134                 </div>
135             </dd>
136         </div>
137     </div>
138     <div class="resetpwdbox dialogbox" id="jsResetDialog">
139         <h1>修改密碼</h1>
140         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
141         <div class="cont">
142             <form id="jsResetPwdForm" autocomplete="off">
143                 <div class="box">
144                     <span class="word2" >&nbsp;&nbsp;&nbsp;&nbsp;</span>
145                     <input type="password" id="pwd" name="password1" placeholder="6-20位非中文字符"/>
146                 </div>
147                 <div class="box">
148                     <span class="word2" >確定密碼</span>
149                     <input type="password" id="repwd" name="password2" placeholder="6-20位非中文字符"/>
150                 </div>
151                 <div class="error btns" id="jsResetPwdTips"></div>
152                 <div class="button">
153                     <input id="jsResetPwdBtn" type="button" value="提交" />
154                 </div>
155                 <input type='hidden' name='csrfmiddlewaretoken' value='DaP7IUKm9FA9nELA9YUlYYWpyIDdCiIP' />
156             <input type='hidden' name='csrfmiddlewaretoken' value='799Y6iPeEDNSGvrTu3noBrO4MBLv6enY' />
157             </form>
158         </div>
159     </div>
160     <div class="dialogbox changeemai1 changephone" id="jsChangeEmailDialog">
161         <h1>修改郵箱</h1>
162         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
163         <p>請輸入新的郵箱地址</p>
164         <form id="jsChangeEmailForm" autocomplete="off">
165             <div class="box">
166                 <input class="fl change_email" name="email" id="jsChangeEmail" type="text" placeholder="輸入重新綁定的郵箱地址">
167             </div>
168             <div class="box">
169                 <input class="fl email_code" type="text" id="jsChangeEmailCode" name="code" placeholder="輸入郵箱驗證碼">
170                 <input class="getcode getting" type="button" id="jsChangeEmailCodeBtn" value="獲取驗證碼">
171             </div>
172             <div class="error btns change_email_tips" id="jsChangeEmailTips" >請輸入...</div>
173             <div class="button">
174                 <input class="changeemai_btn" id="jsChangeEmailBtn" type="button" value="完成"/>
175             </div>
176             <input type='hidden' name='csrfmiddlewaretoken' value='DaP7IUKm9FA9nELA9YUlYYWpyIDdCiIP' />
177         <input type='hidden' name='csrfmiddlewaretoken' value='799Y6iPeEDNSGvrTu3noBrO4MBLv6enY' />
178         </form>
179     </div>
180 
181     <div  class="noactivebox dialogbox" id="jsUnactiveForm" >
182         <h1>郵件驗證提示</h1>
183         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
184         <div class="center">
185             <img src="../images/send.png"/>
186             <p>我們已經向您的郵箱<span class="green" id="jsEmailToActive">12@13.com</span>發送了郵件,<br/>為保證您的賬號安全,請及時驗證郵箱</p>
187             <p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去郵箱驗證</a></p>
188             <p class="zy_success upmove"></p>
189             <p style="display: none;" class="sendE2">沒收到,您可以查看您的垃圾郵件和被過濾郵件,也可以再次發送驗證郵件(<span class="c5c">60s</span></p>
190             <p class="sendE">沒收到,您可以查看您的垃圾郵件和被過濾郵件,<br/>也可以<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次發送驗證郵件</span></p>
191         </div>
192     </div>
193     <div class="resetpassbox dialogbox" id="jsSetNewPwd">
194         <h1>重新設置密碼</h1>
195         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
196         <p class="green">請輸入新密碼</p>
197         <form id="jsSetNewPwdForm">
198             <div class="box">
199                 <span class="word2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
200                 <input type="password" name="password" id="jsResetPwd" placeholder="請輸入新密碼"/>
201             </div>
202             <div class="box">
203                 <span class="word2">&nbsp;&nbsp;&nbsp;</span>
204                 <input type="password" name="password2" id="jsResetPwd2" placeholder="請再次輸入新密碼"/>
205             </div>
206             <div class="box">
207                 <span class="word2">&nbsp;&nbsp;&nbsp;&nbsp;</span>
208                 <input type="text" name="code" id="jsResetCode" placeholder="請輸入手機驗證碼"/>
209             </div>
210             <div class="error btns" id="jsSetNewPwdTips"></div>
211             <div class="button">
212                 <input type="hidden" name="mobile" id="jsInpResetMobil" />
213                 <input id="jsSetNewPwdBtn" type="button" value="提交" />
214             </div>
215             <input type='hidden' name='csrfmiddlewaretoken' value='DaP7IUKm9FA9nELA9YUlYYWpyIDdCiIP' />
216         </form>
217     </div>
218     <div class="forgetbox dialogbox">
219         <h1>忘記密碼</h1>
220         <div class="close jsCloseDialog"><img src="../images/dig_close.png"/></div>
221         <div class="cont">
222             <form id="jsFindPwdForm" autocomplete="off">
223                 <input type='hidden' name='csrfmiddlewaretoken' value='DaP7IUKm9FA9nELA9YUlYYWpyIDdCiIP' />
224                 <div class="box">
225                     <span class="word2" >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
226                     <input type="text" id="account" name="account" placeholder="手機/郵箱"/>
227                 </div>
228                 <div class="box">
229                     <span class="word3">驗證碼</span>
230                     <input autocomplete="off" class="form-control-captcha find-password-captcha" id="find-password-captcha_1" name="captcha_f_1" placeholder="請輸入驗證碼" type="text" /> <input class="form-control-captcha find-password-captcha" id="find-password-captcha_0" name="captcha_f_0" placeholder="請輸入驗證碼" type="hidden" value="5f3c00e47fb1be12d2fd15b9a860711597721b3f" /> &nbsp;<img src="/captcha/image/5f3c00e47fb1be12d2fd15b9a860711597721b3f/" alt="captcha" class="captcha" />
231                 </div>
232                 <div class="error btns" id="jsForgetTips"></div><!--忘記密碼錯誤-->
233                 <div class="button">
234                     <input type="hidden" name="sms_type" value="1">
235                     <input id="jsFindPwdBtn" type="button" value="提交" />
236                 </div>
237             </form>
238         </div>
239     </div>
240 </div>
241 <div class="bg" id="dialogBg"></div>
242 
243 
244 <script src="{% static 'js/selectUi.js' %}" type='text/javascript'></script>
245 <script type="text/javascript" src="{% static 'js/plugins/laydate/laydate.js' %}"></script>
246 <script src="{% static 'js/plugins/layer/layer.js' %}"></script>
247 <script src="{% static 'js/plugins/queryCity/js/public.js' %}" type="text/javascript"></script>
248 <script src="{% static 'js/unslider.js' %}" type="text/javascript"></script>
249 <script src="{% static 'js/plugins/jquery.scrollLoading.js' %}"  type="text/javascript"></script>
250 <script src="{% static 'js/validateDialog.js' %}"  type="text/javascript"></script>
251 <script src="{% static 'js/deco-common.js' %}"  type="text/javascript"></script>
252 
253 <script src='{% static 'js/plugins/jquery.upload.js' %}' type='text/javascript'></script>
254 <script src="{% static 'js/validate.js' %}" type="text/javascript"></script>
255 <script src="{% static 'js/deco-user.js' %}"></script>
256 
257 
258 {% block custom_js %}
259 
260 {% endblock %}
261 
262 <script type="text/javascript">
263     $('.jsDeleteFav_course').on('click', function(){
264         var _this = $(this),
265             favid = _this.attr('data-favid');
266         alert(favid)
267         $.ajax({
268                 cache: false,
269                 type: "POST",
270                 url: "/org/add_fav/",
271                 data: {
272                     fav_type: 1,
273                     fav_id: favid,
274                     csrfmiddlewaretoken: '799Y6iPeEDNSGvrTu3noBrO4MBLv6enY'
275                 },
276                 async: true,
277                 success: function(data) {
278                     Dml.fun.winReload();
279                 }
280             });
281     });
282 
283     $('.jsDeleteFav_teacher').on('click', function(){
284             var _this = $(this),
285                 favid = _this.attr('data-favid');
286             $.ajax({
287                     cache: false,
288                     type: "POST",
289                     url: "/org/add_fav/",
290                     data: {
291                         fav_type: 3,
292                         fav_id: favid,
293                         csrfmiddlewaretoken: '799Y6iPeEDNSGvrTu3noBrO4MBLv6enY'
294                     },
295                     async: true,
296                     success: function(data) {
297                         Dml.fun.winReload();
298                     }
299                 });
300         });
301 
302 
303     $('.jsDeleteFav_org').on('click', function(){
304             var _this = $(this),
305                 favid = _this.attr('data-favid');
306             $.ajax({
307                     cache: false,
308                     type: "POST",
309                     url: "/org/add_fav/",
310                     data: {
311                         fav_type: 2,
312                         fav_id: favid,
313                         csrfmiddlewaretoken: '799Y6iPeEDNSGvrTu3noBrO4MBLv6enY'
314                     },
315                     async: true,
316                     success: function(data) {
317                         Dml.fun.winReload();
318                     }
319                 });
320         });
321 </script>
322 
323 
324 <script>
325         var shareUrl = '',
326             shareText = '',
327             shareDesc = '',
328             shareComment = '';
329         $(function () {
330             $(".bdsharebuttonbox a").mouseover(function () {
331                 var type = $(this).attr('data-cmd'),
332                     $parent = $(this).parent('.bdsharebuttonbox'),
333                     fxurl = $parent.attr('data-url'),
334                     fxtext = $parent.attr('data-text'),
335                     fxdesc = $parent.attr('data-desc'),
336                     fxcomment = $parent.attr('data-comment');
337                 switch (type){
338                     case 'tsina':
339                     case 'tqq':
340                     case 'renren':
341                             shareUrl = fxurl;
342                             shareText = fxdesc;
343                             shareDesc = '';
344                             shareComment = '';
345                         break;
346                     default :
347                             shareUrl = fxurl;
348                             shareText = fxtext;
349                             shareDesc = fxdesc;
350                             shareComment = fxcomment;
351                         break;
352                 }
353             });
354         });
355         function SetShareUrl(cmd, config) {
356             if (shareUrl) {
357                 config.bdUrl = "" + shareUrl;
358             }
359             if(shareText){
360                 config.bdText = shareText;
361             }
362             if(shareDesc){
363                 config.bdDesc = shareDesc;
364             }
365             if(shareComment){
366                 config.bdComment = shareComment;
367             }
368 
369             return config;
370         }
371         window._bd_share_config = {
372             "common": {
373                 "onBeforeClick":SetShareUrl,
374                 "bdPic":"",
375                 "bdMini":"2",
376                 "searchPic":"1",
377                 "bdMiniList":false
378             },
379             "share": {
380                 "bdSize":"16"
381             }
382         };
383     with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com../api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
384 </script>
385 </body>
386 </html>
usercenter-base.html

  然后將usercenter-info.html頁面繼承母版:

1.2 個人信息接口

  在users/views.py中編寫個人中心的接口:

1 class UserInfoView(View):
2     """個人中心頁面"""
3     def get(self, request):
4         return render(request, 'usercenter-info.html', {
5 
6         })

  先在users下新建urls.py文件,然后在MxOnline/urls.py中配置個人信息的路由分發:

1 urlpatterns = [
2     path('users/', include('users.urls', namespace='users')),  # 個人信息
3 ]

  在users/urls.py中配置個人中心頁面的url:

 1 from django.urls import path
 2 
 3 from .views import UserInfoView
 4 
 5 
 6 app_name = 'users'
 7 
 8 urlpatterns = [
 9     path('info/', UserInfoView.as_view(), name='user_info'),  # 個人中心
10 ]

  修改個人中心頁面中顯示個人信息的代碼:

  要完善個人信息接口,首先需要在form.py中加入個人信息的form表單驗證:

1 class UserInfoForm(forms.ModelForm):
2     """個人信息表單驗證"""
3     class Meta:
4         model = UserProfile
5         fields = ['nick_name', 'gender', 'birthday', 'address', 'mobile'] 

  然后完善個人信息接口中更新個人信息的邏輯:

 1 class UserInfoView(View):
 2     """個人中心頁面"""
 3     def get(self, request):
 4         return render(request, 'usercenter-info.html')
 5 
 6     def post(self, request):
 7         userinfo_form = UserInfoForm(request.POST, instance=request.user)
 8         if userinfo_form.is_valid():
 9             userinfo_form.save()
10             return HttpResponse('{"status": "success"}', content_type='application/json')
11         else:
12             return HttpResponse(json.dumps(userinfo_form.errors), content_type='application/json')

  然后修改個人中心頁面中顯示個人信息的代碼,加上{% csrf_token %}:

1.3 修改用戶頭像接口

  首先在form.py文件中加入頭像的ModelForm表單驗證:

1 class UploadImageForm(forms.ModelForm):
2     """修改用戶頭像"""
3     class Meta:
4         model = UserProfile
5         fields = ['image']

  然后完成修改用戶頭像的接口:

 1 class UploadImageView(LoginRequiredMixin, View):
 2     """用戶頭像修改"""
 3     def post(self, request):
 4         # 上傳的文件都在request.FILES里面獲取
 5         image_form = UploadImageForm(request.POST, request.FILES)
 6         if image_form.is_valid():
 7             # 將獲取到的圖片保存到數據庫
 8             image = image_form.cleaned_data['image']
 9             request.user.image = image
10             request.user.save()
11 
12             return HttpResponse('{"status": "success"}', content_type='application/json')
13         else:
14             return HttpResponse('{"status": "fail"}', content_type='application/json')

  配置url:

1 from .views import UploadImageView
2 
3 
4 urlpatterns = [
5     path('image/upload', UploadImageView.as_view(), name='image_upload'),  # 修改頭像
6 ]

  修改個人中心頁面顯示用戶頭像的代碼:

1.4 修改密碼接口

 1 class UpdatePwdView(LoginRequiredMixin, View):
 2     """修改密碼"""
 3     def post(self, request):
 4         modify_form = ModifyPwdForm(request.POST)
 5         if modify_form.is_valid():
 6             # 從request中獲取密碼
 7             pwd1 = request.POST.get('password1', '')
 8             pwd2 = request.POST.get('password2', '')
 9             if pwd1 != pwd2:
10                 return HttpResponse('{"status": "fail", "mag": "密碼不一致"}', content_type='application/json')
11 
12             # 保存密碼
13             user = request.user
14             user.password = make_password(pwd2)
15             user.save()
16 
17             return HttpResponse('{"status": "success"}', content_type='application/json')
18         else:
19             return HttpResponse(json.dumps(modify_form.errors), content_type='application/json')

  配置url:

1 from .views import UpdatePwdView
2 
3 urlpatterns = [
4     path('update/pwd/', UpdatePwdView.as_view(), name='update_pwd'),  # 修改密碼
5 ]

  修改密碼的ajax代碼在deco-user.js文件中,現在只需要在usercenter-base.html頁面中修改密碼的form表單中加上{% csrf_token %}:

  修改完成之后需要重新登錄,現在修改右上角的登錄狀態以及顯示信息,在usercenter-base.html頁面中:

  同時將base.html頁面和org_base.html頁面也修改了。

1.5 發送郵箱驗證碼接口

  首先在郵箱驗證碼的model中添加SEND_CHOICES的選項,並將發送類型字段的長度改成30:

 1 class EmailVerifyRecord(models.Model):
 2     """郵箱驗證碼"""
 3     SEND_CHOICES = (
 4         ('register', '注冊'),
 5         ('forget', '找回密碼'),
 6         ('update_email', '修改郵箱')
 7     )
 8 
 9     code = models.CharField('驗證碼', max_length=20)
10     email = models.EmailField('郵箱', max_length=50)
11     send_type = models.CharField('發送類型', max_length=30, choices=SEND_CHOICES)
12     send_time = models.DateTimeField('發送時間', default=datetime.now)
13 
14     class Meta:
15         verbose_name = '郵箱驗證碼'
16         verbose_name_plural = verbose_name

  遷移數據庫。

 1 class SendEmailCodeView(LoginRequiredMixin, View):
 2     """發送郵箱驗證碼"""
 3     def get(self, request):
 4         # 從request中獲取email
 5         email = request.GET.get('email', '')
 6 
 7         # 判斷郵箱是否已經存在
 8         if UserProfile.objects.filter(email=email):
 9             return HttpResponse('{"email": "郵箱已存在"}', content_type='application/json')
10 
11         # 發送郵件
12         send_register_email(email, 'update_email')
13         return HttpResponse('{"status": "success"}', content_type='application/json')

  配置url:

from .views import SendEmailCodeView

urlpatterns = [
    path("sendemail_code/", SendEmailCodeView.as_view(),name='sendemail_code'),  # 發送郵箱驗證碼
]

  發送郵件的ajax代碼在dec-user.js中,在utils/email_send.py中增加發送郵件的內容:

1     if send_type == 'update_email':
2         email_title = "知能網郵箱修改驗證碼"
3         email_body = "你的郵箱驗證碼為{0}".format(code)
4 
5         send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
6         if send_status:
7             pass

1.6 修改郵箱接口

 1 class UpdateEmailView(LoginRequiredMixin, View):
 2     """修改郵箱"""
 3     def post(self, request):
 4         # 從request中獲取email和code
 5         email = request.POST.get('email', '')
 6         code = request.POST.get('code', '')
 7 
 8         # 在數據庫中查找是否已有記錄
 9         existed_records = EmailVerifyRecord.objects.filter(email=email, code=code, send_type='update_email')
10         if existed_records:
11             # 修改郵箱
12             user = request.user
13             user.email = email
14             user.save()
15 
16             return HttpResponse('{"status": "success"}', content_type='application/json')
17         else:
18             return HttpResponse('{"email": "驗證碼無效"}', content_type='application/json')

  配置url:

1 from .views import UpdateEmailView
2 
3 urlpatterns = [
4     path("update_email/", UpdateEmailView.as_view(), name='update_email'),  # 修改郵箱
5 ]

  修改郵箱的ajax代碼在dec-user.js中,然后在usercenter-base.html中顯示修改郵箱代碼加上{% csrf_token %}:

 2、我的課程頁面

2.1 前端頁面配置

  將前端頁面usercenter-mycourse.html拷貝到templates下。

  然后繼承usercenter-base.html頁面,重寫需要block的地方:

2.2 我的課程接口

1 class MyCourseView(LoginRequiredMixin, View):
2     """我的課程頁面"""
3     def get(self, request):
4         # 獲取用戶的課程
5         user_courses = UserCourse.objects.filter(user=request.user)
6 
7         return render(request, 'usercenter-mycourse.html', {
8             'user_courses': user_courses
9         })

  配置url:

1 urlpatterns = [
2     path('mycourse/', MyCourseView.as_view(), name='mycourse'),  # 我的課程
3 ]

  然后修改usercenter.html頁面中跳轉到我的課程頁面的url:

  修改我的課程頁面中顯示我的課程的代碼:

3、我的收藏頁面

3.1 課程機構頁面

  前端頁面配置,先將usercenter-fav-org.html頁面拷貝到templates下,繼承usercenter-base.html頁面,重寫需要block的地方:

  我的收藏-機構接口編寫:

 1 class MyFavOrgView(LoginRequiredMixin, View):
 2     """我的收藏 - 機構"""
 3     def get(self, request):
 4         # 存放用戶收藏的機構對象
 5         org_list = []
 6 
 7         # 從UserFavorite中獲取用戶收藏機構的id
 8         fav_orgs = UserFavorite.objects.filter(user=request.user, fav_type=2)
 9 
10         # 根據id將機構對象放到org_list中
11         for fav_org in fav_orgs:
12             org_id = fav_org.fav_id
13             org = CourseOrg.objects.get(id=org_id)
14             org_list.append(org)
15 
16         return render(request, 'usercenter-fav-org.html', {
17             'org_list': org_list
18         })

  配置url:

1 urlpatterns = [
2     path('myfav/org/', MyFavOrgView.as_view(), name="myfav_org"),  # 我的收藏 - 機構
3 ]

  修改usercenter-base.html頁面中跳轉到我的收藏的url:

 

   修改我的收藏頁面顯示收藏機構的代碼:

3.2 授課教師頁面

  前端頁面配置,先將usercenter-fav-teacher.html頁面拷貝到templates下,繼承usercenter-base.html頁面,重寫需要block的地方:

  我的收藏 - 教師接口編寫:

 1 class MyFavTeacherView(LoginRequiredMixin, View):
 2     """我的收藏 - 教師"""
 3     def get(self, request):
 4         teacher_list = []
 5         fav_teachers = UserFavorite.objects.filter(user=request.user, fav_type=3)
 6         for fav_teacher in fav_teachers:
 7             teacher_id = fav_teacher.fav_id
 8             teacher = Teacher.objects.get(id=teacher_id)
 9             teacher_list.append(teacher)
10 
11         return render(request, 'usercenter-fav-teacher.html', {
12             'teacher_list': teacher_list
13         })

  配置url:

1 urlpatterns = [
2     path('myfav/teacher/', MyFavTeacherView.as_view(), name="myfav_teacher"),  # 我的收藏 - 教師
3 ]

  該頁面需要顯示教師課程的數量,需要在teacher的model中添加獲取課程數量的函數:

 1 class Teacher(models.Model):
 2     """機構老師"""
 3     org = models.ForeignKey(CourseOrg, verbose_name='所屬機構', on_delete=models.CASCADE)
 4     name = models.CharField('老師名', max_length=50)
 5     age = models.IntegerField('年齡', default=25)
 6     work_years =models.IntegerField('工作年限', default=0)
 7     work_company = models.CharField('就職公司', max_length=50)
 8     work_position = models.CharField('工作職位', max_length=50)
 9     points = models.CharField('教學特點', max_length=50)
10     click_nums = models.IntegerField('點擊數', default=0)
11     fav_nums = models.IntegerField('收藏數', default=0)
12     image = models.ImageField('頭像', upload_to='teacher/%Y/%m', max_length=100, default='')
13     add_time = models.DateTimeField('添加時間', default=datetime.now)
14 
15     class Meta:
16         verbose_name = '教師'
17         verbose_name_plural = verbose_name
18 
19     # 獲取教師課程的數量
20     def get_course_nums(self):
21         return self.course_set.all().count()
22 
23     def __str__(self):
24         return '[{}]機構的教師:{}'.format(self.org.name, self.name)

  在課程機構頁面修改跳轉到授課教師的url:

  修改授課教師頁面中顯示授課教師的代碼:

3.3 公開課程頁面

  前端頁面配置,先將usercenter-fav-course.html頁面拷貝到templates下,繼承usercenter-base.html頁面,重寫需要block的地方:

  我的收藏 - 課程接口編寫:

 1 class MyFavCourseView(LoginRequiredMixin, View):
 2     """我的收藏 - 課程"""
 3     def get(self, request):
 4         course_list = []
 5         fav_courses = UserFavorite.objects.filter(user=request.user, fav_type=1)
 6         for fav_course in fav_courses:
 7             course_id = fav_course.fav_id
 8             course = Course.objects.get(id=course_id)
 9             course_list.append(course)
10 
11         return render(request, 'usercenter-fav-course.html', {
12             'course_list': course_list
13         })

  配置url:

1 urlpatterns = [
2     path('myfav/course/', MyFavCourseView.as_view(), name="myfav_course"),  # 我的收藏 - 課程
3 ]

  修改公開課程頁面顯示收藏課程的代碼:

  最后不要忘記修改各個頁面之間跳轉的url。

4、我的消息頁面

4.1 前端頁面配置

  將前端頁面usercenter-message.html頁面拷貝到templates下,繼承usercenter-base.html頁面,重寫需要block的地方:

4.2 我的消息接口

 1 class MyMessageView(LoginRequiredMixin, View):
 2     """我的消息頁面"""
 3     def get(self, request):
 4         # 獲取用戶的消息
 5         all_message = UserMessage.objects.filter(user=request.user.id)
 6 
 7         # 分頁
 8         try:
 9             page = request.GET.get('page', 1)
10         except PageNotAnInteger:
11             page = 1
12         p = Paginator(all_message, 5, request=request)
13         messages = p.page(page)
14 
15         return render(request, 'usercenter-message.html', {
16             'messages': messages
17         })

  配置url:

1 urlpatterns = [
2     path('my_message/', MyMessageView.as_view(), name="my_message"),  # 我的消息
3 ]

  在usercenter-base.html頁面中修改跳轉到我的消息頁面的url:

  修改我的消息頁面顯示消息的代碼:

  分頁顯示:

5、登出功能

  在views.py中編寫登出的接口:

1 class LogoutView(View):
2     """登出功能"""
3     def get(self, request):
4         # 使用django的logout函數登出
5         logout(request)
6 
7         # 將頁面重定向到index
8         return HttpResponseRedirect(reverse('index'))

  在MxOnline/urls.py中配置url:

1 urlpatterns = [
2     path('logout/', LogoutView.as_view(), name='logout'),  # 登出
3 ]

  然后在三個base頁面修改登出的url。

6、點擊數、收藏數

  在用戶點擊開始學習之后,學習人數需要加1,在課程章節接口CourseLessonView中完善加1操作:

 1 class CourseLessonView(LoginRequiredMixin, View):
 2     """課程章節"""
 3     def get(self, request, course_id):
 4         # 根據前端傳遞的課程id找到對應的課程
 5         course = Course.objects.get(id=int(course_id))
 6 
 7         # 學習人數+1
 8         course.students += 1
 9         course.save()
10 
11         # 課程和用戶關聯,先判斷用戶是否已經學習過該課程
12         user_courses = UserCourse.objects.filter(user=request.user, course=course)
13         if not user_courses:
14             # 沒有學習過該課程,關聯
15             user_course = UserCourse(user=request.user, course=course)
16             user_course.save()
17 
18         # 獲取所有的資源文件
19         all_resources = CourseResourse.objects.filter(course=course)
20 
21         # 相關課程推薦
22         # 找到學習這門課程的所有用戶
23         user_courses = UserCourse.objects.filter(course=course)
24         # 找到學習這門課的所有用戶的id
25         user_ids = [user_course.user_id for user_course in user_courses]
26         # 通過所有用戶的id,找到所有用戶學習過的所有課程
27         all_user_courses = UserCourse.objects.filter(user_id__in=user_ids)
28         # 取出所有課程id
29         course_ids = [all_user_course.course_id for all_user_course in all_user_courses]
30         # 通過所有課程id找到所有的課程,按點擊量區5個
31         relate_courses = Course.objects.filter(id__in=course_ids).order_by('-click_nums')[:5]
32 
33         return render(request, 'course-video.html', {
34             'course': course,
35             'all_resources': all_resources,
36             'relate_courses': relate_courses
37         })

  在點擊教師進入教師詳情頁面,教師的點擊數加1,在教師詳情接口TeacherDetailView中完善加1邏輯:

 1 class TeacherDetailView(View):
 2     """講師詳情頁面"""
 3     def get(self, request, teacher_id):
 4         # 根據前端的講師id找到對應的講師
 5         teacher = Teacher.objects.get(id=int(teacher_id))
 6 
 7         # 老師點擊數加1
 8         teacher.click_nums += 1
 9         teacher.save()
10 
11         # 獲取該老師所有的課程
12         all_courses = Course.objects.filter(teacher=teacher)
13 
14         # 講師排行
15         teacher_sorted = Teacher.objects.all().order_by('-click_nums')[:3]
16 
17         # 講師收藏、機構收藏
18         has_teahcer_faved = False
19         if UserFavorite.objects.filter(user=request.user, fav_type=3, fav_id=teacher_id):
20             has_teahcer_faved = True
21         has_org_faved = False
22         if UserFavorite.objects.filter(user=request.user, fav_type=2, fav_id=teacher.org.id):
23             has_org_faved = True
24 
25         return render(request, 'teacher-detail.html', {
26             'teacher': teacher,
27             'all_courses': all_courses,
28             'teacher_sorted': teacher_sorted,
29             'has_teahcer_faved': has_teahcer_faved,
30             'has_org_faved': has_org_faved
31         })

  在點擊機構進入機構詳情頁,機構的點擊數加1,在機構詳情接口OrgHomeView中完善點擊數加1邏輯:

 1 class OrgHomeView(View):
 2     """機構首頁頁面"""
 3     def get(self, request, org_id):
 4         # 根據前端的id找機構
 5         org = CourseOrg.objects.get(id=int(org_id))
 6 
 7         # 點擊數加1
 8         org.click_nums += 1
 9         org.save()
10 
11         # 反向查詢機構所有的課程和教師
12         all_courses = org.course_set.all()
13         all_teachers =org.teacher_set.all()
14 
15         # 標記
16         current_page = 'home'
17 
18         # 判斷收藏狀態
19         has_fav = False
20         if request.user.is_authenticated:
21             if UserFavorite.objects.filter(user=request.user, fav_id=org.id, fav_type=2):
22                 has_fav = True
23 
24         return render(request, 'org-detail-homepage.html', {
25             'org': org,
26             'all_courses': all_courses,
27             'all_teachers': all_teachers,
28             'current_page': current_page,
29             'has_fav': has_fav
30         })

  用戶在進行收藏和取消收藏時都需要對收藏數進行加和減的操作,在機構收藏接口OrgFavView中完善收藏數的邏輯:

 1 class OrgFavView(View):
 2     """機構收藏"""
 3     def post(self, request):
 4         # 從request中獲取收藏的機構id和類型
 5         id = request.POST.get('fav_id', 0)
 6         type = request.POST.get('fav_type', 0)
 7 
 8         # 未登錄返回json數據到前端,由前端進行登錄頁面的跳轉
 9         if not request.user.is_authenticated:
10             return HttpResponse('{"status": "fail", "msg": "用戶未登錄"}', content_type='application/json')
11 
12         # 在數據庫中查找是否有過收藏記錄:
13         exist_record = UserFavorite.objects.filter(user=request.user, fav_id=int(id), fav_type=int(type))
14         if exist_record:
15             # 記錄存在,取消收藏
16             exist_record.delete()
17 
18             # 收藏數減1
19             if int(type) == 1:
20                 course = Course.objects.get(id=int(id))
21                 course.fav_nums -= 1
22                 if course.fav_nums < 0:
23                     course.fav_nums = 0
24                 course.save()
25             elif int(type) == 2:
26                 org = CourseOrg.objects.get(id=int(id))
27                 org.fav_nums -= 1
28                 if org.fav_nums < 0:
29                     org.fav_nums = 0
30                 org.save()
31             elif int(type) == 3:
32                 teacher = Teacher.objects.get(id=int(id))
33                 teacher.fav_nums -= 1
34                 if teacher.fav_nums < 0:
35                     teacher.fav_nums = 0
36                 teacher.save()
37             return HttpResponse('{"status": "success", "msg": "收藏"}', content_type='application/json')
38         else:
39             # 記錄不存在,收藏
40             user_fav = UserFavorite()
41             if int(id)>0 and int(type)>0:
42                 user_fav.user = request.user
43                 user_fav.fav_id = int(id)
44                 user_fav.fav_type = int(type)
45                 user_fav.save()
46 
47                 # 收藏數
48                 if int(type) == 1:
49                     course = Course.objects.get(id=int(id))
50                     course.fav_nums += 1
51                     course.save()
52                 elif int(type) == 2:
53                     org = CourseOrg.objects.get(id=int(id))
54                     org.fav_nums += 1
55                     org.save()
56                 elif int(type) == 3:
57                     teacher = Teacher.objects.get(id=int(id))
58                     teacher.fav_nums += 1
59                     teacher.save()
60                 return HttpResponse('{"status": "success", "msg": "已收藏"}', content_type='application/json')
61             else:
62                 return HttpResponse('{"status": "fail", "msg": "收藏出錯"}', content_type='application/json')

7、個人中心頁面左側選中狀態

  現在在usercenter-base.html頁面中修改左側導航欄選中狀態的代碼:

  還有一個問題,就是我的收藏中刪除機構收藏,需要修改usercenter-base.html頁面中最下面的代碼:

  下面的教師和課程也是同樣的改法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM