基于前面两个章节讲解的知识,我们已经可以利用Django框架来实现Web运用的开拓了。接下来我们就考试测验实现一个投票运用,详细的需求是用户进入系统首先来到“登录页”;登录成功后可以查看到“学科先容”页面,该页面显示了一个学校所开设的所有学科;通过点击某个学科,可以进入“讲师详情”页面,该页面展示了该学科所有讲师的详细情形,可以在该页面上给讲师点击“好评”或“差评”;对付未注册的用户,可以在登录页点击“新用户注册”进入“注书页”完成用户注册,注册成功或失落败都会得到相应的提示信息,注册成功后会返回“登录页”。
准备事情
由于之前已经详细的讲解了如何创建Django项目以及项目的干系配置,因此我们略过这部分内容,唯一须要解释的是,我们将项目命名为hellodjango,在项眼前创建了一个名为demo的运用。从“学科先容”和“讲师详情”页面的需求,我们可以首先剖析出两个业务实体,一个是学科,一个是讲师,二者之前是一对多关联。因此,我们首先修正运用demo下的models.py文件来定义数据模型。

from django.db import modelsfrom django.db.models import PROTECTclass Subject(models.Model): no = models.AutoField(primary_key=True, db_column='sno', verbose_name='编号') name = models.CharField(max_length=50, db_column='sname', verbose_name='学科名称') intro = models.CharField(max_length=511, db_column='sintro', verbose_name='学科先容') def __str__(self): return self.name class Meta(object): db_table = 'tb_subject' verbose_name = '学科' verbose_name_plural = '学科'class Teacher(models.Model): no = models.AutoField(primary_key=True, db_column='tno', verbose_name='编号') name = models.CharField(max_length=20, db_column='tname', verbose_name='姓名') intro = models.CharField(max_length=1023, db_column='tintro', verbose_name='简介') motto = models.CharField(max_length=255, db_column='tmotto', verbose_name='传授教化理念') photo = models.CharField(max_length=511, db_column='tphoto', verbose_name='照片', null=True, blank=True) subject = models.ForeignKey(Subject, db_column='sno', on_delete=PROTECT, related_name='+', verbose_name='所属学科') manager = models.BooleanField(default=False, db_column='tmanager', verbose_name='是否主管') good_count = models.IntegerField(default=0, db_column='tgcount', verbose_name='好评数') bad_count = models.IntegerField(default=0, db_column='tbcount', verbose_name='差评数') @property def gcount(self): return f'{self.good_count}' \ if self.good_count <= 999 else '999+' @property def bcount(self): return f'{self.bad_count}' \ if self.bad_count <= 999 else '999+' class Meta(object): db_table = 'tb_teacher' verbose_name = '讲师' verbose_name_plural = '讲师'
模型定义完成后,可以通过“天生迁移”和“实行迁移”来完成关系型数据库中二维表的创建,当然这须要提前启动数据库做事器并创建好对应的数据库,同时我们在项目中已经安装了PyMySQL而且完成了相应的配置,这些内容此处不再赘述。
(venv)$ python manage.py makemigrations demo...(venv)$ python manage.py migrate...
完成模型迁移之后,我们可以通过下面的SQL语句来添加学科和讲师的数据。
INSERT INTO `tb_subject` (`sname`, `sintro`)VALUES('Python传授教化部', 'Python是一种面向工具的阐明型打算机程序设计措辞,由荷兰人Guido van Rossum于1989年发明,第一个公开拓行版发行于1991年。' ),('JavaEE传授教化部', 'Java是一门面向工具编程措辞,不仅接管了C++措辞的各种优点,还摒弃了C++里难以理解的多继续、指针等观点,因此Java措辞具有功能强大和大略易用两个特色。' ),('HTML5传授教化部', 'HTML5 将成为 HTML、XHTML 以及 HTML DOM 的新标准。' );INSERT INTO `tb_teacher` (`tname`, `tintro`, `tmotto`, `tphoto`, `tmanager`, `sno`)VALUES('骆昊', '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借贷平台等产品的研发,一贯践行“用知识创造快乐”的传授教化理念,长于总结,乐于分享。', '教诲是让受教诲者体会用知识创造快乐的过程', 'images/ken.png', 1, 1),('余小美', '5年以上移动互联网项目开拓履历和传授教化履历,曾担当上市游戏公司高等软件研发工程师和移动端(iOS)技能卖力人,参了多个企业级运用和游戏类运用的移动端开拓和后台做事器开拓,拥有丰富的开拓履历和项目管理履历,以个人开拓者和协作开拓者的身份在苹果的AppStore上发布过多款App。精通Python、C、Objective-C、Swift等开拓措辞,熟习iOS原生App开拓、RESTful接口设计以及基于Cocos2d-x的游戏开拓。授课条理清晰、细致入微,性情活泼爽朗、有较强的亲和力,传授教化过程看重理论和实践的结合,在学员中有良好的口碑。', '每天叫醒你的不是闹钟而是梦想', 'images/linus.png', 0, 1),('肖小帅', '10年以上互联网和移动互联网产品设计、研发、技能架构和项目管理履历,曾在中国移动、symbio、ajinga.com、万达信息等公司担当架构师、项目经理、技能总监等职务,长期为苹果、保时捷、耐克、沃尔玛等国际客户以及海内确当局机构供应信息化做事,主导的项目曾得到“天下科技先锋”称号,个人作品“许愿吧”曾在腾讯运用市场生活类App排名前3,拥有百万级用户群体,运营的"大众年夜众号“卵石坊”是海内有名的智能穿着设备平台。精通Python、C++、Java、Ruby、JavaScript等开拓措辞,主导和参与了20多个企业级项目(含国家级重大项目和互联网创新项目),涉及的领域包括政务、社交、电信、卫生和金融,有极为丰富的项目实战履历。授课深入浅出、条理清晰,长于调动学员的学习激情亲切并帮助学员理清思路和方法。', '世上没有绝望的处境,只有对处境绝望的人', 'images/dennis.png', 0, 1),('王大帅', '5年以上Python开拓履历,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域干系做事网站担当Python高等研发工程师、项目经理等职务,善于基于Python、Java、PHP等开拓措辞的企业级运用开拓,全程参与了多个企业级运用从需求到上线所涉及的各种事情,精通Django、Flask等框架,熟习基于微做事的企业级项目开拓,拥有丰富的项目实战履历。长于用浅近易懂的办法在教室上传授知识点,在授课过程中常常穿插企业开拓的实际案例并剖析个中的重点和难点,通过这种互动性极强的传授教化模式帮助学员找到办理问题的办法并提升学员的综合本色。', '不要给我说什么底层事理、框架内核!
老夫敲代码便是一把梭!
复制!
黏贴!
拿起键盘便是干!
', NULL, 0, 1),('何大富', '5年以上JavaEE项目开拓和传授教化履历,参与过人力资源管理系统、电子教诲产品在线商城、安然好年夜夫App、安然好车主App等项目的设计与研发。善于Java措辞、面向工具编程、JavaEE框架、Web前端开拓、数据库编程和Android运用开拓,对新技能有着浓厚的兴趣和研讨精神,对微做事架构、虚拟化技能、区块链、边缘打算等领域都有自己独到的认识和见地,有丰富的项目履历和传授教化履历。授课时看重学习方法的勾引,提倡以项目为导向的实战型传授教化,同时也看重根本知识的节制和底层事理的理解,教室氛围轻松诙谐,能够把呆板乏味的知识变成生动有趣的案例,帮助学员更快更好的节制技能的办法,从事JavaEE传授教化事情以来,得到了学生潮水般的好评。', '每天撸代码,生活乐无边!
', 'images/andrew.png', 0, 2),('吴小富', '毕业于西南交通大学,高等软件研发工程师,10年以上的开拓和培训履历。曾就职于华为赛门铁克科技有限公司,卖力公司内部ERP系统的研发,参与和主导过多个大型门户网站、电子商务网站、电子政务系统以及多个企业级Web项目的设计和开拓,同时卖力过多门企业内训课程的研发与讲授,有着非常丰富的JavaEE项目开拓履历和Web前端开拓履历,精通C/C++、Java、PHP、JavaScript等开拓措辞,能够利用多种技能进行全栈开拓。授课履历丰富、思路清晰、富有激情,对知识点的讲解由浅入深、深入浅出,能够通过实际开拓的场景勾引学员思考业务并理解干系技能,长于将多年的项目实战履历和企业内训履历融入教室,通过理论联系实际的办法帮助学员迅速提升就业能力。', '人生的道路在态度的岔口一分为二', NULL, 1, 3);
接下来,我们就可以修正views.py文件,通过编写视图函数先实现“学科先容”页面。
def show_subjects(request): ctx = {'subjects_list': Subject.objects.all()} return render(request, 'demo/subject.html', ctx)
至此,我们还须要一个模板页,模板的配置以及模板页中模板措辞的用法在之前已经进行过简要的先容,如果不熟习可以看看下面的代码,相信学会编写模板页并闇练的利用模板措辞并不是一件困难的事情。
<!DOCTYPE html><html lang=\"大众en\"大众><head> <meta charset=\公众UTF-8\公众> <title>学科信息</title> <style> body { width: 960px; margin: 0 auto; } .sub { margin: 20px 10px; } </style></head><body> <h1>学科信息</h1> <hr> {% for subject in subjects_list %} <dl class=\"大众sub\公众> <dt><a href=\公众/subjects/{{ subject.no }}\"大众>{{ subject.name }}</a></dt> <dd>{{ subject.intro }}</dd> </dl> {% endfor %}</body></html>
启动做事器,运行效果如下图所示。
加载静态资源
在上面的模板中,我们为每个学科添加了一个超链接,点击超链接可以查看该学科的讲师信息,为此我们得修正项目的urls.py文件配置一个新的URL。
from django.contrib import adminfrom django.urls import pathfrom demo import viewsurlpatterns = [ path('', views.show_subjects), path('subjects/<int:no>', views.show_teachers), path('admin/', admin.site.urls),]
Django 2.x在配置URL时可以利用如上面所示的占位符语法,而且可以指定占位符的类型,由于在查询学科讲师信息时,须要传入该学科的编号作为条件,而学科编号在定义模型时设定为AutoField,实在质便是int类型。相较于Django 1.x中利用正则表达式的命名捕获组来从URL中获取数据(如果对Django 1.x并没有什么观点,这句话可以暂时忽略不计),这种更加优雅的写法可以让我们在视图函数中直接得到学科编号,代码如下所示。
def show_teachers(request, no): teachers = Teacher.objects.filter(subject__no=no) ctx = {'teachers_list': teachers} return render(request, 'demo/teacher.html', ctx)
接下来我们可以定制“讲师详情”的模板页。
<!DOCTYPE html>{% load staticfiles %}<html lang=\"大众en\"大众><head> <meta charset=\"大众UTF-8\"大众> <title>讲师信息</title> <style> .container { width: 960px; margin: 0 auto; } .basic { width: 60%; float: left; } .potrait { width: 40%; float: left; text-align: right; } hr { clear: both; } .button { display: inline-block; width: 80px; height: 30px; background-color: red; color: white; font: 16px/30px Arial; text-decoration: none; text-align: center; margin-bottom: 10px;} </style></head><body> {% for x in teachers_list %} <div class=\公众container\"大众> <div class=\"大众basic\"大众> <h1>{{ x.name }}老师</h1> <p><strong>讲师简介</strong></p> <p>{{ x.intro }}</p> <p><strong>传授教化理念</strong></p> <p>{{ x.motto }}</p> <a href=\公众/good/{{ x.no }}\"大众 class=\公众button\"大众>好评({{ x.gcount }})</a> <a href=\公众/bad/{{ x.no }}\"大众 class=\公众button\公众>差评({{ x.bcount }})</a> </div> <div class=\"大众potrait\公众> {% if x.photo %} <img src=\"大众{% static x.photo %}\公众> {% endif %} </div> <hr> </div> {% endfor %}</body></html>
请把稳上面的模板页面,我们在第2行和<img>标签中利用了加载静态资源的模板指令,通过加载静态资源的指令我们可以显示讲师的头像。当然,我们还得创建放置静态资源的文件夹并在项目的配置文件中指明静态资源文件夹的所在以及静态资源的URL。
(venv)$ mkdir static(venv)$ cd static(venv)$ mkdir css js images
首先在项目根目录下创建static文件,再进入static目录,创建css、js和images三个文件夹,分别用来放置层叠样式表、JavaScript文件和图片资源。
# 此处省略上面的代码STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]STATIC_URL = '/static/'# 此处省略下面的代码
Ajax要求
接下来就可以实现“好评”和“差评”的功能了,很明显如果能够在不刷新页面的情形下实现这两个功能会带来更好的用户体验,因此我们考虑利用Ajax来实现“好评”和“差评”。
首先修正项目的urls.py文件,为“好评”和“差评”功能映射对应的URL,跟上面一样我们在URL中利用了占位符语法来绑定讲师的编号。
from django.contrib import adminfrom django.urls import pathfrom demo import viewsurlpatterns = [ path('', views.login), path('subjects/', views.show_subjects), path('subjects/<int:no>/', views.show_teachers), path('good/<int:no>/', views.make_comment), path('bad/<int:no>/', views.make_comment), path('admin/', admin.site.urls),]
设计视图函数make_comment来支持“好评”和“差评”功能,可以通过json模块的dumps函数实现将字典转成JSON字符串并作为HttpResponse返回给浏览器的内容。在创建HttpResponse工具时,可以通过content_type参数来指定相应的MIME类型为JSON且利用UTF-8编码(避免JSON字符串中的中文涌现乱码)。
def make_comment(request, no): ctx = {'code': 200} try: teacher = Teacher.objects.get(pk=no) if request.path.startswith('/good'): teacher.good_count += 1 ctx['result'] = f'好评({teacher.gcount})' else: teacher.bad_count += 1 ctx['result'] = f'差评({teacher.bcount})' teacher.save() except Teacher.DoesNotExist: ctx['code'] = 404 return HttpResponse(json.dumps(ctx), content_type='application/json; charset=utf-8')
修正模板页引入jQuery库来实现事宜处理、Ajax要乞降DOM操作。
<!DOCTYPE html>{% load staticfiles %}<html lang=\"大众en\"大众><head> <meta charset=\公众UTF-8\公众> <title>讲师信息</title> <style> .container { width: 960px; margin: 0 auto; } .basic { width: 60%; float: left; } .potrait { width: 40%; float: left; text-align: right; } hr { clear: both; } .button { display: inline-block; width: 80px; height: 30px; background-color: red; color: white; font: 16px/30px Arial; text-decoration: none; text-align: center; margin-bottom: 10px; } </style></head><body> {% for x in teachers_list %} <div class=\公众container\公众> <div class=\"大众basic\"大众> <h1>{{ x.name }}老师</h1> <p><strong>讲师简介</strong></p> <p>{{ x.intro }}</p> <p><strong>传授教化理念</strong></p> <p>{{ x.motto }}</p> <a href=\"大众/good/{{ x.no }}\公众 class=\公众button\"大众>好评({{ x.gcount }})</a> <a href=\"大众/bad/{{ x.no }}\"大众 class=\"大众button\公众>差评({{ x.bcount }})</a> </div> <div class=\"大众potrait\公众> {% if x.photo %} <img src=\"大众{% static x.photo %}\公众> {% endif %} </div> <hr> </div> {% endfor %} <script src=\"大众{% static 'js/jquery.min.js' %}\"大众></script> <script> $(function() { $('.basic .button').on('click', function(evt) { evt.preventDefault(); var $a = $(evt.target); var url = $a.attr('href'); $.ajax({ 'url': url, 'type': 'get', 'dataType': 'json', 'success': function(json) { if (json.code == 200) { $a.text(json.result); } } }); }); }); </script></body></html>
小结
到此,这个小项目的核心功能已然完成,不才一个章节中我们会增加用户登录和注册的功能,稍后我们还会限定登录后的用户才能进行投票操作,而且每个用户只能投出3票。