|
|
@@ -12,35 +12,34 @@ from django.db import models
|
|
|
|
|
|
class Subject(models.Model):
|
|
|
"""学科"""
|
|
|
- no = models.AutoField(primary_key=True, verbose_name='编号')
|
|
|
- name = models.CharField(max_length=31, verbose_name='名称')
|
|
|
- intro = models.CharField(max_length=511, verbose_name='介绍')
|
|
|
+ no = models.IntegerField(primary_key=True, verbose_name='编号')
|
|
|
+ name = models.CharField(max_length=20, verbose_name='名称')
|
|
|
+ intro = models.CharField(max_length=511, default='', verbose_name='介绍')
|
|
|
+ create_date = models.DateField(null=True, verbose_name='成立日期')
|
|
|
+ is_hot = models.BooleanField(default=False, verbose_name='是否热门')
|
|
|
|
|
|
def __str__(self):
|
|
|
return self.name
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'tb_subject'
|
|
|
+ verbose_name = '学科'
|
|
|
verbose_name_plural = '学科'
|
|
|
|
|
|
|
|
|
class Teacher(models.Model):
|
|
|
"""老师"""
|
|
|
no = models.AutoField(primary_key=True, verbose_name='编号')
|
|
|
- name = models.CharField(max_length=15, verbose_name='姓名')
|
|
|
- gender = models.BooleanField(default=True, choices=((True, '男'), (False, '女')), verbose_name='性别')
|
|
|
- birth = models.DateField(null=True, verbose_name='出生日期')
|
|
|
- intro = models.CharField(max_length=511, default='', verbose_name='')
|
|
|
+ name = models.CharField(max_length=20, verbose_name='姓名')
|
|
|
+ detail = models.CharField(max_length=1023, default='', blank=True, verbose_name='详情')
|
|
|
+ photo = models.CharField(max_length=1023, default='', verbose_name='照片')
|
|
|
good_count = models.IntegerField(default=0, verbose_name='好评数')
|
|
|
bad_count = models.IntegerField(default=0, verbose_name='差评数')
|
|
|
- photo = models.CharField(max_length=255, verbose_name='照片')
|
|
|
subject = models.ForeignKey(to=Subject, on_delete=models.PROTECT, db_column='sno', verbose_name='所属学科')
|
|
|
|
|
|
- def __str__(self):
|
|
|
- return self.name
|
|
|
-
|
|
|
class Meta:
|
|
|
db_table = 'tb_teacher'
|
|
|
+ verbose_name = '老师'
|
|
|
verbose_name_plural = '老师'
|
|
|
```
|
|
|
|
|
|
@@ -55,51 +54,27 @@ class Teacher(models.Model):
|
|
|
|
|
|
> 注意:为了给vote应用生成迁移文件,需要修改Django项目settings.py文件,在INSTALLED_APPS中添加vote应用。
|
|
|
|
|
|
-完成模型迁移之后,我们可以通过下面的SQL语句来添加学科和老师测试的数据。
|
|
|
-
|
|
|
-```SQL
|
|
|
-INSERT INTO `tb_subject` (`no`,`name`,`intro`)
|
|
|
-VALUES
|
|
|
-(1, 'Python全栈+人工智能', 'Python是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido van Rossum于1989年发明,第一个公开发行版发行于1991年。'),
|
|
|
-(2, 'JavaEE+分布式服务', 'Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。'),
|
|
|
-(3, 'HTML5大前端', 'HTML5 将成为 HTML、XHTML 以及 HTML DOM 的新标准。'),
|
|
|
-(4, '全栈软件测试', '在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程'),
|
|
|
-(5, '全链路UI/UE', '全链路要求设计师关注整个业务链中的每一个环节,将设计的价值融入每一个和用户的接触点中,让整个业务的用户体验质量得到几何级数的增长。');
|
|
|
-
|
|
|
-INSERT INTO `tb_teacher` (`no`,`name`,`gender`,`birth`,`intro`,`good_count`,`bad_count`,`photo`,`sno`)
|
|
|
-VALUES
|
|
|
-(1, '骆昊', 1, '1980-11-28', '10年以上软硬件产品设计、研发、架构和管理经验,2003年毕业于四川大学,四川大学Java技术俱乐部创始人,四川省优秀大学毕业生,在四川省网络通信技术重点实验室工作期间,参与了2项国家自然科学基金项目、1项中国科学院中长期研究项目和多项四川省科技攻关项目,在国际会议和国内顶级期刊上发表多篇论文(1篇被SCI收录,3篇被EI收录),大规模网络性能测量系统DMC-TS的设计者和开发者,perf-TTCN语言的发明者。国内最大程序员社区CSDN的博客专家,在Github上参与和维护了多个高质量开源项目,精通C/C++、Java、Python、R、Swift、JavaScript等编程语言,擅长OOAD、系统架构、算法设计、协议分析和网络测量,主持和参与过电子政务系统、KPI考核系统、P2P借贷平台等产品的研发,一直践行“用知识创造快乐”的教学理念,善于总结,乐于分享。', 0, 0, 'images/luohao.png', 1),
|
|
|
-(2, '王海飞', 1, '1993-05-24', '5年以上Python开发经验,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域相关服务网站担任Python高级研发工程师、项目经理等职务,擅长基于Python、Java、PHP等开发语言的企业级应用开发,全程参与了多个企业级应用从需求到上线所涉及的各种工作,精通Django、Flask等框架,熟悉基于微服务的企业级项目开发,拥有丰富的项目实战经验。善于用浅显易懂的方式在课堂上传授知识点,在授课过程中经常穿插企业开发的实际案例并分析其中的重点和难点,通过这种互动性极强的教学模式帮助学员找到解决问题的办法并提升学员的综合素质。', 0, 0, 'images/wanghaifei.png', 1),
|
|
|
-(3, '余婷', 0, '1992-03-12', '5年以上移动互联网项目开发经验和教学经验,曾担任上市游戏公司高级软件研发工程师和移动端(iOS)技术负责人,参了多个企业级应用和游戏类应用的移动端开发和后台服务器开发,拥有丰富的开发经验和项目管理经验,以个人开发者和协作开发者的身份在苹果的AppStore上发布过多款App。精通Python、C、Objective-C、Swift等开发语言,熟悉iOS原生App开发、RESTful接口设计以及基于Cocos2d-x的游戏开发。授课条理清晰、细致入微,性格活泼开朗、有较强的亲和力,教学过程注重理论和实践的结合,在学员中有良好的口碑。', 0, 0, 'images/yuting.png', 1),
|
|
|
-(4, '肖世荣', 1, '1977-07-02', '10年以上互联网和移动互联网产品设计、研发、技术架构和项目管理经验,曾在中国移动、symbio、ajinga.com、万达信息等公司担任架构师、项目经理、技术总监等职务,长期为苹果、保时捷、耐克、沃尔玛等国际客户以及国内的政府机构提供信息化服务,主导的项目曾获得“世界科技先锋”称号,个人作品“许愿吧”曾在腾讯应用市场生活类App排名前3,拥有百万级用户群体,运营的公众号“卵石坊”是国内知名的智能穿戴设备平台。精通Python、C++、Java、Ruby、JavaScript等开发语言,主导和参与了20多个企业级项目(含国家级重大项目和互联网创新项目),涉及的领域包括政务、社交、电信、卫生和金融,有极为丰富的项目实战经验。授课深入浅出、条理清晰,善于调动学员的学习热情并帮助学员理清思路和方法。', 0, 0, 'images/xiaoshirong.png', 1),
|
|
|
-(5, '张无忌', 1, '1987-07-07', '出生起便在冰火岛过着原始生活,踏入中土后因中玄冥神掌命危而带病习医,忍受寒毒煎熬七年最后因福缘际会练成“九阳神功”更在之后又练成了“乾坤大挪移”等盖世武功,几乎无敌于天下。 生性随和,宅心仁厚,精通医术和药理。20岁时便凭着盖世神功当上明教教主,率领百万教众及武林群雄反抗蒙古政权元朝的高压统治,最后推翻了元朝。由于擅长乾坤大挪移神功,上课遇到问题就转移话题。', 0, 0, 'images/zhangwuji.png', 5),
|
|
|
-(6, '韦一笑', 1, '1975-12-15', '外号“青翼蝠王”,为明教四大护教法王之一。 身披青条子白色长袍,轻功十分了得。由于在修炼至阴至寒的“寒冰绵掌”时出了差错,经脉中郁积了至寒阴毒,只要运上内力,寒毒就会发作,如果不吸人血解毒,全身血脉就会凝结成冰,后得张无忌相助,以其高明医术配以“九阳神功”,终将寒毒驱去,摆脱了吸吮人血这一命运。由于轻功绝顶,学生一问问题就跑了。', 0, 0, 'images/weiyixiao.png', 3);
|
|
|
-```
|
|
|
-
|
|
|
-当然也可以直接使用Django提供的后台管理应用来添加学科和老师信息,这需要先注册模型类和模型管理类。
|
|
|
+完成模型迁移之后,我们可以直接使用Django提供的后台管理来添加学科和老师信息,这需要先注册模型类和模型管理类。
|
|
|
|
|
|
```SQL
|
|
|
from django.contrib import admin
|
|
|
-from django.contrib.admin import ModelAdmin
|
|
|
|
|
|
-from vote.models import Teacher, Subject
|
|
|
+from poll2.forms import UserForm
|
|
|
+from poll2.models import Subject, Teacher
|
|
|
|
|
|
|
|
|
-class SubjectModelAdmin(ModelAdmin):
|
|
|
- """学科模型管理"""
|
|
|
- list_display = ('no', 'name')
|
|
|
+class SubjectAdmin(admin.ModelAdmin):
|
|
|
+ list_display = ('no', 'name', 'create_date', 'is_hot')
|
|
|
ordering = ('no', )
|
|
|
|
|
|
|
|
|
-class TeacherModelAdmin(ModelAdmin):
|
|
|
- """老师模型管理"""
|
|
|
- list_display = ('no', 'name', 'gender', 'birth', 'good_count', 'bad_count', 'subject')
|
|
|
- ordering = ('no', )
|
|
|
- search_fields = ('name', )
|
|
|
+class TeacherAdmin(admin.ModelAdmin):
|
|
|
+ list_display = ('no', 'name', 'detail', 'good_count', 'bad_count', 'subject')
|
|
|
+ ordering = ('subject', 'no')
|
|
|
|
|
|
|
|
|
-admin.site.register(Subject, SubjectModelAdmin)
|
|
|
-admin.site.register(Teacher, TeacherModelAdmin)
|
|
|
+admin.site.register(Subject, SubjectAdmin)
|
|
|
+admin.site.register(Teacher, TeacherAdmin)
|
|
|
```
|
|
|
|
|
|
接下来,我们就可以修改views.py文件,通过编写视图函数先实现“学科介绍”页面。
|
|
|
@@ -118,24 +93,23 @@ def show_subjects(request):
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
- <title>学科信息</title>
|
|
|
+ <title>所有学科信息</title>
|
|
|
<style>/* 此处略去了层叠样式表的选择器 */</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
- <h1>千锋互联所有学科信息</h1>
|
|
|
+ <h1>所有学科</h1>
|
|
|
<hr>
|
|
|
- <div id="container">
|
|
|
- {% for subject in subjects %}
|
|
|
- <dl>
|
|
|
- <dt>
|
|
|
- <a href="/teachers?sno={{ subject.no }}">
|
|
|
- {{ subject.name }}
|
|
|
- </a>
|
|
|
- </dt>
|
|
|
- <dd>{{ subject.intro }}</dd>
|
|
|
- </dl>
|
|
|
- {% endfor %}
|
|
|
+ {% for subject in subjects %}
|
|
|
+ <div>
|
|
|
+ <h3>
|
|
|
+ <a href="/teachers/?sno={{ subject.no }}">{{ subject.name }}</a>
|
|
|
+ {% if subject.is_hot %}
|
|
|
+ <img src="/static/images/hot.png" width="32" alt="">
|
|
|
+ {% endif %}
|
|
|
+ </h3>
|
|
|
+ <p>{{ subject.intro }}</p>
|
|
|
</div>
|
|
|
+ {% endfor %}
|
|
|
</body>
|
|
|
</html>
|
|
|
```
|
|
|
@@ -144,13 +118,12 @@ def show_subjects(request):
|
|
|
|
|
|
```Python
|
|
|
def show_teachers(request):
|
|
|
- """查看指定学科的老师"""
|
|
|
+ """显示指定学科的老师"""
|
|
|
try:
|
|
|
sno = int(request.GET['sno'])
|
|
|
subject = Subject.objects.get(no=sno)
|
|
|
- teachers = Teacher.objects.filter(subject__no=sno)
|
|
|
- context = {'subject': subject, 'teachers': teachers}
|
|
|
- return render(request, 'teacher.html', context)
|
|
|
+ teachers = subject.teacher_set.all()
|
|
|
+ return render(request, 'teachers.html', {'subject': subject, 'teachers': teachers})
|
|
|
except (KeyError, ValueError, Subject.DoesNotExist):
|
|
|
return redirect('/')
|
|
|
```
|
|
|
@@ -163,40 +136,36 @@ def show_teachers(request):
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
- <title>老师信息</title>
|
|
|
+ <title>老师</title>
|
|
|
<style>/* 此处略去了层叠样式表的选择器 */</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<h1>{{ subject.name }}学科老师信息</h1>
|
|
|
<hr>
|
|
|
{% if teachers %}
|
|
|
- <div id="container">
|
|
|
- {% for teacher in teachers %}
|
|
|
- <div class="teacher">
|
|
|
- <div class="photo">
|
|
|
- <img src="{% static teacher.photo %}" height="140" alt="">
|
|
|
- </div>
|
|
|
- <div class="info">
|
|
|
- <div>
|
|
|
- <span><strong>姓名:{{ teacher.name }}</strong></span>
|
|
|
- <span>性别:{{ teacher.gender | yesno:'男,女' }}</span>
|
|
|
- <span>出生日期:{{ teacher.birth }}</span>
|
|
|
- </div>
|
|
|
- <div class="intro">{{ teacher.intro }}</div>
|
|
|
- <div class="comment">
|
|
|
- <a href="">好评({{ teacher.good_count }})</a>
|
|
|
- <a href="">差评({{ teacher.bad_count }})</a>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ {% for teacher in teachers %}
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <img src="{% static teacher.photo %}" alt="">
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h3>{{ teacher.name }}</h3>
|
|
|
+ <p>{{ teacher.detail }}</p>
|
|
|
+ <p class="comment">
|
|
|
+ <a href="">好评</a>
|
|
|
+ (<span>{{ teacher.good_count }}</span>)
|
|
|
+ <a href="">差评</a>
|
|
|
+ (<span>{{ teacher.bad_count }}</span>)
|
|
|
+ </p>
|
|
|
</div>
|
|
|
- {% endfor %}
|
|
|
</div>
|
|
|
+ {% endfor %}
|
|
|
{% else %}
|
|
|
- <h2>暂时没有该学科的老师信息</h2>
|
|
|
+ <h3>暂时没有该学科的老师信息</h3>
|
|
|
{% endif %}
|
|
|
- <div class="back">
|
|
|
- <a href="/"><< 返回学科</a>
|
|
|
- </div>
|
|
|
+ <p>
|
|
|
+ <a href="/">返回首页</a>
|
|
|
+ </p>
|
|
|
</body>
|
|
|
</html>
|
|
|
```
|
|
|
@@ -231,11 +200,11 @@ urlpatterns = [
|
|
|
|
|
|
启动服务器运行项目,进入首页查看学科信息。
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
点击学科查看老师信息。
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
### Ajax请求
|
|
|
|
|
|
@@ -285,48 +254,50 @@ def praise_or_criticize(request):
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
- <title>老师信息</title>
|
|
|
- <style>/* 此处略去了层叠样式表的选择器 */</style>
|
|
|
+ <title>老师</title>
|
|
|
+ <style>/* 此处略去了层叠样式表的选择器 */</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
- <h1>{{ subject.name }}的老师信息</h1>
|
|
|
+ <h1>{{ subject.name }}学科老师信息</h1>
|
|
|
<hr>
|
|
|
- <div id="container">
|
|
|
- {% for teacher in teachers %}
|
|
|
- <div class="teacher">
|
|
|
- <div class="photo">
|
|
|
- <img src="{% static teacher.photo %}" height="140" alt="">
|
|
|
- </div>
|
|
|
- <div class="info">
|
|
|
- <div>
|
|
|
- <span><strong>姓名:{{ teacher.name }}</strong></span>
|
|
|
- <span>性别:{{ teacher.gender | yesno:'男,女' }}</span>
|
|
|
- <span>出生日期:{{ teacher.birth }}</span>
|
|
|
- </div>
|
|
|
- <div class="intro">{{ teacher.intro }}</div>
|
|
|
- <div class="comment">
|
|
|
- <a href="/vote/praise/?tno={{ teacher.no }}">好评</a>
|
|
|
- (<span>{{ teacher.good_count }}</span>)
|
|
|
-
|
|
|
- <a href="/vote/criticize/?tno={{ teacher.no }}">差评</a>
|
|
|
- (<span>{{ teacher.bad_count }}</span>)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ {% if teachers %}
|
|
|
+ {% for teacher in teachers %}
|
|
|
+ <div class="teacher">
|
|
|
+ <div class="photo">
|
|
|
+ <img src="{% static teacher.photo %}" height="140" alt="">
|
|
|
+ </div>
|
|
|
+ <div class="info">
|
|
|
+ <h3>{{ teacher.name }}</h3>
|
|
|
+ <p>{{ teacher.detail }}</p>
|
|
|
+ <p class="comment">
|
|
|
+ <a href="/praise/?tno={{ teacher.no }}">好评</a>
|
|
|
+ (<span>{{ teacher.good_count }}</span>)
|
|
|
+
|
|
|
+ <a href="/criticize/?tno={{ teacher.no }}">差评</a>
|
|
|
+ (<span>{{ teacher.bad_count }}</span>)
|
|
|
+ </p>
|
|
|
</div>
|
|
|
- {% endfor %}
|
|
|
</div>
|
|
|
- <script src="{% static 'js/jquery.min.js' %}"></script>
|
|
|
+ {% endfor %}
|
|
|
+ {% else %}
|
|
|
+ <h3>暂时没有该学科的老师信息</h3>
|
|
|
+ {% endif %}
|
|
|
+ <p>
|
|
|
+ <a href="/">返回首页</a>
|
|
|
+ </p>
|
|
|
+ <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
|
|
|
<script>
|
|
|
$(() => {
|
|
|
- $('.comment > a').on('click', (evt) => {
|
|
|
+ $('.comment>a').on('click', (evt) => {
|
|
|
evt.preventDefault()
|
|
|
- let a = $(evt.target)
|
|
|
- $.getJSON(a.attr('href'), (json) => {
|
|
|
- if (json.code == 200) {
|
|
|
- let span = a.next()
|
|
|
+ let anchor = $(evt.target)
|
|
|
+ let url = anchor.attr('href')
|
|
|
+ $.getJSON(url, (json) => {
|
|
|
+ if (json.code == 10001) {
|
|
|
+ let span = anchor.next()
|
|
|
span.text(parseInt(span.text()) + 1)
|
|
|
} else {
|
|
|
- alert(json.message)
|
|
|
+ alert(json.hint)
|
|
|
}
|
|
|
})
|
|
|
})
|