专题:Django2.0.8+xadmin2实现在线学习网站
Django2.0.8+xadmin2实现在线学习网站,课程、讲师、机构、用户收藏功能。GitHub地址:https://github.com/xyliurui/OnlineLearningPlatform ;Django版本:2.0.8
更多内容请点击 我的博客 查看,欢迎来访。
授课机构功能实现
定义父模板base.html
用户其他模板扩展
机构列表基础
机构列表展示模板org-list.html
该模板继承base.html,使用{% extends 'base.html' %}
机构列表视图OrgListView(View)
organization/views.py
from django.shortcuts import render
from django.views.generic.base import View
class OrgListView(View):
def get(self, request):
return render(request, 'org-list.html')
机构列表url
修改主url,配置课程机构首页url
from organization.views import OrgListView
urlpatterns = [
path('admin/', admin.site.urls),
path('xadmin/', xadmin.site.urls),
path('', TemplateView.as_view(template_name='index.html'), name='index'),
# path('login/', TemplateView.as_view(template_name='login.html'), name='login'),
# path('login/', user_login, name='login'),
path('login/', LoginView.as_view(), name='login'), # 基于类方法实现登录,这里是调用它的方法
path('register/', RegisterView.as_view(), name='register'),
re_path('register/active/(?P<active_code>.*)/', ActiveUserView.as_view(), name='user_active'), # 激活
path('captcha/', include('captcha.urls')),
path('forgetpwd/', ForgetPwdView.as_view(), name='forgetpwd'), # 忘记密码
re_path('forgetpwd/reset/(?P<active_code>.*)/', RestpwdView.as_view(), name='resetpwd'), # 密码重置验证
path('modify_pwd/', ModifypwdView.as_view(), name="modify_pwd"), # 密码修改
path('org/list/', OrgListView.as_view(), name="org_list"), # 机构列表
]
这样,访问 http://127.0.0.1:8000/org/list/ 即可查看机构列表
机构列表数据展示
确定由后台传过来的动态数据:授课机构列表本身, 授课机构的排名,所在地区(后台取出所有地区), 机构类别写成静态,因为一般不怎么变动。
在xadmin中添加城市信息,课程信息。
机构models中添加机构类别
organization/models.py
# 课程机构信息
class CourseOrg(models.Model):
ORG_CHOICES = (
("pxjg", "培训机构"),
("gx", "高校"),
("gr", "个人"),
)
name = models.CharField(max_length=50, verbose_name='机构名称')
desc = models.TextField(verbose_name='机构描述')
category = models.CharField(choices=ORG_CHOICES, max_length=10, default='pxjg', verbose_name='机构类别')
click_nums = models.IntegerField(default=0, verbose_name='点击数')
fav_nums = models.IntegerField(default=0, verbose_name='收藏数')
image = models.ImageField(upload_to='org/%Y/%m', max_length=100, verbose_name='封面图')
address = models.CharField(max_length=150, verbose_name='机构地址')
city = models.ForeignKey(CityDict, on_delete=models.CASCADE, verbose_name='所在城市')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '课程机构'
def __str__(self):
return self.name
然后需要进行数据同步
manage.py@DjangoOnlineLearningPlatform > makemigrations
manage.py@DjangoOnlineLearningPlatform > migrate
完善机构列表视图
将列表里的静态数据变成后台获取的动态数据
organization/views.py
from .models import CourseOrg, CityDict
class OrgListView(View):
def get(self, request):
# 查找所有的机构
all_org = CourseOrg.objects.all()
# 取出所有城市
all_city = CityDict.objects.all()
# 机构类别
all_category = list(map(lambda x: {'code': x[0], 'explain': x[1]}, CourseOrg.ORG_CHOICES))
return render(request, 'org-list.html', locals())
模板中进行数据填充org-list.html
<div class="short-lst">
<ul>
<li><b>机构类别</b></li>
<li><a href="?category=&city="> 全部 </a></li>
{% for category in all_category %}
<li><a href="?category={{ category.code }}&city="> {{ category.explain }} </a></li>
{% endfor %}
</ul>
</div>
<div class="short-lst">
<ul>
<li><b>所在地区</b></li>
<li><a href="?category=&city="> 全部 </a></li>
{% for city in all_city %}
<li><a href="?category=&city={{ city.id }}"> {{ city.name }} </a></li>
{% endfor %}
</ul>
</div>
<div class="short-lst">
<h2>授课机构<small>(共{{ all_org.count }}家)</small></h2>
<ul>
<!-- Short List -->
<li>
<p>全部</p>
</li>
<li>
<p>学习人数↓</p>
</li>
<li>
<p>课程数↓</p>
</li>
</ul>
</div>
{% for org in all_org %}
<div class="product">
<article>
<!-- Product img -->
<div class="media-left">
<div class="item-img"><img class="img-responsive" src="{{ org.image.url }}" alt=""></div>
</div>
<!-- Content -->
<div class="media-body">
<div class="row">
<!-- Content Left -->
<div class="col-sm-7"><span class="tag"></span>
<h4><a href="#.">{{ org.name }}</a></h4>
<!-- Reviews -->
<ul class="bullet-round-list">
<li>课程数:xx</li>
<li>学习人数:xx</li>
<li>地址:</li>
<li>经典课程</li>
</ul>
</div>
<!-- Content Right -->
<div class="col-sm-5 text-center">
<div class="position-center-center">
<a href="#." class="btn-round">联系</a>
</div>
</div>
</div>
</div>
</article>
</div>
{% endfor %}
BLOG_20190604_135852_84
列表分页功能
首先需要安装相应的库
pip install django-pure-pagination
分页设置
修改settings.py添加分页app:pure_pagination
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'courses',
'organization',
'operation',
'xadmin',
'crispy_forms',
'reversion',
'captcha',
'pure_pagination',
]
PAGINATION_SETTINGS = {
'PAGE_RANGE_DISPLAYED': 10,
'MARGIN_PAGES_DISPLAYED': 2,
'SHOW_FIRST_PAGE_WHEN_INVALID': True,
}
-
PAGE_RANGE_DISPLAYED
是总共会显示多少个page。(包括省略号,包括两边和中间) -
MARGIN_PAGES_DISPLAYED
是旁边会显示多少个。 -
SHOW_FIRST_PAGE_WHEN_INVALID
当输入页数不合法是否要跳到第一页
视图中分页实现
参照官方的文档
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
from .models import CourseOrg, CityDict
class OrgListView(View):
def get(self, request):
# 查找所有的机构
all_org = CourseOrg.objects.all()
# 取出所有城市
all_city = CityDict.objects.all()
# 机构类别
all_category = list(map(lambda x: {'code': x[0], 'explain': x[1]}, CourseOrg.ORG_CHOICES))
# 机构数量
org_nums = all_org.count()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 从列表中取5个出来,也就是每页显示5个
p = Paginator(all_org, 5, request=request)
all_org = p.page(page)
return render(request, 'org-list.html', locals())
html配置分页
<h2>授课机构<small>(共{{ org_nums }}家,本页显示{{ all_org.object_list.count }}家)</small></h2>
{% for org in all_org.object_list %}
# ....
{% endofr %}
<!-- pagination -->
<ul class="pagination">
{% if all_org.has_previous %}
<li><a href="?{{ all_org.previous_page_number.querystring }}" aria-label="Previous"> <i class="fa fa-angle-left"></i> </a></li>
{% endif %}
{% for page in all_org.pages %}
{% if page %}
{% ifequal page all_org.number %}
<li><a class="active" href="?{{ page.querystring }}">{{ page }}</a></li>
{% else %}
<li><a href="?{{ page.querystring }}">{{ page }}</a></li>
{% endifequal %}
{% else %}
<li><a href="">...</a></li>
{% endif %}
{% endfor %}
{% if all_org.has_next %}
<li><a href="?{{ all_org.next_page_number.querystring }}" aria-label="Next"> <i class="fa fa-angle-right"></i> </a></li>
{% endif %}
</ul>
机构列表不再是objects,而是all_org.object_list
分类筛选功能
直接在url中添加参数,例如当用户点击某一个city时对应加上参数city的id
<li><a href="?category=&city={{ city.id }}"> {{ city.name }} </a></li>
后台处理类别筛选
class OrgListView(View):
def get(self, request):
# 查找所有的机构
all_org = CourseOrg.objects.all()
# 取出所有城市
all_city = CityDict.objects.all()
# 机构类别
all_category = list(map(lambda x: {'code': x[0], 'explain': x[1]}, CourseOrg.ORG_CHOICES))
# 处理类别筛选
category_code = request.GET.get('category', '')
if category_code:
all_org = all_org.filter(category=category_code)
# 机构数量
org_nums = all_org.count()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 从列表中取5个出来,也就是每页显示5个
p = Paginator(all_org, 5, request=request)
all_org = p.page(page)
return render(request, 'org-list.html', locals())
后台处理城市筛选
class OrgListView(View):
def get(self, request):
# 查找所有的机构
all_org = CourseOrg.objects.all()
# 取出所有城市
all_city = CityDict.objects.all()
# 机构类别
all_category = list(map(lambda x: {'code': x[0], 'explain': x[1]}, CourseOrg.ORG_CHOICES))
# 处理类别筛选,取回的是字符串
category_code = request.GET.get('category', '')
if category_code:
all_org = all_org.filter(category=category_code)
# 处理城市筛选,取回的是city的ID
city_id = request.GET.get('city', '')
if city_id:
all_org = all_org.filter(city=city_id)
# 机构数量
org_nums = all_org.count()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 从列表中取5个出来,也就是每页显示5个
p = Paginator(all_org, 5, request=request)
all_org = p.page(page)
return render(request, 'org-list.html', locals())
模板中处理两种筛选
已经选中的进行标记
<div class="short-lst">
<ul>
<li><b>机构类别</b></li>
<li><a href="?category=&city={{ city_id }}" {% ifequal category_code '' %} style="color: #BEBEBE" {% endifequal %}> 全部 </a></li>
{% for category in all_category %}
<li><a href="?category={{ category.code }}&city={{ city_id }}" {% ifequal category_code category.code %} style="color: #BEBEBE" {% endifequal %}> {{ category.explain }} </a></li>
{% endfor %}
</ul>
</div>
<div class="short-lst">
<ul>
<li><b>所在地区</b></li>
<li><a href="?category={{ category_code }}&city=" {% ifequal city_id '' %} style="color: #BEBEBE" {% endifequal %}> 全部 </a></li>
{% for city in all_city %}
<li><a href="?category={{ category_code }}&city={{ city.id }}" {% ifequal city_id city.id|stringformat:'i' %} style="color: #BEBEBE" {% endifequal %}> {{ city.name }} </a></li>
{% endfor %}
</ul>
</div>
BLOG_20190604_135827_76
由于我们使用的是分页库,这里变动page的时候url中其他参数不会变化
例如 访问 http://127.0.0.1:8000/org/list/?category=pxjg&city= 如果这时候点第2也, 则url会跳转到 http://127.0.0.1:8000/org/list/?category=pxjg&city=&page=2
进行城市与分类的联动:
- 当选择全部类别的时候,就只通过当前城市id。
- 当选择全部城市的时候,就只通过当前类别id。
- 当两者都选的时候使用
&
连接。
课程机构排序
学习人数,课程数
organization/models.py
模型中添加排序字段
CourseOrg模型中添加两个字段students
和course_nums
# 课程机构信息
class CourseOrg(models.Model):
ORG_CHOICES = (
("pxjg", "培训机构"),
("gx", "高校"),
("gr", "个人"),
)
name = models.CharField(max_length=50, verbose_name='机构名称')
desc = models.TextField(verbose_name='机构描述')
category = models.CharField(choices=ORG_CHOICES, max_length=10, default='pxjg', verbose_name='机构类别')
click_nums = models.IntegerField(default=0, verbose_name='点击数')
fav_nums = models.IntegerField(default=0, verbose_name='收藏数')
students = models.IntegerField(default=0, verbose_name='学习人数')
course_nums = models.IntegerField(default=0, verbose_name='课程数数')
image = models.ImageField(upload_to='org/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图')
address = models.CharField(max_length=150, verbose_name='机构地址')
city = models.ForeignKey(CityDict, on_delete=models.CASCADE, verbose_name='所在城市')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '课程机构'
def __str__(self):
return self.name
然后执同步
manage.py@DjangoOnlineLearningPlatform > makemigrations organization
manage.py@DjangoOnlineLearningPlatform > migrate organization
视图中增加排序OrgListView(View)
class OrgListView(View):
def get(self, request):
# 查找所有的机构
all_org = CourseOrg.objects.all()
# 取出所有城市
all_city = CityDict.objects.all()
# 机构类别
all_category = list(map(lambda x: {'code': x[0], 'explain': x[1]}, CourseOrg.ORG_CHOICES))
# 热门机构,选择点击数最多的3个机构显示到右边
hot_org = all_org.order_by('-click_nums')[:3]
# 处理类别筛选,取回的是字符串
category_code = request.GET.get('category', '')
if category_code:
all_org = all_org.filter(category=category_code)
# 处理城市筛选,取回的是city的ID
city_id = request.GET.get('city', '')
if city_id:
all_org = all_org.filter(city=city_id)
# 排序,按照学习人数或者课程数排序
sort = request.GET.get('sort', '')
if sort:
if sort == 'students':
all_org = all_org.order_by('-students')
elif sort == 'courses':
all_org = all_org.order_by('-course_nums')
# 机构数量
org_nums = all_org.count()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 从列表中取5个出来,也就是每页显示5个
p = Paginator(all_org, 5, request=request)
all_org = p.page(page)
return render(request, 'org-list.html', locals())
模板中排序url修改
<div class="short-lst">
<h2>授课机构<small>(共{{ org_nums }}家,本页显示{{ all_org.object_list.count }}家)</small></h2>
<ul>
<!-- Short List -->
<li>
<p><a href="?category={{ category_code }}&city={{ city_id }}" {% ifequal sort '' %} style="font-weight: bold" {% endifequal %}> 全部 </a></p>
</li>
<li>
<p><a href="?sort=students&category={{ category_code }}&city={{ city_id }}" {% ifequal sort 'students' %} style="color: #BEBEBE" {% endifequal %}> 学习人数 ↓</a></p>
</li>
<li>
<p><a href="?sort=courses&category={{ category_code }}&city={{ city_id }}" {% ifequal sort 'courses' %} style="color: #BEBEBE" {% endifequal %}>课程数 ↓</a></p>
</li>
</ul>
</div>
网友评论