python:django API、视图、模板和表单使用

注:续上一篇博客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次
在这里插入图片描述
自动跳到投票结果详情页
在这里插入图片描述
至此一个简单的投票系统就搞定啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值