八、授課機構功能
1、模板繼承
如果幾個頁面的大體結構相同,可以使用繼承的方式來實現母版的重用性,也就是子版繼承母版的內容,既可以使用模板的內容,也可以重寫需要改變的地地方。
首先完成授課機構的頁面,通過頁面顯示發現,
先把org-list.html頁面拷貝到templates下,在該目錄下新建base.html頁面,然后將org-list.html內容剪切到base.html下,然后修改靜態文件的路徑,在base.html頁面下找到需要block的地方,以供子版繼承重寫:
org-list.html繼承base.html,自定義org-list.html頁面中的內容:
base.html頁面還需要修改的地方是頂部登錄注冊的顯示問題,這個問題和index.html頁面的一樣,只需要將index頁面的拷貝過來即可。
2、后端機構列表接口
2.1 機構列表接口
在organization/views.oy文件下編寫機構列表的接口:
1 class OrgView(View): 2 """機構列表""" 3 def get(self, request): 4 return render(request, 'org-list.html')
配置url:
1 from organization.views import OrgView 2 3 urlpatterns = [ 4 path('org_list/', OrgView.as_view(), name='org_list') # 機構列表 5 ]
然后修改index.html導航欄跳轉到機構列表的url:
現在訪問機構列表頁就可以看到頁面了。
2.2 后臺添加數據
后臺添加城市的相關數據:
后臺添加機構的相關數據,不過需要先在organization/models.py機構中添加一個字段category,用來區分機構的類別:
1 class CourseOrg(models.Model): 2 """課程機構""" 3 CATEGORY_CHOICES = ( 4 ('pxjg', '培訓機構'), 5 ('gx', '高校'), 6 ('gr', '個人') 7 ) 8 name = models.CharField('機構名稱', max_length=50) 9 category = models.CharField('機構類別', max_length=20, choices=CATEGORY_CHOICES, default='pxjg') 10 desc = models.TextField('機構描述') 11 click_nums = models.IntegerField('點擊數', default=0) 12 fav_nums = models.IntegerField('收藏數', default=0) 13 image = models.ImageField('封面圖', upload_to='org/%Y/%m', max_length=100) 14 address = models.CharField('地址', max_length=150) 15 city = models.ForeignKey(CityDict, verbose_name='所在城市', on_delete=models.CASCADE) 16 add_time = models.DateTimeField('添加時間', default=datetime.now) 17 18 class Meta: 19 verbose_name = '課程機構' 20 verbose_name_plural = verbose_name
修改之后需要遷移數據庫。
在后臺添加機構信息的時候需要上傳機構的圖片,在項目根目錄下新建一個media,用來存放上傳的圖片,然后在settings.py文件中設置上傳文件的路徑:
1 # 上傳文件的路徑 2 MEDIA_URL = '/media/' 3 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
然后現在添加機構的數據:
2.3 完善機構列表的接口
1 class OrgView(View): 2 """機構列表""" 3 def get(self, request): 4 # 取出所有的機構 5 all_orgs = CourseOrg.objects.all() 6 org_nums = all_orgs.count() 7 8 # 取出所有的城市 9 all_citys = CityDict.objects.all() 10 11 return render(request, 'org-list.html', { 12 'all_orgs': all_orgs, 13 'all_citys': all_citys, 14 'org_nums': org_nums 15 })
然后修改前端org-list.html顯示的內容:
要顯示后臺的圖片,需要在settings.py中的TEMPLATES添加圖片處理器django.template.context_processors.media,如下:
1 TEMPLATES = [ 2 { 3 'BACKEND': 'django.template.backends.django.DjangoTemplates', 4 'DIRS': [os.path.join(BASE_DIR, 'templates')] 5 , 6 'APP_DIRS': True, 7 'OPTIONS': { 8 'context_processors': [ 9 'django.template.context_processors.debug', 10 'django.template.context_processors.request', 11 'django.contrib.auth.context_processors.auth', 12 'django.contrib.messages.context_processors.messages', 13 # 圖片處理器,為了在課程列表中前面加上MEDIA_URL 14 'django.template.context_processors.media', 15 ], 16 }, 17 }, 18 ]
然后在urls中配置處理圖片的url,固定寫法:
1 from django.views.static import serve 2 from MxOnline.settings import MEDIA_ROOT 3 4 urlpatterns = [ 5 re_path(r'^media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT}), # 處理圖片顯示 6 ]
現在刷新列表頁即可看到如下效果:
3、分頁功能
機構如果超出每一頁的數量,就需要使用分頁,在這里使用第三方庫django-pure-pagination來實現分頁。
3.1 安裝
在虛擬環境中直接pip install django-pure-pagination
3.2 注冊
將pure_pagination注冊進INSTALLED_APPS中:
1 INSTALLED_APPS = [ 2 'pure_pagination', 3 ]
3.3 在機構列表接口加入分頁邏輯
1 class OrgView(View): 2 """機構列表""" 3 def get(self, request): 4 # 取出所有的機構 5 all_orgs = CourseOrg.objects.all() 6 org_nums = all_orgs.count() 7 8 # 取出所有的城市 9 all_citys = CityDict.objects.all() 10 11 # 分頁 12 try: 13 page = request.GET.get('page', 1) 14 except PageNotAnInteger: 15 page = 1 16 p = Paginator(all_orgs, 5, request=request) 17 orgs = p.page(page) 18 19 return render(request, 'org-list.html', { 20 'all_orgs': orgs, 21 'all_citys': all_citys, 22 'org_nums': org_nums 23 })
然后修改org-list.html中的all_orgs:
在org-list.html中修改前端分頁顯示的代碼:
刷新列表頁后,每頁顯示5條機構:
4、篩選功能
4.1 城市篩選
在機構列表接口中完善篩選數據的邏輯:
1 class OrgView(View): 2 """機構列表""" 3 def get(self, request): 4 # 取出所有的機構 5 all_orgs = CourseOrg.objects.all() 6 org_nums = all_orgs.count() 7 8 # 取出所有的城市 9 all_citys = CityDict.objects.all() 10 11 # 篩選(從request中獲取城市的id) 12 city_id = request.GET.get('city', '') 13 if city_id: 14 all_orgs = all_orgs.filter(city_id=int(city_id)) 15 16 # 分頁 17 try: 18 page = request.GET.get('page', 1) 19 except PageNotAnInteger: 20 page = 1 21 p = Paginator(all_orgs, 5, request=request) 22 orgs = p.page(page) 23 24 return render(request, 'org-list.html', { 25 'all_orgs': orgs, 26 'all_citys': all_citys, 27 'org_nums': org_nums, 28 'city_id': city_id 29 })
前端顯示的修改如下:
4.2 類別篩選
繼續在機構列表接口完善類別篩選功能:
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 # 城市篩選(從request中獲取城市的id) 11 city_id = request.GET.get('city', '') 12 if city_id: 13 all_orgs = all_orgs.filter(city_id=int(city_id)) 14 15 # 類別篩選(從request中獲取機構類別ct) 16 category = request.GET.get('ct', '') 17 if category: 18 all_orgs = all_orgs.filter(category=category) 19 20 # 篩選完再統計數量 21 org_nums = all_orgs.count() 22 23 # 分頁 24 try: 25 page = request.GET.get('page', 1) 26 except PageNotAnInteger: 27 page = 1 28 p = Paginator(all_orgs, 5, request=request) 29 orgs = p.page(page) 30 31 return render(request, 'org-list.html', { 32 'all_orgs': orgs, 33 'all_citys': all_citys, 34 'org_nums': org_nums, 35 'city_id': city_id, 36 'category': category 37 })
前端的顯示修改內容如下:
修改完成之后,篩選功能完成,可以根據類別和城市篩選機構:
4.3 機構排名篩選
機構的排名按照點擊量進行排名,在機構列表接口中添加排名篩選邏輯:
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 hot_orgs = all_orgs.order_by('-click_nums')[:3] 12 13 # 城市篩選(從request中獲取城市的id) 14 city_id = request.GET.get('city', '') 15 if city_id: 16 all_orgs = all_orgs.filter(city_id=int(city_id)) 17 18 # 類別篩選(從request中獲取機構類別ct) 19 category = request.GET.get('ct', '') 20 if category: 21 all_orgs = all_orgs.filter(category=category) 22 23 # 篩選完再統計數量 24 org_nums = all_orgs.count() 25 26 # 分頁 27 try: 28 page = request.GET.get('page', 1) 29 except PageNotAnInteger: 30 page = 1 31 p = Paginator(all_orgs, 5, request=request) 32 orgs = p.page(page) 33 34 return render(request, 'org-list.html', { 35 'all_orgs': orgs, 36 'all_citys': all_citys, 37 'org_nums': org_nums, 38 'city_id': city_id, 39 'category': category, 40 'hot_orgs': hot_orgs 41 })
然后修改前端顯示代碼:
4.4 學習人數和課程排名篩選
首先在organization/models.py中的CourseOrg中加入students和course_nums兩個字段:
1 class CourseOrg(models.Model): 2 """課程機構""" 3 CATEGORY_CHOICES = ( 4 ('pxjg', '培訓機構'), 5 ('gx', '高校'), 6 ('gr', '個人') 7 ) 8 name = models.CharField('機構名稱', max_length=50) 9 category = models.CharField('機構類別', max_length=20, choices=CATEGORY_CHOICES, default='pxjg') 10 desc = models.TextField('機構描述') 11 students = models.IntegerField('學習人數', default=0) 12 course_nums = models.IntegerField('課程數', default=0) 13 click_nums = models.IntegerField('點擊數', default=0) 14 fav_nums = models.IntegerField('收藏數', default=0) 15 image = models.ImageField('封面圖', upload_to='org/%Y/%m', max_length=100) 16 address = models.CharField('地址', max_length=150) 17 city = models.ForeignKey(CityDict, verbose_name='所在城市', on_delete=models.CASCADE) 18 add_time = models.DateTimeField('添加時間', default=datetime.now) 19 20 class Meta: 21 verbose_name = '課程機構' 22 verbose_name_plural = verbose_name 23 24 def __str__(self): 25 return self.name
然后遷移數據庫。
然后在機構列表接口中完善學習人數和課程數排名的邏輯:
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 hot_orgs = all_orgs.order_by('-click_nums')[:3] 12 13 # 學習人數和課程數排名篩選 14 sort = request.GET.get('sort', '') 15 if sort: 16 if sort == 'students': 17 all_orgs = all_orgs.order_by('-students') 18 elif sort == 'courses': 19 all_orgs = all_orgs.order_by('-course_nums') 20 21 # 城市篩選(從request中獲取城市的id) 22 city_id = request.GET.get('city', '') 23 if city_id: 24 all_orgs = all_orgs.filter(city_id=int(city_id)) 25 26 # 類別篩選(從request中獲取機構類別ct) 27 category = request.GET.get('ct', '') 28 if category: 29 all_orgs = all_orgs.filter(category=category) 30 31 # 篩選完再統計數量 32 org_nums = all_orgs.count() 33 34 # 分頁 35 try: 36 page = request.GET.get('page', 1) 37 except PageNotAnInteger: 38 page = 1 39 p = Paginator(all_orgs, 5, request=request) 40 orgs = p.page(page) 41 42 return render(request, 'org-list.html', { 43 'all_orgs': orgs, 44 'all_citys': all_citys, 45 'org_nums': org_nums, 46 'city_id': city_id, 47 'category': category, 48 'hot_orgs': hot_orgs, 49 'sort': sort 50 })
然后修改前端代碼:
5、我要學習咨詢功能
5.1 我要學習咨詢接口
我要學習咨詢的表單這次使用ModelForm來實現,首先在organization下新建form.py文件:
1 from django import forms 2 from operation.models import UserAsk 3 4 5 class UserAskForm(forms.ModelForm): 6 """我要學習咨詢表單驗證""" 7 class Meta: 8 model = UserAsk 9 fields = ['name','mobile','course_name']
編寫我要學習咨詢的后臺接口:
1 class UserAskView(View): 2 """我要學習咨詢""" 3 def post(self, request): 4 userask_form = UserAskForm(request.POST) 5 if userask_form.is_valid(): 6 # 通過ModelForm可以直接將表單中的內容保存 7 user_ask = userask_form.save(commit=True) 8 # 通過ajax提交,給前端返回json數據 9 return HttpResponse('{"status": "success"}', content_type='application/json') 10 else: 11 return HttpResponse('{"status": "fail", "msg": "添加出錯"}', content_type='application/json')
現在使用路由分發的方式來配置url,首先刪除urls.py中的org_list這個路由,然后添加一級路由:
1 urlpatterns = [ 2 # path('org_list/', OrgView.as_view(), name='org_list'), # 機構列表 3 path('org/', include('organization.urls', namespace='org')), # 機構列表 4 ]
然后在organization下新建urls.py文件,在這個文件配置機構列表頁的相關url,之前刪除了機構列表的url,現在將機構列表和我要學習咨詢的url都添加到這個文件下:
1 from django.urls import path, re_path 2 3 from .views import OrgView, UserAskView 4 5 app_name = 'organization' 6 7 urlpatterns = [ 8 path('list/',OrgView.as_view(),name='org_list'), # 機構列表 9 path('user_ask/', UserAskView.as_view(), name='user_ask'), # 我要學習咨詢 10 ]
之前在首頁跳轉機構列表的url需要修改過來:
然后在form中添加驗證手機號碼合法性的邏輯:
1 import re 2 3 from django import forms 4 from operation.models import UserAsk 5 6 7 class UserAskForm(forms.ModelForm): 8 """我要學習咨詢表單驗證""" 9 class Meta: 10 model = UserAsk 11 fields = ['name','mobile','course_name'] 12 13 def clean_mobile(self): 14 """驗證手機號合法性""" 15 mobile = self.cleaned_data['mobile'] 16 REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|176\d{8}$" 17 p = re.compile(REGEX_MOBILE) 18 if p.match(mobile): 19 return mobile 20 else: 21 raise forms.ValidationError('手機號非法', code='mobile_invalid')
我要學習咨詢表單是將數據ajax提交到后臺的,不刷新頁面,所以在前端要編寫script代碼:
?