注:续上一篇博客python:django部署《python:django部署》
在python shell中运行指令
(djenv) [root@room9pc01 mysite]# python manage.py shell
Python 3.6.7 (default, May 20 2019, 13:24:03)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
- 使用上述命令而不是简单地键入“python”进入python环境
- 因为manage.py 设置了DJANGO_SETTINGS_MODULE 环境变量,该环境
变量告诉Django导入mysite/settings.py文件的路径
导入前面编写的模型
>>> from polls.models import Question, Choice
创建问题实例
>>> q1 = Question(question_text='你期待哪家公司给你发offer?', pub_date='2019-05-27 9:00:00')
>>> q1.save()
使用objects管理器
django为每一个ORM类都创建了名为objects的管理器,可以通过这个管理器的方法实现对表的管理。
>>> q2 = Question.objects.create(question_text='从学校毕业后,你希望去哪个城市工作?', pub_date='2019-06-01 12:00:00')
创建选项实例
c1 = Choice(choice_text='腾讯', question=q1) //由于存在外键关系,django通过Question对象可以反向得到Choice对象集
>>> c1.save()
使用管理器创建选项实例
>>> c2 = Choice.objects.create(choice_text='华为', question=q1)
通过问题实例的管理器创建选项
问题和选项有主外键约束,这是一对多的关系,即一个问题可以有多个选项。每个问题的实例都有一个xxx_set管理器。问题的选项是Choice,那么管理器就是choice_set,如果选项的类名是XuanXiang,那么管理器的名称是xuanxiang_set。
>>> c3 = q1.choice_set.create(choice_text='阿里巴巴')
删除选项
>>> c3.delete()
修改问题
>>> q2.question_text = '从学校毕业后,你打算去哪个城市工作?'
>>> q2.save()
查询所有问题
>>> Question.objects.all()
<QuerySet [<Question: 问题: 从大学毕业后,你期望的新水是多少?>, <Question: 问题: 放假后打算去哪里玩?>, <Question: 问题: 你期待哪家公司给你发offer?>, <Question: 问题: 从学校毕业后,你打算去哪个城市工作?>]>
#########################################################################
Question.objects.all() //查询所有问题
>>> for q in Question.objects.all():
... print(q.pub_date)
...
2019-05-25 17:29:00
2019-06-07 12:00:00
2019-05-27 09:00:00
2019-06-01 12:00:00
>>> Question.objects.order_by('pub_date')
>>> for q in Question.objects.order_by('pub_date'): //根据发布时间升序排列
... print(q.pub_date)
...
2019-05-25 17:29:00
2019-05-27 09:00:00
2019-06-01 12:00:00
2019-06-07 12:00:00
>>> for q in Question.objects.order_by('pub_date'):
... print(q.pub_date, q.question_text)
...
2019-05-25 17:29:00 从大学毕业后,你期望的新水是多少?
2019-05-27 09:00:00 你期待哪家公司给你发offer?
2019-06-01 12:00:00 从学校毕业后,你打算去哪个城市工作?
2019-06-07 12:00:00 放假后打算去哪里玩?
>>> for q in Question.objects.order_by('-pub_date'): //根据发布时间降序排列
... print(q.pub_date, q.question_text)
...
2019-06-07 12:00:00 放假后打算去哪里玩?
2019-06-01 12:00:00 从学校毕业后,你打算去哪个城市工作?
2019-05-27 09:00:00 你期待哪家公司给你发offer?
2019-05-25 17:29:00 从大学毕业后,你期望的新水是多少?
获取某一个问题的实例
get必须得到一个实例,否则报错
>>> Question.objects.get(id=1) //返回1号问题
<Question: 问题: 从大学毕业后,你期望的新水是多少?>
>>> Question.objects.get(id=10) //如果不存在,则报错
>>> Question.objects.get(id__gt=1) //id>1的问题,不止一项,报错
获取多个实例
filter可以得到0到多个实例的集合
>>> Question.objects.filter(id=1) //具有一项的查询集
<QuerySet [<Question: 问题: 从大学毕业后,你期望的新水是多少?>]>
>>> Question.objects.filter(id=10) //查询集为空
<QuerySet []>
>>> Question.objects.filter(id__gt=1) //查询集有多项
<QuerySet [<Question: 问题: 放假后打算去哪里玩?>, <Question: 问题: 你期待哪家公司给你发offer?>, <Question: 问题: 从学校毕业后,你打算去哪个城市工作?>]>
查询条件
查询条件采用的形式是“属性__操作符=值”,id=1实际上是id_exact=1的简写
>>> Question.objects.filter(id__exact=1) //等于1
>>> Question.objects.filter(id__gt=1) //大于1
>>> Question.objects.filter(id__gte=1) //大于等于1
>>> Question.objects.filter(id__lt=1) //小于1
>>> Question.objects.filter(id__lte=1) //小于等于1
其他属性与数值属性类似,也是使用__
>>> Question.objects.filter(question_text__startswith='从学校')
<QuerySet [<Question: 问题: 从学校毕业后,你打算去哪个城市工作?>]>
>>> Question.objects.filter(pub_date__month=5)
<QuerySet [<Question: 问题: 从大学毕业后,你期望的新水是多少?>, <Question: 问题: 你期待哪家公司给你发offer?>]>
视图基础
• 在Django中,网页的页面和其他内容都是由视图来传递的(视图对WEB请求进行回应)
• 每个视图都是由一个简单的Python函数(或者是基于类的视图的方法)表示的
• Django通过检查请求的URL(准确地说,是URL里域名之后的那部分)来选择使用哪个视图
编写URLCONF
• 将视图和polls.urls模块关联
• 当客户端向你的网站请求一个页面 ( 例如“/polls/34/”)时,Django将加载mysite.urls
Python模块
• 因为它被指向ROOT_URLCONF设置, 它寻找名为urlpatterns 的变量并按顺序匹配其中的正则表达式
•在‘^polls/’找到匹配后,它将取消匹配的文本(“polls/”),并发送剩余的文本 ( “34/” )
到’polls.urls’URLconf进行进一步处理
模板概述
• 前面的例子,HTML是硬编码在python代码中的。这会带来不少问题:
– 任何页面的改动会牵扯到Python代码的改动
– 写后台Python代码与设计HTML是不同的工作,更专业的Web开发应该将两者分开
– 程序员写Python代码同时页面设计者写HTML模板会更高效,而不是一个人等待另一个人编辑同样的文件
• 为了解决硬码的这些问题,可以模板:
– 网站的设计改动会比Python代码改动更频繁,所以如果我们将两者分离开会更方便
– 页面设计者和HTML/CSS程序员不应该编辑Python代码,他们应该与HTML打交道
– 使用Django的模板系统分离设计和Python代码会更干净更易维护
创建模板工作目录
• 默认的设置文件settings.py配置了一个DjangoTemplates后端,其中将APP_DIRS选项设置为True
• DjangoTemplates在 INSTALLED_APPS所包含的每个应用的目录下查找名为"templates"子目录
• 模板应该位于polls/templates/polls/目录下
• 当模板系统遇到变量名里有小数点时会按以下顺序查找:
– 字典查找,如foo[“bar”]
– 属性查找,如foo.bar
– 方法调用,如foo.bar()
– 列表的索引查找,如foo[bar]
• 模板中可以使用的元素有:
– 变量,使用 {{ variable }} 的格式
– 标签/指令,使用 {% … %}的格式
– 字符串:{ } 之外的任何东西,都当做字符串处理
表单说明
• 在detail网页模板中,我们为Question对应的每个Choice都添加了一个单选按钮用于选择。 每个单选按钮的value属性是对应的各个Choice的ID。
• 每个单选按钮的name是“choice”。 这意味着,当选择一个单选按钮并提交表单提交时,它将发送一个POST数据choice=#,其中#为选择的Choice的ID
• 由于我们创建一个POST表单(它具有修改数据的作用),所以我们需要小心跨站点请求伪造
• Django已经拥有一个用来防御它的非常容易使用的系统
•简而言之,所有针对内部URL的POST表单都应该使用{% csrf_token %}模板标签
投票视图说明
• request.POST 是一个类似字典的对象,可以通过关键字的名字获取提交的数据
• request.POST[‘choice’] 以字符串形式返回选择的Choice的ID。request.POST 的值永远是字符串
• 如果在POST数据中没有提供request.POST[‘choice’],choice将引发一个KeyError
##################################################################
完善投票首页
修改视图函数,取出所有问题
pycharm设置:右击外层mysite—>Mark Directory as—>Sources Root
# polls/views.py
from django.shortcuts import render
from polls.models import Question //导入模块
# Create your views here.
def index(request):
questions = Question.objects.order_by('-pub_date')
return render(request, 'index.html', {'questions': questions}) //修改首页返回内容
def detail(request, question_id):
return render(request, 'detail.html', {'qid': question_id})
def result(request, question_id):
return render(request, 'result.html', {'qid': question_id})
修改首页模板,显示所有问题
# templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>投票首页</title>
</head>
<body>
<div class="container">
<h1>投票首页</h1>
<div>
<ol>
{% for question in questions %}
<li>
<a href="">{{ question.question_text }}</a>
{{ question.pub_date }}
</li>
{% endfor %}
</ol>
</div>
</div>
</body>
</html>
说明:{{var}}表示变量,{% %}是模板语法标签,在{}以外的是html语法。
为首页中的超链接加上具体的url
# templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<div class="container">
<h1>投票首页</h1>
<div>
<ol>
{% for question in questions %}
<li>
<a href="http://127.0.0.1/polls/{{ question.id }}">{{ question.question_text }}</a> //添加url
{{ question.pub_date }}
</li>
{% endfor %}
</ol>
</div>
</div>
</body>
</html>
修改首页中超链接的url
# templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<div class="container">
<h1>投票首页</h1>
<div>
<ol>
{% for question in questions %}
<li>
<a href="{% url 'detail' question_id=question.id %}" target="_blank">
{{ question.question_text }}
</a>
{{ question.pub_date }}
</li>
{% endfor %}
</ol>
</div>
</div>
</body>
</html>
将网页制作用到的static目录拷贝到polls目录下
[root@room8pc16 mysite]# cp -r …/…/day16/static/ polls/
修改index.html首页,使用boostrap
# templates/index.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> //适应屏幕
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}"> //调用css
</head>
<body>
<div class="container">
<div id="linux-carousel" class="carousel slide"> //添加轮播图部分
<ol class="carousel-indicators">
<li class="active" data-target="#linux-carousel" data-slide-to="0"></li>
<li data-target="#linux-carousel" data-slide-to="1"></li>
<li data-target="#linux-carousel" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="item active">
<a href="http://www.sogou.com" target="_blank">
<img src="{% static 'imgs/fj1.jpg' %}"> //轮播图1
</a>
</div>
<div class="item">
<img src="{% static 'imgs/fj2.jpg' %}"> //轮播图2
</div>
<div class="item">
<img src="{% static 'imgs/fj3.jpg' %}"> //轮播图3
</div>
</div>
<a href="#linux-carousel" data-slide="prev" class="carousel-control left">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a href="#linux-carousel" data-slide="next" class="carousel-control right">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div> //以上为轮播图部分
<h1 class="text-center text-warning">投票首页</h1>
<div class="h4">
<ol>
{% for question in questions %}
<li>
<a href="{% url 'detail' question_id=question.id %}" target="_blank">
{{ question.question_text }}
</a>
{{ question.pub_date }}
</li>
{% endfor %}
</ol>
</div>
<div class="footer text-center h3">
<a href="">星空旅游</a>
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script type="text/javascript">
$('#linux-carousel').carousel({
interval : 3000
});
</script>
</body>
</html>
首页效果图如下:
使用模板继承
- 把共性的内容,写到基础模板中
- 在基础模板添加block占位符
- 创建html页面,继承模板,将个性内容写到block中
拷贝index.html为base.html
cp index.html base.html
将base.html中的个性内容用block替代
# templates/base.html //base.html保存共性内容
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
</head>
<body>
<div class="container">
<div id="linux-carousel" class="carousel slide">
<ol class="carousel-indicators">
<li class="active" data-target="#linux-carousel" data-slide-to="0"></li>
<li data-target="#linux-carousel" data-slide-to="1"></li>
<li data-target="#linux-carousel" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="item active">
<a href="http://www.sogou.com" target="_blank">
<img src="{% static 'imgs/fj1.jpg' %}">
</a>
</div>
<div class="item">
<img src="{% static 'imgs/fj2.jpg' %}">
</div>
<div class="item">
<img src="{% static 'imgs/fj3.jpg' %}">
</div>
</div>
<a href="#linux-carousel" data-slide="prev" class="carousel-control left">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a href="#linux-carousel" data-slide="next" class="carousel-control right">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
<div>
{% block content %}{% endblock %} //index.html中个性内容用block代替
</div>
<div class="footer text-center h3">
<a href="">星空旅游</a>
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script type="text/javascript">
$('#linux-carousel').carousel({
interval : 3000
});
</script>
</body>
</html>
将index.html中的共性删除,将个性内容写到block中
# templates/index.html //index.html中保存个性内容
{% extends 'base.html' %} //扩展连接base.html中共性内容
{% load static %}
{% block title %}投票首页{% endblock %}
{% block content %}
<h1 class="text-center text-warning">投票首页</h1>
<div class="h4">
<ol>
{% for question in questions %}
<li>
<a href="{% url 'detail' question_id=question.id %}" target="_blank">
{{ question.question_text }}
</a>
{{ question.pub_date }}
</li>
{% endfor %}
</ol>
</div>
{% endblock %}
页面效果和之前一样
实现投票详情页
修改投票详情页函数
# polls/views.py
from django.shortcuts import render
from polls.models import Question
# Create your views here.
def index(request):
questions = Question.objects.order_by('-pub_date')
return render(request, 'index.html', {'questions': questions})
def detail(request, question_id): //修改投票详情页函数
question = Question.objects.get(id=question_id)
return render(request, 'detail.html', {'question': question})
def result(request, question_id):
return render(request, 'result.html', {'qid': question_id})
修改投票详情页模板文件
# templates/detail.html
{% extends 'base.html' %}
{% load static %}
{% block title %}投票详情{% endblock %}
{% block content %}
<h1 class="text-center text-warning">{{ question.id }}号问题投票详情</h1>
<h3>{{ question.question_text }}</h3>
<form action="" method="post">
{% for choice in question.choice_set.all %}
<div class="radio">
<label>
<input type="radio" name="choice_id" value="{{ choice.id }}">
{{ choice.choice_text }}
</label>
</div>
{% endfor %}
<div class="form-group">
<input class="btn btn-primary" type="submit" value="投 票">
</div>
</form>
{% endblock %}
投票详情页效果
实现投票功能
- 在投票详情页选择某一项后,投票
- 投票需要修改数据库。数据库通过调用函数进行修改
- 访问某一URL,触发函数调用
为投票函数定义URL
# polls/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
#url(正则,函数,name=该url的名字)
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>\d+)/result/$', views.result, name='result'),
url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'), //投票函数url
]
定义投票函数
# polls/views.py
from django.shortcuts import render
from polls.models import Question
from django.shortcuts import render, redirect
# Create your views here.
def index(request):
questions = Question.objects.order_by('-pub_date')
return render(request, 'index.html', {'questions': questions})
def detail(request, question_id):
question = Question.objects.get(id=question_id)
return render(request, 'detail.html', {'question': question})
def vote(request, question_id): //定义投票函数
# 取出问题
question = Question.objects.get(id=question_id)
if request.method == 'POST':
# 取出用户的选择
choice_id = request.POST.get('choice_id')
# 取出选项实例
choice = question.choice_set.get(id=choice_id)
choice.votes += 1
choice.save()
# redirect相当于打开一个新窗口,访问网址。
# 如果仍然采用render,将会把request的数据继续向result传递
return redirect('result', question_id=question_id)
def result(request, question_id):
return render(request, 'result.html', {'qid': question_id})
修改投票详情页表单的action行为
{% extends 'base.html' %}
{% load static %}
{% block title %}投票详情{% endblock %}
{% block content %}
<h1 class="text-center text-warning">{{ question.id }}号问题投票详情</h1>
<h3>{{ question.question_text }}</h3>
<form action="{% url 'vote' question_id=question.id %}" method="post"> //投票表单行为
{% csrf_token %} //防止跨站攻击
{% for choice in question.choice_set.all %}
<div class="radio">
<label>
<input type="radio" name="choice_id" value="{{ choice.id }}">
{{ choice.choice_text }}
</label>
</div>
{% endfor %}
<div class="form-group">
<input class="btn btn-primary" type="submit" value="投 票">
</div>
</form>
{% endblock %}
##################################################################
pycharm中项目mysite虚拟环境的目录结构
##################################################################
模拟客户端投票(从大学毕业后,你期望的新水是多少?选择10000+两次)
查看后端投票结果
实现投票结果页
修改函数
from django.shortcuts import render
from polls.models import Question
from django.shortcuts import render, redirect
# Create your views here.
def index(request):
questions = Question.objects.order_by('-pub_date')
return render(request, 'index.html', {'questions': questions})
def detail(request, question_id):
question = Question.objects.get(id=question_id)
return render(request, 'detail.html', {'question': question})
def vote(request, question_id):
# 取出问题
question = Question.objects.get(id=question_id)
if request.method == 'POST':
# 取出用户的选择
choice_id = request.POST.get('choice_id')
# 取出选项实例
choice = question.choice_set.get(id=choice_id)
choice.votes += 1
choice.save()
# redirect相当于打开一个新窗口,访问网址。
# 如果仍然采用render,将会把request的数据继续向result传递
return redirect('result', question_id=question_id)
def result(request, question_id): //修改投票结果页函数
question = Question.objects.get(id=question_id)
return render(request, 'result.html', {'question': question})
修改投票结果页模板
# templates/result.html
{% extends 'base.html' %}
{% load static %}
{% block title %}投票结果{% endblock %}
{% block content %}
<h1 class="text-center text-warning">{{ question.id }}号问题投票结果</h1>
<h3>{{ question.question_text }}</h3>
<table class="table table-bordered table-striped table-hover h4">
<tr class="info text-center">
<td>选项</td>
<td>票数</td>
</tr>
{% for choice in question.choice_set.all %}
<tr>
<td>{{ choice.choice_text }}</td>
<td>{{ choice.votes }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
再次投票3次
自动跳到投票结果详情页
至此一个简单的投票系统就搞定啦!