慕课网《强力django+杀手级xadmin 打造上线标准的在线教育平台》 学习笔记
本章主要内容:
- 完成课程机构的相关功能
- 本章会开始django的templates模板继承机制实现模板的重用。
- 本章包括分页、筛选、收藏等功能, 会讲到如何通过modelform对表单进行验证和保存。
- 分析页面
Django模板操作
- 包含与继承
后台添加一些数据
- 图片路径的配置
列表展示
- 取出所有的机构
class OrgView(View):
"""
课程机构列表功能
"""
def get(self, request):
#课程机构
all_orgs = CourseOrg.objects.all()
return render(request, "org-list.html", {
"all_orgs":orgs
})
列表展示
<div class="cont">
<a href="?ct={{ category }}"><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>
{% for city in all_citys %}
<a href="?city={{ city.id }}&ct={{ category }}"><span class="{% ifequal city_id city.id|stringformat:"i" %}active2{% endifequal %}">{{ city.name }}</span></a>
{% endfor %}
</div>
分页
django-pure-pagination provides advanced pagination features and is fully compatible with existing code based on Django’s core pagination module. (aka no need to rewrite code!)
安装及配置略
后台分页
#课程机构
all_orgs = CourseOrg.objects.all()
# 对课程机构进行分页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(all_orgs, 5, request=request) # 每页5个
orgs = p.page(page)
- 前台分页显示
<div class="pageturn">
<ul class="pagelist">
{% if all_orgs.has_previous %}
<li class="long"><a href="?{{ all_orgs.previous_page_number.querystring }}">上一页</a></li>
{% endif %}
{% for page in all_orgs.pages %}
{% if page %}
{% ifequal page all_orgs.number %}
<li class="active"><a href="?{{ page.querystring }}">{{ page }}</a></li>
{% else %}
<li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
{% endifequal %}
{% else %}
<li class="none"><a href="">...</a></li>
{% endif %}
{% endfor %}
{% if all_orgs.has_next %}
<li class="long"><a href="?{{ all_orgs.next_page_number.querystring }}">下一页</a></li>
{% endif %}
</ul>
</div>
筛选
- 分别传机构类别、所在地区、排序sort的参数,参数存在则过滤或排序,最后把参数传回页面
class OrgView(View):
"""
课程机构列表功能
"""
def get(self, request):
#课程机构
all_orgs = CourseOrg.objects.all()
# 机构排名,按点击数排序,取前3
hot_orgs = all_orgs.order_by("-click_nums")[:3]
#城市
all_citys = CityDict.objects.all()
#机构搜索
search_keywords = request.GET.get('keywords', "")
if search_keywords:
all_orgs = all_orgs.filter(Q(name__icontains=search_keywords)|Q(desc__icontains=search_keywords))
#取出筛选城市
city_id = request.GET.get('city', "")
if city_id:
all_orgs = all_orgs.filter(city_id=int(city_id))
#类别筛选
category = request.GET.get('ct', "")
if category:
all_orgs = all_orgs.filter(category=category)\
sort = request.GET.get('sort', "")
if sort:
if sort == "students":
all_orgs = all_orgs.order_by("-students")
elif sort == "courses":
all_orgs = all_orgs.order_by("-course_nums")
# 最后才计数
org_nums = all_orgs.count()
#对课程机构进行分页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(all_orgs, 5, request=request)
orgs = p.page(page)
return render(request, "org-list.html", {
"all_orgs":orgs,
"all_citys":all_citys,
"org_nums": org_nums,
"city_id": city_id,
"category": category,
"hot_orgs": hot_orgs,
"sort": sort
})
前台页面
- 筛选机构类别
注意:同时要把城市的参数 &city={{ city_id }} 带上去
<li>
<h2>机构类别</h2>
<div class="cont">
<a href="?city={{ city_id }}"><span class="{% ifequal category '' %}active2{% endifequal %}">全部</span></a>
<a href="?ct=pxjg&city={{ city_id }}"><span class="{% ifequal category 'pxjg' %}active2{% endifequal %}">培训机构</span></a>
<a href="?ct=gx&city={{ city_id }}"><span class="{% ifequal category 'gx' %}active2{% endifequal %}">高校</span></a>
<a href="?ct=gr&city={{ city_id }}"><span class="{% ifequal category 'gr' %}active2{% endifequal %}">个人</span></a>
</div>
</li>
- 筛选所在地区
注意:此处也要把机构类别 &ct={{ category }} 带上去
<li>
<h2>所在地区</h2>
<div class="more">更多</div>
<div class="cont">
<a href="?ct={{ category }}"><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>
{% for city in all_citys %}
<a href="?city={{ city.id }}&ct={{ category }}"><span class="{% ifequal city_id city.id|stringformat:"i" %}active2{% endifequal %}">{{ city.name }}</span></a>
{% endfor %}
</div>
</li>
- 结果数量
<div class="all">共<span class="key">{{ org_nums }}</span>家</div>
- 排序
此处要同时把上面两个参数 ?ct={{ category }}&city={{ city_id }} 带上去
<div class="head">
<ul class="tab_header">
<li class="{% if sort == '' %}active{% endif %}"><a href="?ct={{ category }}&city={{ city_id }}">全部</a> </li>
<li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students&ct={{ category }}&city={{ city_id }}">学习人数 ↓</a></li>
<li class="{% if sort == 'courses' %}active{% endif %}"><a href="?sort=courses&ct={{ category }}&city={{ city_id }}">课程数 ↓</a></li>
</ul>
</div>
- 机构排名
<div class="right companyrank layout">
<div class="head">授课机构排名</div>
{% for curent_org in hot_orgs %}
<dl class="des">
<dt class="num fl">{{ forloop.counter }}</dt>
<dd>
<a href="/company/2/"><h1>{{ curent_org.name }}</h1></a>
<p>{{ curent_org.address }}</p>
</dd>
</dl>
{% endfor %}
</div>
使用ModelForm提交‘我要学习’表单
- 当表单和model很相似的时候可以用ModelForm从指定的Model生成
- 可以指定只要model的哪些字段
- 可以扩展新的字段
- 可以直接保存model
验证
- 可以在表单中定义一些验证字段的函数,以clean_*开头,表示检查哪一个字段的合法性,modelform在检查合法性时会自动调用该方法
- 在该方法中通过 self.cleaned_data 可以获取表单中的数据
class UserAskForm(forms.ModelForm):
# 新扩展的字段
# newArgs = forms.CharField(required=True, min_length=5)
class Meta:
model = UserAsk # 指定从那个model生成
# 指定只要Model中的哪些字段
fields = ['name', 'mobile', 'course_name']
def clean_mobile(self):
"""
验证手机号码是否合法
"""
mobile = self.cleaned_data['mobile']
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"
p = re.compile(REGEX_MOBILE)
if p.match(mobile):
return mobile
else:
raise forms.ValidationError(u"手机号码非法", code="mobile_invalid")
分发 url
- 防止项目的urls.py臃肿
- 命名空间可减少重名
- 使用
<a href="{% url 'org:org_home' course_org.id %}">
提交表单
- ModelForm可以直接保存save(),不需要转换成model
- HttpResponse 返回 json
注意:此处是ajax提交
class AddUserAskView(View):
"""
用户添加咨询
"""
def post(self, request):
userask_form = UserAskForm(request.POST)
if userask_form.is_valid():
user_ask = userask_form.save(commit=True) # 关键是这里
return HttpResponse('{"status":"success"}', content_type='application/json')
else:
return HttpResponse('{"status":"fail", "msg":"添加出错"}', content_type='application/json')