Django+xadmin打造在线教育平台(四)
目录
代码
教程
学习自慕课网-使用python3.x与Django2.0.1开发的在线教育平台
七、授课机构功能
7.1.模板继承
(1)创建母板
把org-list.html拷贝到templates目录下,新建base.html,剪切org-list.html内容到里面
再修改一下静态文件的地址(css、就是、image和media)
(2)机构首页路由
from organization.views import OrgView path('org_list/',OrgView.as_view(),name = 'org_list'),
(3)机构views
class OrgView(View):
'''课程机构'''
def get(self,request):
return render(request,'org-list.html')
(4)org-list.html继承base
{#templates/org-list.html#} {% extends 'base.html' %} {% block title %}
课程机构列表
{% endblock %}
访问:http://127.0.0.1:8000/org_list/ 可以看到org_list页面
(5)修改base模板
把base中custom_bread和content两个block的内容剪切到org-list.html里面
base.html
org-list.html
7.2.添加城市和课程机构
(1)进xadmin后台添加城市
这里机构是静态固定不变的,所在地区是动态的,从数据库中获取得到的
(2)修改机构的models,添加一个机构类别字段
organization/models.py:
class CourseOrg(models.Model):
ORG_CHOICES = (
("pxjg", u"培训机构"),
("gx", u"高校"),
("gr", u"个人"),
) #添加字段
category = models.CharField(max_length=20, choices=ORG_CHOICES, verbose_name=u"机构类别", default="pxjg")
class CourseOrg(models.Model):
ORG_CHOICES = (
("pxjg", u"培训机构"),
("gx", u"高校"),
("gr", u"个人"),
)
name = models.CharField('机构名称',max_length=50)
desc = models.TextField('机构描述')
category = models.CharField(max_length=20, choices=ORG_CHOICES, verbose_name=u"机构类别", default="pxjg")
click_nums = models.IntegerField('点击数',default=0)
fav_nums = models.IntegerField('收藏数',default=0)
image = models.ImageField('logo',upload_to='org/%Y%m',max_length=100)
address = models.CharField('机构地址',max_length=150,)
city = models.ForeignKey(CityDict,verbose_name='所在城市',on_delete=models.CASCADE)
add_time = models.DateTimeField(default=datetime.now) class Meta:
verbose_name = '课程机构'
verbose_name_plural = verbose_name def __str__(self):
return self.name
全部代码
添加后makemigrations-->>migrate
(3)添加机构
添加机构信息的时候要上传机构的图片
在项目目录下面新建一个目录“media”,用来存放上传的图片
setting中要配置我们把文件存放在哪个根目录之下
#settings.py # 设置上传文件的路径
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media') #指定根目录
会跟upload里面拼接完整的路径
“/media/org/2018/月份/图片名字”
然后在后台添加十个机构
7.3.显示课程机构和城市
(1)写视图函数organization/views.py
class OrgView(View):
'''课程机构'''
def get(self,request):
# 取出所有课程机构
all_orgs = CourseOrg.objects.all()
org_onums = all_orgs.count()
# 取出所有城市
all_citys = CityDict.objects.all()
return render(request, "org-list.html", {
"all_orgs": all_orgs,
"all_citys": all_citys,
'org_onums':org_onums,
})
(2)修改org-list.html
显示机构总共数量
显示城市
显示机构
然后还要做下面的设置
如何将image Field转换成图片地址
数据库中image以字符串格式保存的,是相对路径,直接取是取不出来的,必须补全路径
data-url="{{ MEDIA_URL }}{{ course_org.image }}"
MEDIA_URL = '/media/',这个是之前settings中设置好了
要向使用{{ MEDIA_URL }},要先在settings中TEMPLATES 里面添加media处理器:'django.core.context_processors.media'
然后也要添加处理图片相应路径的url
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
#添加图片处理器,为了在课程列表中前面加上MEDIA_URL
'django.template.context_processors.media',
],
},
},
]
urls.py
from django.views.static import serve
from MxOnline.settings import MEDIA_ROOT # 处理图片显示的url,使用Django自带serve,传入参数告诉它去哪个路径找,我们有配置好的路径MEDIAROOT
re_path(r'^media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT })
四个地方
7.4.分页功能
使用 分页神器 django-pure-pagination 分页,github上面有介绍使用方法
(1)安装
pip install django-pure-pagination
(2)settings里面添加
INSTALLED_APPS = (
...
'pure_pagination',
)
(3)views中使用方法
class OrgView(View):
'''课程机构''' def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all()
# 有多少家机构
org_nums = all_orgs.count()
# 所有城市
all_citys = CityDict.objects.all()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示5个
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,
})
(4)修改org-list.html
这里变成 "all_orgs.object_list"
分页功能
<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>
改成每页显示2个列表,如下:
7.5.列表筛选功能
(1)城市列表筛选
- 点城市,筛选出对应的课程机构
- 默认“全部”是‘active’状态(绿色),如果点了某个城市,应该城市是‘active’状态
- 当用户点击city时,应该把city的id传到后台,然后后台在传到模板中,是的可以知道哪个城市被选中,然后加上‘’active‘’
后台处理city筛选
class OrgView(View):
'''课程机构''' def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all()
# 有多少家机构
org_nums = all_orgs.count()
# 所有城市
all_citys = CityDict.objects.all() city_id = request.GET.get('city','')
if city_id:
all_orgs = all_orgs.filter(city_id=int(city_id)) # 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示5个
p = Paginator(all_orgs, 2, 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,
})
前端页面
<h2>所在地区</h2>
<div class="more">更多</div>
<div class="cont">
<a href="?ct="><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>
{% for city in all_citys %}
<a href="?city={{ city.id }}"><span class="{% ifequal city.id|stringformat:'i' city_id %}active2{% endifequal %}">{{ city.name }}</span></a>
{% endfor %}
</div>
因为city.id是一个int类型,要转换成字符串,再作比较。
{% ifequal city_id '' %} 如果为空,说明没有city选中,则“全部”是“active”
(2)类别筛选
后台处理
# 类别筛选
category = request.GET.get('ct','')
if category:
all_orgs = all_orgs.filter(category=category) # 有多少家机构
org_nums = all_orgs.count()
把org_numsf放到后面,先筛选在统计数量
模板中
<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>
<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>
进行城市与分类的联动:
- 当选择全部类别的时候,就只通过当前城市id。
- 当选择全部城市的时候,就只通过当前目录id。
- 当两者都选的时候使用&连接。
(3)课程机构排名筛选
后台处理
按点击量排名,只取前三个
# 热门课程机构排名
hot_orgs = all_orgs.order_by('-click_nums')[:3]
模板中
<div class="right companyrank layout">
<div class="head">授课机构排名</div>
{% for curent_org in hot_orgs %}
<dl class="des">
<dt class="num fl">{{ foorloop.counter }}</dt>
<dd>
<a href="/company/2/"><h1>{{ curent_org.name }}</h1></a>
<p>{{ curent_org.address }}</p>
</dd>
</dl>
{% endfor %}
</div>
循环时内置变量forloop.counter取当前循环到第几次
(4)学习人数和课程的筛选
在models中添加学习人数和课程数两个字段
students = models.IntegerField("学习人数",default=0)
course_nums = models.IntegerField("课程数",default=0)
class CourseOrg(models.Model):
ORG_CHOICES = (
("pxjg", u"培训机构"),
("gx", u"高校"),
("gr", u"个人"),
)
name = models.CharField('机构名称',max_length=50)
desc = models.TextField('机构描述')
category = models.CharField(max_length=20, choices=ORG_CHOICES, verbose_name=u"机构类别", default="pxjg")
click_nums = models.IntegerField('点击数',default=0)
fav_nums = models.IntegerField('收藏数',default=0)
students = models.IntegerField("学习人数",default=0)
course_nums = models.IntegerField("课程数",default=0)
image = models.ImageField('logo',upload_to='org/%Y/%m',max_length=100)
address = models.CharField('机构地址',max_length=150,)
city = models.ForeignKey(CityDict,verbose_name='所在城市',on_delete=models.CASCADE)
add_time = models.DateTimeField(default=datetime.now) class Meta:
verbose_name = '课程机构'
verbose_name_plural = verbose_name def __str__(self):
return self.name
CourseOrg
migrate到数据库
后台处理
# 学习人数和课程数筛选
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")
class OrgView(View):
'''课程机构''' def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all() # 所有城市
all_citys = CityDict.objects.all()
# 城市筛选
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) # 热门课程机构排名
hot_orgs = all_orgs.order_by('-click_nums')[:3]
# 学习人数和课程数筛选
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()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示5个
p = Paginator(all_orgs, 2, 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,
})
OrgView
前端
<div class="head">
<ul class="tab_header">
<li class="{% if sort == '' %}active{% endif %}"><a href="?sort=students&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>
7.6.提交我要学习咨询
(1)用ModelForm来实现
在organazition目录下创建forms.py文件
# organization/forms.py from django import forms
from operation.models import UserAsk class UserAskForm(forms.Form):
'''我要咨询'''
class Meta:
model = UserAsk
fields = ['name','mobile','course_name']
(2)include路由分发
# MxOnline/urls.py import xadmin from django.urls import path,include,re_path from django.views.generic import TemplateView
from users.views import LoginView,RegisterView,ActiveUserView,ForgetPwdView,ResetView,ModifyPwdView from organization.views import OrgView
from django.views.static import serve
from MxOnline.settings import MEDIA_ROOT urlpatterns = [
path('xadmin/', xadmin.site.urls),
path('', TemplateView.as_view(template_name='index.html'),name='index'),
path('login/',LoginView.as_view(),name = 'login'),
path('register/',RegisterView.as_view(),name = 'register'),
path('captcha/',include('captcha.urls')),
re_path('active/(?P<active_code>.*)/',ActiveUserView.as_view(),name='user_active'),
path('forget/',ForgetPwdView.as_view(),name='forget_pwd'),
re_path('reset/(?P<active_code>.*)/', ResetView.as_view(), name='reset_pwd'),
path('modify_pwd/', ModifyPwdView.as_view(), name='modify_pwd'), path('org_list/',OrgView.as_view(),name = 'org_list'),
# 处理图片显示的url,使用Django自带serve,传入参数告诉它去哪个路径找,我们有配置好的路径MEDIAROOT
re_path(r'^media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT }),
]
MxOnline/urls.py
删掉org_list的那个路由,改成include
path("org/", include('organization.urls', namespace="org")),
使用命名空间防止重复
然后在organization/urls.py中添加
# organization/urls.py from organization.views import OrgView from django.urls import path,re_path # 要写上app的名字
app_name = "organization" urlpatterns = [
path('list/',OrgView.as_view(),name='org_list'),
]
html中使用命名空间的方式:
修改base.html中“课程机构的链接”
<li class="active" ><a href="{% url 'org:org_list' %}">授课机构</a></li>
(3)视图函数
from django.http import HttpResponse
from .forms import UserAskForm class AddUserAskView(View):
"""
用户添加咨询
"""
def post(self, request):
userask_form = UserAskForm(request.POST)
if userask_form.is_valid():
user_ask = userask_form.save(commit=True)
# 如果保存成功,返回json字符串,后面content type是告诉浏览器返回的数据类型
return HttpResponse('{"status":"success"}', content_type='application/json')
else:
# 如果保存失败,返回json字符串,并将form的报错信息通过msg传递到前端
return HttpResponse('{"status":"fail", "msg":"添加出错"}', content_type='application/json')
# organization/views.py from django.shortcuts import render from django.views.generic import View
from .models import CourseOrg,CityDict
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger from django.http import HttpResponse
from .forms import UserAskForm class OrgView(View):
'''课程机构''' def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all() # 所有城市
all_citys = CityDict.objects.all()
# 城市筛选
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) # 热门课程机构排名
hot_orgs = all_orgs.order_by('-click_nums')[:3]
# 学习人数和课程数筛选
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()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示5个
p = Paginator(all_orgs, 2, 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,
}) class AddUserAskView(View):
"""
用户添加咨询
"""
def post(self, request):
userask_form = UserAskForm(request.POST)
if userask_form.is_valid():
user_ask = userask_form.save(commit=True)
# 如果保存成功,返回json字符串,后面content type是告诉浏览器返回的数据类型
return HttpResponse('{"status":"success"}', content_type='application/json')
else:
# 如果保存失败,返回json字符串,并将form的报错信息通过msg传递到前端
return HttpResponse('{"status":"fail", "msg":"添加出错"}', content_type='application/json')
views.py
这里要用到Ajax提交,不会对页面整体刷新,应该给前端返回一个Json数据
HttpResponse可以指定传递到前端的数据类型
(4)配置url
# organization/urls.py from organization.views import OrgView,AddUserAskView from django.urls import path,re_path # 要写上app的名字
app_name = "organization" urlpatterns = [
path('list/',OrgView.as_view(),name='org_list'),
path('add_ask/', AddUserAskView.as_view(), name="add_ask"),
]
(5)在ModelForm中自定义一个手机号验证的方法
# organization/forms.py import re
from django import forms
from operation.models import UserAsk class UserAskForm(forms.ModelForm): class Meta:
model = UserAsk
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")
(6)模板中使用Ajax方式提交
org-list.html
<div class="right companyright">
<div class="head">我要学习</div>
<form class="rightform" id="jsStayForm">
<div>
<img src="{% static 'images/rightform1.png' %}"/>
<input type="text" name="name" id="companyName" placeholder="名字" maxlength="25"/>
</div>
<div>
<img src="{% static 'images/rightform2.png' %}"/>
<input type="text" name="mobile" id="companyMobile" placeholder="联系电话"/>
</div>
<div>
<img src="{% static 'images/rightform3.png' %}"/>
<input type="text" name="course_name" id="companyAddress" placeholder="课程名" maxlength="50"/>
</div>
<p class="error company-tips" id="jsCompanyTips"></p>
<input class="btn" type="text" id="jsStayBtn" value="立即咨询 >"/>
{% csrf_token %}
</form>
</div>
<script>
$(function () {
$('#jsStayBtn').on('click', function () {
$.ajax({
cache: false,
type: "POST",
url: "{% url "org:add_ask" %}",
data: $('#jsStayForm').serialize(),
async: true,
success: function (data) {
if (data.status == 'success') {
$('#jsStayForm')[0].reset();
alert("提交成功")
} else if (data.status == 'fail') {
$('#jsCompanyTips').html(data.msg)
}
},
});
});
})
</script>
{#templates/org-list.html#}
{% extends 'base.html' %}
{% load staticfiles %} {% block title %}课程机构列表{% endblock %} {% block custom_bread %}
<section>
<div class="wp">
<ul class="crumbs">
<li><a href="index.html">首页</a>></li>
<li>课程机构</li>
</ul>
</div>
</section>
{% endblock %} {% block content %}
<section>
<div class="wp butler_list_box list">
<div class='left'>
<div class="listoptions">
<ul>
<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>
<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>
</ul>
</div> <div class="all">共<span class="key">{{ org_nums }}</span>家</div> <div class="butler_list company list">
<div class="layout">
<div class="head">
<ul class="tab_header">
<li class="{% if sort == '' %}active{% endif %}"><a
href="?sort=students&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> {% for course_org in all_orgs.object_list %}
<dl class="des difdes"> <dt>
<a href="org-detail-homepage.html"> <img width="200" height="120" class="scrollLoading"
data-url="{{ MEDIA_URL }}{{ course_org.image }}"/> </a>
</dt>
<dd>
<div class="clearfix">
<a href="org-detail-homepage.html">
<h1>{{ course_org.name }}</h1>
<div class="pic fl"> <img src="{% static 'images/authentication.png' %}"/> <img src="{% static 'images/gold.png' %}"/> </div>
</a>
</div>
<ul class="cont">
<li class="first"><p class="pic9">课程数:<span>1</span></p>
<p class="c7">学习人数:<span>1000</span></p></li>
<li class="c8" style="padding-left:18px;">北京市海淀区中关村北大街</li>
<li class="pic10" style="padding-left:18px;">经典课程: <a href="/diary/19/">c语言基础入门</a> <a href="/diary/16/">数据库基础</a> </li>
</ul>
</dd>
<div class="buy start_groupbuy jsShowPerfect2" data-id="22"><br/>联系<br/>服务</div>
</dl>
{% endfor %} </div>
<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> </div>
</div> <div class="right companyright">
<div class="head">我要学习</div>
<form class="rightform" id="jsStayForm">
<div>
<img src="{% static 'images/rightform1.png' %}"/>
<input type="text" name="name" id="companyName" placeholder="名字" maxlength="25"/>
</div>
<div>
<img src="{% static 'images/rightform2.png' %}"/>
<input type="text" name="mobile" id="companyMobile" placeholder="联系电话"/>
</div>
<div>
<img src="{% static 'images/rightform3.png' %}"/>
<input type="text" name="course_name" id="companyAddress" placeholder="课程名" maxlength="50"/>
</div>
<p class="error company-tips" id="jsCompanyTips"></p>
<input class="btn" type="text" id="jsStayBtn" value="立即咨询 >"/>
{% csrf_token %}
</form>
</div> <div class="right companyrank layout">
<div class="head">授课机构排名</div>
{% for curent_org in hot_orgs %}
<dl class="des">
<dt class="num fl">{{ foorloop.counter }}</dt>
<dd>
<a href="/company/2/"><h1>{{ curent_org.name }}</h1></a>
<p>{{ curent_org.address }}</p>
</dd>
</dl>
{% endfor %}
</div>
</div>
</section>
{% endblock %} <script>
$(function () {
$('#jsStayBtn').on('click', function () {
$.ajax({
cache: false,
type: "POST",
url: "{% url "org:add_ask" %}",
data: $('#jsStayForm').serialize(),
async: true,
success: function (data) {
if (data.status == 'success') {
$('#jsStayForm')[0].reset();
alert("提交成功")
} else if (data.status == 'fail') {
$('#jsCompanyTips').html(data.msg)
}
},
});
});
})
</script>
org-list.html全部代码
Ajax代码说明:
- 第一行表示:其它代码执行完再执行
- 给“立即咨询”按钮绑定click事件,点击后执行function()函数里面的代码
- cache:false 这个参数默认True,表示缓存,这里改为false,表示不用缓存
- type:post 以post方式发送数据
- url:把请求发送到哪个url
- data:发送到服务器的数据
- async:ture 表示异步发送
- success:请求成功时执行的回调函数,data是服务器返回过来的数据
- 因为后台返回的数据是{"status’:"success"}或者{"status’:"fail"},这里做个判断
- 如果是“success”,则把提交表单里面的数据清空,如果是“fail”,显示错误信息
提交数据不合法时
合法时,提示成功信息,数据保存到数据库
7.7.机构首页
(1)给courses添加一个外键
from organization.models import CourseOrg course_org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, verbose_name="所属机构", null=True, blank=True)
# course/models.py from datetime import datetime from django.db import models
from organization.models import CourseOrg class Course(models.Model):
DEGREE_CHOICES = (
("cj", "初级"),
("zj", "中级"),
("gj", "高级")
)
name = models.CharField("课程名",max_length=50)
desc = models.CharField("课程描述",max_length=300)
detail = models.TextField("课程详情")
degree = models.CharField('难度',choices=DEGREE_CHOICES, max_length=2)
learn_times = models.IntegerField("学习时长(分钟数)",default=0)
students = models.IntegerField("学习人数",default=0)
fav_nums = models.IntegerField("收藏人数",default=0)
image = models.ImageField("封面图",upload_to="courses/%Y/%m",max_length=100)
click_nums = models.IntegerField("点击数",default=0)
add_time = models.DateTimeField("添加时间",default=datetime.now,)
course_org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, verbose_name="所属机构", null=True, blank=True) class Meta:
verbose_name = "课程"
verbose_name_plural = verbose_name def __str__(self):
return self.name
全部代码
在后台添加课程和讲师
(2)模板
把课程机构页面的四个文件拷贝到templates目录下
新建一个模板,命名为“org_base.html”,复制org-detail-homepage.html的内容到里面
添加block,修改静态文件路径
{#templates/org_base.html#} {% load staticfiles %}
<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
<title>{% block title %}机构首页{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/animate.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'js/plugins/queryCity/css/cityLayout.css' %}">
{% block custom_css %}{% endblock %}
<script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
<script src="{% static 'js/jquery-migrate-1.2.1.min.js' %}" type="text/javascript"></script>
{% block custom_js %}{% endblock %}
</head>
<body>
<section class="headerwrap headerwrap2">
<header>
<div class="header2 header"> <div class="top">
<div class="wp">
<div class="fl">
<p>联系方式:<b>3333333333</b></p>
</div>
<a style="color:white" class="fr registerbtn" href="register.html">注册</a>
<a style="color:white" class="fr loginbtn" href="login.html">登录</a>
</div>
</div> <div class="middle companyheader">
<div class="wp">
<img class="fl" style="width: 112px;height: 103px" src="{% static 'media/org/2016/11/imooc.png' %}"/>
<div class="head fl">
<h1>
慕课网
<img src="{% static 'images/authentication.png' %}"/>
<img src="{% static 'images/gold.png' %}"/>
</h1>
<p class="fl">
<span class="fl" style="margin-top:8px;color:#848484;">推荐指数: </span>
<span class="precision company-credit" data-star-scope="5.0"></span>
<span class="key">5.0</span>
</p>
</div>
<div class="btn fr collectionbtn notlogin
"data-favid="22" data-fav-type="1">
收藏
</div> </div>
</div>
</div>
</header>
</section>
<section>
<div class="wp">
<ul class="crumbs">
<li><a href="index.html">首页</a>></li>
<li><a href="org-list.html">课程机构</a>></li>
<li>{% block page_path %}机构首页{% endblock %}</li>
</ul>
</div>
</section> <section>
<div class="wp list personal_list comp">
<div class="left">
<ul>
<li class="active2"><a href="org-detail-homepage.html">机构首页</a></li>
<li class=""><a href="org-detail-course.html">机构课程</a></li>
<li class=""><a href="org-detail-desc.html">机构介绍</a></li>
<li class=""><a href="org-detail-teachers.html">机构讲师</a></li>
</ul>
</div> {% block right_form %}
{% endblock %} <div class="head">
<h1>机构介绍</h1>
<a class="green fr more" href="org-detail-desc.html">查看更多 > </a>
</div>
<div class="cont"> <p> </p><h1 class="ue_t" label="Title center" name="tc" style="border-bottom-color:#cccccc;border-bottom-width:2px;border-bottom-style:solid;padding:0px 4px 0px 0px;text-align:center;margin:0px 0px 20px;"><span style="color:#c0504d;">[键入文档标题]</span></h1><p style="text-align:center;"><strong class="ue_t">[键入文档副标题]</strong></p><h3><span class="ue_t" style="font-family:幼圆">[标题 1]</span></h3><p class="ue_t" style="text-indent:2em;">对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。</p><p class="ue_t" style="text-indent:2em;"><img src="../media/courses/ueditor/57aa86a0000145c512000460_20161210234050_865.jpg" title="" alt="57aa86a0000145c512000460.jpg"/> </p><h3><span class="ue_t" style="font-family:幼圆">[标题 2]</span></h3><p><img src="http://api.map.baidu.com/staticimage?center=116.410899,39.863624&zoom=11&width=530&height=340&markers=116.404,39.915" width="530" height="340"/> </p><p class="ue_t" style="text-indent:2em;">在“开始”选项卡上,通过从快速样式库中为所选文本选择一种外观,您可以方便地更改文档中所选文本的格式。 您还可以使用“开始”选项卡上的其他控件来直接设置文本格式。大多数控件都允许您选择是使用当前主题外观,还是使用某种直接指定的格式。</p><h3><span class="ue_t" style="font-family:幼圆">[标题 3]</span></h3><p>2016-12-10</p><p class="ue_t">对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。</p><p class="ue_t"><br/> </p><p><br/></p><p><br/></p><a href="/company/desc/22/"><span class="green">[查看更多]</span></a></div>
</div> </section>
<!--sidebar start-->
<section>
<ul class="sidebar">
<li class="qq">
<a target="_blank" href="http://wpa.qq.com/msgrd?v=3&uin=2023525077&site=qq&menu=yes"></a>
</li>
<li class="totop"></li>
</ul>
</section>
<!--sidebar end-->
<!--header start-->
</div>
<!--弹出省省市-->
<script src="{% static 'js/selectUi.js' %}" type='text/javascript'></script>
<script type="text/javascript" src="{% static 'js/plugins/laydate/laydate.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'js/plugins/queryCity/js/public.js' %}" type="text/javascript"></script> <script type="text/javascript" src="{% static 'js/plugins/jquery.raty.js' %}"></script>
<script type="text/javascript">
//收藏分享
//收藏分享
function add_fav(current_elem, fav_id, fav_type){
$.ajax({
cache: false,
type: "POST",
url:"/org/add_fav/",
data:{'fav_id':fav_id, 'fav_type':fav_type},
async: true,
beforeSend:function(xhr, settings){
xhr.setRequestHeader("X-CSRFToken", "5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy");
},
success: function(data) {
if(data.status == 'fail'){
if(data.msg == '用户未登录'){
window.location.href="login.html";
}else{
alert(data.msg)
} }else if(data.status == 'success'){
current_elem.text(data.msg)
}
},
});
} $('.collectionbtn').on('click', function(){
add_fav($(this), 1, 2);
}); $(function(){
var $precision = $('.precision'),
score = $precision.attr('data-star-scope'),
option = {
half : true,
path : '../images/',
precision : true,
size : 24,
starOff : 'g_star.png',
starOn : 'r_star.png',
starHalf : 'h_star.png',
hints : ['极差', '差', '一般', '好评', '非常满意'],
noRatedMsg : '暂时还未获得评价!',
readOnly : true,
score : score
};
$precision.raty(option); $('.jsFavBtn').on('click', function(){
var type = $(this).attr('data-fav-type');
if(type == '1'){
favPraise($(this), 'fav' ,1 , '收藏'); }else if(type == '3'){
favPraise($(this), 'fav' ,3 ); }else if(type == '11'){
favPraise($(this), 'pra', 1); }else if(type == '4'){
favPraise($(this), 'fav' ,4 ); }
});
})
</script> <script type="text/javascript">
$(function() {
$('.recordbtn1').click(function(){
$('.recordbox1').show();
});
$('.recordbtn2').click(function(){
$('.recordbox2').show();
}); $('.imgslide').unslider({
speed: 500, // The speed to animate each slide (in milliseconds)
delay: 3000, // The delay between slide animations (in milliseconds)
complete: function() {}, // A function that gets called after every slide animation
keys: true, // Enable keyboard (left, right) arrow shortcuts
dots: true, // Display dot navigation
fluid: false // Support responsive design. May break non-responsive designs
});
var unslider = $('.imgslide').unslider();
$('.unslider-arrow').click(function() {
var fn = this.className.split(' ')[1];
unslider.data('unslider')[fn]();
});
});
</script> </body>
</html>
org_base.html
(3)org-detail-homepage.html继承模板
把org_base中的三个“right”剪切到home里面
(4)home页面的url
from .views import OrgHomeView re_path('home/(?P<org_id>\d+)/', OrgHomeView.as_view(), name="org_home"),
(5)后端逻辑处理
class OrgHomeView(View):
'''机构首页''' def get(self,request,org_id):
# 根据id找到课程机构
course_org = CourseOrg.objects.get(id=int(org_id))
# 反向查询到课程机构的所有课程和老师
all_courses = course_org.course_set.all()[:4]
all_teacher = course_org.teacher_set.all()[:2]
return render(request,'org-detail-homepage.html',{
'course_org':course_org,
'all_courses':all_courses,
'all_teacher':all_teacher,
})
(6)显示全部课程
<div class="brief group_list">
{% for course in all_courses %}
<div class="module1_5 box">
<a href="course-detail.html"><img width="214" src="{{ MEDIA_URL }}{{ course.image }}"/></a>
<div class="des">
<a href="course-detail.html"><h2>{{ course.name }}</h2></a>
<span class="fl">课时:<i class="key">{{ course.learn_times }}</i></span>
<span class="fr">参加人数:{{ course.students }}</span>
</div>
<div class="bottom">
<span class="fl">{{ course.course_org.name }}</span>
<span class="star fr notlogin
" data-favid="13" data-fav-type="4">
{{ course.fav_nums }}
</span>
</div>
</div>
{% endfor %}
</div>
在org-list.html中修改链接,点击机构,跳到对应机构主页
(6)修改org-base.html
(7)为teacher添加一个图形字段
image = models.ImageField(
default= '',
upload_to="teacher/%Y/%m",
verbose_name="头像",
max_length=100)
(8)显示机构教师
(9)显示机构详情
机构 首页:
7.8.机构课程
(1)模板文件
把org-detail-course.html中不同的地方(right)取出来
(2)添加url
re_path('course/(?P<org_id>\d+)/', OrgCourseView.as_view(), name="org_course"),
(3)views.py
class OrgCourseView(View):
"""
机构课程列表页
"""
def get(self, request, org_id):
# 根据id取到课程机构
course_org = CourseOrg.objects.get(id= int(org_id))
# 通过课程机构找到课程。内建的变量,找到指向这个字段的外键引用
all_courses = course_org.course_set.all() return render(request, 'org-detail-course.html',{
'all_courses':all_courses,
'course_org': course_org,
})
(4)修改org-base.html中left的链接
(5)显示机构课程,修改org-detail-course.html
<div class="brief group_list">
{% for course in all_courses %}
<div class="module1_5 box">
<a class="comp-img-box" href="course-detail.html"> <img width="214" height="195" src="{{ MEDIA_URL }}{{ course.image }}"/>
</a>
<div class="des">
<a href="course-detail.html"><h2>{{ course.name }}</h2></a>
<span class="fl">课时:<i class="key">{{ course.learn_times }}</i></span>
<span class="fr">学习人数{{ course.students }}</span>
</div>
<div class="bottom">
<span class="fl">{{ course.course_org.name }}</span>
<span class="star fr notlogin
" data-favid="13" data-fav-type="4">
{{ course.fav_nums }}
</span>
</div>
</div>
{% endfor %}
点“机构课程”,看有哪些课程
(6)左侧“active”状态修改
因为现在没有值能判断当前是哪个页面。所以在后台传个current page参数
修改org_base.html
<div class="left">
<ul>
<li class="{% ifequal current_page 'home' %}active2{% endifequal %}"><a href="{% url 'org:org_home' course_org.id %}">机构首页</a></li>
<li class="{% ifequal current_page 'course' %}active2{% endifequal %}"><a href="{% url 'org:org_course' course_org.id %}">机构课程</a></li>
<li class="{% ifequal current_page 'desc' %}active2{% endifequal %}"><a href="org-detail-desc.html">机构介绍</a></li>
<li class="{% ifequal current_page 'teacher' %}active2{% endifequal %}"><a href="org-detail-teachers.html">机构讲师</a></li>
</ul>
</div>
修改views,传个current_page参数到前端,可以知道当前是哪个被激活状态
class OrgHomeView(View):
'''机构首页''' def get(self,request,org_id):
current_page = 'home'
# 根据id找到课程机构
course_org = CourseOrg.objects.get(id=int(org_id))
# 反向查询到课程机构的所有课程和老师
all_courses = course_org.course_set.all()[:4]
all_teacher = course_org.teacher_set.all()[:2]
return render(request,'org-detail-homepage.html',{
'course_org':course_org,
'all_courses':all_courses,
'all_teacher':all_teacher,
'current_page':current_page,
})
class OrgCourseView(View):
"""
机构课程列表页
"""
def get(self, request, org_id):
current_page = 'course'
# 根据id取到课程机构
course_org = CourseOrg.objects.get(id= int(org_id))
# 通过课程机构找到课程。内建的变量,找到指向这个字段的外键引用
all_courses = course_org.course_set.all() return render(request, 'org-detail-course.html',{
'all_courses':all_courses,
'course_org': course_org,
'current_page':current_page,
})
7.9.机构介绍
(1)url
re_path('desc/(?P<org_id>\d+)/', OrgDescView.as_view(), name="org_desc"),
(2)views
class OrgDescView(View):
'''机构介绍页'''
def get(self, request, org_id):
current_page = 'desc'
# 根据id取到课程机构
course_org = CourseOrg.objects.get(id= int(org_id))
return render(request, 'org-detail-desc.html',{
'course_org': course_org,
'current_page':current_page,
})
7.10.机构讲师
(1)url
re_path('teacher/(?P<org_id>\d+)/', OrgTeacherView.as_view(), name="org_teacher"),
(2)views
class OrgTeacherView(View):
"""
机构教师页
"""
def get(self, request, org_id):
current_page = 'teacher'
course_org = CourseOrg.objects.get(id= int(org_id))
all_teacher = course_org.teacher_set.all() return render(request, 'org-detail-teachers.html',{
'all_teacher':all_teacher,
'course_org': course_org,
'current_page':current_page,
})
(3)org-detail-teachers.html
{% extends 'org_base.html' %}
{% load staticfiles %} <title>{% block title %}机构教师页--新东方{% endblock %}</title> {% block right_form %}
<div class="right companycenter layout" >
<div class="head">
<h1>机构讲师</h1>
</div>
<div class="messagelist">
<div class=" butler_list butler-fav-box">
{% for teacher in all_teacher %}
<dl class="des users">
<dt>
<a href="">
<img width="100" height="100" class="scrollLoading" data-url="{{ MEDIA_URL }}{{ teacher.image }}" src="{{ MEDIA_URL }}{{ teacher.image }}"/>
</a>
</dt>
<dd>
<h1>
<a href="">
{{ teacher.name }}<span class="key">已认证</span>
</a>
</h1>
<ul class="cont clearfix">
<li class="time">工作年限:<span>{{ teacher.work_years }}</span></li>
<li class="c7">课程数:<span>3</span></li>
</ul>
</dd>
</dl>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
(4)org-bae.html中left
<ul>
<li class="{% ifequal current_page 'home' %}active2{% endifequal %}"><a href="{% url 'org:org_home' course_org.id %}">机构首页</a></li>
<li class="{% ifequal current_page 'course' %}active2{% endifequal %}"><a href="{% url 'org:org_course' course_org.id %}">机构课程</a></li>
<li class="{% ifequal current_page 'desc' %}active2{% endifequal %}"><a href="{% url 'org:org_desc' course_org.id %}">机构介绍</a></li>
<li class="{% ifequal current_page 'teacher' %}active2{% endifequal %}"><a href="{% url 'org:org_teacher' course_org.id %}">机构讲师</a></li>
</ul>
(5)修改面包屑,点机构课程应该显示机构课程
base.html
然后分别在其它四个页面中重载page_path
其它三个方法一样
7.11.课程机构收藏功能
(1)url
path('add_fav/', AddFavView.as_view(), name="add_fav"),
# organization/urls.py from organization.views import OrgView,AddUserAskView from django.urls import path,re_path
from .views import OrgHomeView,OrgCourseView,OrgDescView,OrgTeacherView,AddFavView # 要写上app的名字
app_name = "organization" urlpatterns = [
path('list/',OrgView.as_view(),name='org_list'),
path('add_ask/', AddUserAskView.as_view(), name="add_ask"),
re_path('home/(?P<org_id>\d+)/', OrgHomeView.as_view(), name="org_home"),
re_path('course/(?P<org_id>\d+)/', OrgCourseView.as_view(), name="org_course"),
re_path('desc/(?P<org_id>\d+)/', OrgDescView.as_view(), name="org_desc"),
re_path('teacher/(?P<org_id>\d+)/', OrgTeacherView.as_view(), name="org_teacher"),
path('add_fav/', AddFavView.as_view(), name="add_fav"),
]
organization/urls.py
# MxOnline/urls.py import xadmin from django.urls import path,include,re_path from django.views.generic import TemplateView
from users.views import LoginView,RegisterView,ActiveUserView,ForgetPwdView,ResetView,ModifyPwdView
from organization.views import OrgView
from django.views.static import serve
from MxOnline.settings import MEDIA_ROOT urlpatterns = [
path('xadmin/', xadmin.site.urls),
path('', TemplateView.as_view(template_name='index.html'),name='index'),
path('login/',LoginView.as_view(),name = 'login'),
path('register/',RegisterView.as_view(),name = 'register'),
path('captcha/',include('captcha.urls')),
re_path('active/(?P<active_code>.*)/',ActiveUserView.as_view(),name='user_active'),
path('forget/',ForgetPwdView.as_view(),name='forget_pwd'),
re_path('reset/(?P<active_code>.*)/', ResetView.as_view(), name='reset_pwd'),
path('modify_pwd/', ModifyPwdView.as_view(), name='modify_pwd'), path("org/", include('organization.urls', namespace="org")),
# 处理图片显示的url,使用Django自带serve,传入参数告诉它去哪个路径找,我们有配置好的路径MEDIAROOT
re_path(r'^media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT }),
]
MxOnline/urls.py
(2)后台处理
class AddFavView(View):
"""
用户收藏和取消收藏
"""
def post(self, request):
id = request.POST.get('fav_id', 0) # 防止后边int(fav_id)时出错
type = request.POST.get('fav_type', 0) # 防止int(fav_type)出错 if not request.user.is_authenticated:
# 未登录时返回json提示未登录,跳转到登录页面是在ajax中做的
return HttpResponse('{"status":"fail", "msg":"用户未登录"}', content_type='application/json') exist_record = UserFavorite.objects.filter(user=request.user, fav_id=int(id), fav_type=int(type))
if exist_record:
# 如果记录已经存在,表示用户取消收藏
exist_record.delete()
return HttpResponse('{"status":"success", "msg":"收藏"}', content_type='application/json')
else:
user_fav = UserFavorite()
if int(id) > 0 and int(type) > 0:
user_fav.user = request.user
user_fav.fav_id = int(id)
user_fav.fav_type = int(type)
user_fav.save()
return HttpResponse('{"status":"success", "msg":"已收藏"}', content_type='application/json')
else:
return HttpResponse('{"status":"fail", "msg":"收藏出错"}', content_type='application/json')
(3)前端Ajax
Ajax放在org_base.html里面
<script type="text/javascript">
//收藏分享
//收藏分享
function add_fav(current_elem, fav_id, fav_type){
$.ajax({
cache: false,
type: "POST",
url:"{% url 'org:add_fav' %}",
data:{'fav_id':fav_id, 'fav_type':fav_type},
async: true,
beforeSend:function(xhr, settings){
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(data) {
if(data.status == 'fail'){
if(data.msg == '用户未登录'){
window.location.href="/login/";
}else{
alert(data.msg)
} }else if(data.status == 'success'){
current_elem.text(data.msg)
}
},
});
} $('.collectionbtn').on('click', function(){
add_fav($(this), {{ course_org.id }}, 2);
});
访问页面点右上角的“收藏”,可以发现正常工作了
可以在数据库中看到用户的收藏
(4)但是还有个问题就是 ,刷新页面后,“已收藏”就变成“收藏”,是因为在返回页面的时候,没有判断收藏状态
所有要在views里面加个判断
# 判断收藏状态
has_fav = False
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
has_fav = True
四个页面都加上这个判断
# organization/views.py from django.shortcuts import render from django.views.generic import View
from .models import CourseOrg,CityDict
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger from django.http import HttpResponse
from .forms import UserAskForm
from operation.models import UserFavorite
from django.contrib.auth import authenticate class OrgView(View):
'''课程机构''' def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all() # 所有城市
all_citys = CityDict.objects.all()
# 城市筛选
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) # 热门课程机构排名
hot_orgs = all_orgs.order_by('-click_nums')[:3]
# 学习人数和课程数筛选
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()
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示5个
p = Paginator(all_orgs, 2, 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,
}) class AddUserAskView(View):
"""
用户添加咨询
"""
def post(self, request):
userask_form = UserAskForm(request.POST)
if userask_form.is_valid():
user_ask = userask_form.save(commit=True)
# 如果保存成功,返回json字符串,后面content type是告诉浏览器返回的数据类型
return HttpResponse('{"status":"success"}', content_type='application/json')
else:
# 如果保存失败,返回json字符串,并将form的报错信息通过msg传递到前端
return HttpResponse('{"status":"fail", "msg":"添加出错"}', content_type='application/json') class OrgHomeView(View):
'''机构首页''' def get(self,request,org_id):
current_page = 'home'
# 根据id找到课程机构
course_org = CourseOrg.objects.get(id=int(org_id))
# 判断收藏状态
has_fav = False
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
has_fav = True
# 反向查询到课程机构的所有课程和老师
all_courses = course_org.course_set.all()[:4]
all_teacher = course_org.teacher_set.all()[:2]
return render(request,'org-detail-homepage.html',{
'course_org':course_org,
'all_courses':all_courses,
'all_teacher':all_teacher,
'current_page':current_page,
'has_fav':has_fav,
}) class OrgCourseView(View):
"""
机构课程列表页
"""
def get(self, request, org_id):
current_page = 'course'
# 根据id取到课程机构
course_org = CourseOrg.objects.get(id= int(org_id))
# 通过课程机构找到课程。内建的变量,找到指向这个字段的外键引用
all_courses = course_org.course_set.all()
# 判断收藏状态
has_fav = False
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
has_fav = True return render(request, 'org-detail-course.html',{
'all_courses':all_courses,
'course_org': course_org,
'current_page':current_page,
'has_fav': has_fav,
}) class OrgDescView(View):
'''机构介绍页'''
def get(self, request, org_id):
current_page = 'desc'
# 根据id取到课程机构
course_org = CourseOrg.objects.get(id= int(org_id))
# 判断收藏状态
has_fav = False
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
has_fav = True
return render(request, 'org-detail-desc.html',{
'course_org': course_org,
'current_page':current_page,
'has_fav': has_fav,
}) class OrgTeacherView(View):
"""
机构教师页
"""
def get(self, request, org_id):
current_page = 'teacher'
course_org = CourseOrg.objects.get(id= int(org_id))
all_teacher = course_org.teacher_set.all()
# 判断收藏状态
has_fav = False
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
has_fav = True return render(request, 'org-detail-teachers.html',{
'all_teacher':all_teacher,
'course_org': course_org,
'current_page':current_page,
'has_fav': has_fav,
}) class AddFavView(View):
"""
用户收藏和取消收藏
"""
def post(self, request):
fav_id = request.POST.get('fav_id', 0) # 防止后边int(fav_id)时出错
fav_type = request.POST.get('fav_type', 0) # 防止int(fav_type)出错 if not request.user.is_authenticated:
# 未登录时返回json提示未登录,跳转到登录页面是在ajax中做的
return HttpResponse('{"status":"fail", "msg":"用户未登录"}', content_type='application/json') exist_record = UserFavorite.objects.filter(user=request.user, fav_id=int(fav_id), fav_type=int(fav_type))
if exist_record:
# 如果记录已经存在,表示用户取消收藏
exist_record.delete()
return HttpResponse('{"status":"fail", "msg":"已取消收藏"}', content_type='application/json')
else:
user_fav = UserFavorite()
if int(fav_id) > 0 and int(fav_type) > 0:
user_fav.user = request.user
user_fav.fav_id = int(fav_id)
user_fav.fav_type = int(fav_type)
user_fav.save()
return HttpResponse('{"status":"success", "msg":"已收藏"}', content_type='application/json')
else:
return HttpResponse('{"status":"fail", "msg":"收藏出错"}', content_type='application/json')
organization/views.py
(5)在org_base.html添加判断
(6)修改右上角登录和注册
把index.html页面中的登录、注册判断放到org_base里面
完善url链接
(1)org-detail-homepage.html
(2)org-detail-course.html
(3)org-detail-teachers.html
Django+xadmin打造在线教育平台(四)的更多相关文章
- Django+xadmin打造在线教育平台(二)
三.xadmin后台管理 3.1.xadmin的安装 django2.0的安装(源码安装方式): https://github.com/sshwsfc/xadmin/tree/django2 把zip ...
- Django+xadmin打造在线教育平台(三)
五.完成注册.找回密码和激活验证码功能 5.1.用户注册 register.html拷贝到templates目录 (1)users/views.py class RegisterView(View): ...
- Django+xadmin打造在线教育平台(一)
目录 在线教育平台(一) 在线教育平台(二) 在线教育平台(三) 在线教育平台(四) 在线教育平台(五) 在线教育平台(六) 在线教育平台(七) 在线教育平台( ...
- Django+xadmin打造在线教育平台(六)
九.课程章节信息 9.1.模板和urls 拷贝course-comments.html 和 course-video.html放入 templates目录下 先改course-video.html,同 ...
- Django+xadmin打造在线教育平台(十)
十四.xadmin的进阶开发 14.1.权限管理 (1)用户权限 超级用户拥有所有权限,其它添加的用户默认没有任何权限 进后台添加一个用户“Editor1”,勾上“职员状态”后,这个用户才可以登录进后 ...
- Django+xadmin打造在线教育平台(五)
目录 在线教育平台(一) 在线教育平台(二) 在线教育平台(三) 在线教育平台(四) 在线教育平台(五) 在线教育平台(六) 在线教育平台(七) 在线教育平台( ...
- Django+xadmin打造在线教育平台(七)
十.授课教师 10.1.讲师列表页 拷贝teacher-list.html和teacher-detail.html到templates目录下 先改teacher-list.html,同样继承base. ...
- Django+xadmin打造在线教育平台(八)
十一.用户信息 11.1.个人信息展示 (1)新建‘usercenter-bae.html’当母板 {% load staticfiles %} <!DOCTYPE html> <h ...
- Django+xadmin打造在线教育平台(九)
目录 在线教育平台(一) 在线教育平台(二) 在线教育平台(三) 在线教育平台(四) 在线教育平台(五) 在线教育平台(六) 在线教育平台(七) 在线教育平台( ...
随机推荐
- 【视频教程】一步步将AppBox升级到Pro版
本系列教程分为上中下三部分,通过视频的形式讲解如何将基于FineUI(开源版)的AppBox v6.0一步一步升级FineUIPro(基础版). [视频教程]一步步将AppBox升级到Pro版(上)主 ...
- CEPH RGW 设置 user default_placement为ssd-placement,优化100KB-200KB小文件性能,使用户创建的bucket对象放置到 SSD设备的Pool上。
sudo radosgw-admin metadata get user:tuanzi > user.md.json vi user.md.json #to add ssd-placement ...
- AndFix
AndFix 是阿里巴巴开源的 Android 应用热修复工具,帮助 Anroid 开发者修复应用的线上问题.Andfix 是 "Android hot-fix" 的缩写.支持 A ...
- Srtuts2实现登录界面(不连接数据库)
1.设计思路 (1)利用Struts2框架设计出一个登录页面的跳转,当用户名和密码都正确时, 跳到登录成功页面:否则,跳到登录失败页面,并在10秒钟内跳到登录界面: (2)在Action中判断用户名和 ...
- eclipse在线安装JBoss Tool过程
eclipse在线安装JBoss Tool过程 1.打开eclipse,依次点击"help--->Install New Software..." 2.再单击"Ad ...
- Direcshow中视频捕捉和参数设置报告
Direcshow中视频捕捉和参数设置报告 1. 关于视频捕捉(About Video Capture in Dshow) 1视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图 ...
- Flex中对表格中某列的值进行数字格式化并求百分比
1.问题背景 一般的,需要对表格中某列的数值进行格式化,对该数值乘以100,并保留两位小数,添加"%" 2.实现实例 <?xml version="1.0" ...
- 芝麻HTTP:TensorFlow LSTM MNIST分类
本节来介绍一下使用 RNN 的 LSTM 来做 MNIST 分类的方法,RNN 相比 CNN 来说,速度可能会慢,但可以节省更多的内存空间. 初始化 首先我们可以先初始化一些变量,如学习率.节点单元数 ...
- Django学习-6-路由系统
1.url(r'^index/', views.index), 函数处理 url(r'^home/', views.Home.as_view()), 类方法处理 ...
- BZOJ 2969: 矩形粉刷(期望)
BZOJ 2969: 矩形粉刷(期望) 题意: 给你一个\(w*h\)的方阵,不断在上面刷格子.每次等概率选择方阵中的两个点(可以相同)将以这两个点为端点的矩形(边平行于矩形边界)进行染色.共染\(k ...