(项目)在线教育平台(六)
八、授课机构功能
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代码: