Django_通用视图(五)
参考官网的投票系统,按照综合案例的流程创建应用polls,主要模块代码如下:
test1/polls/models.py
import datetime from django.db import models
from django.utils import timezone # Create your models here. class Questions(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published') class Meta:
ordering = ['-id'] # 搜索的数据默认按id倒序排序 def __str__(self):
return self.question_text def was_published_recently(self):
now = timezone.now()
return now >= self.pub_date >= now - datetime.timedelta(days=1) class Choices(models.Model):
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
questions = models.ForeignKey(Questions, on_delete=models.CASCADE) def __str__(self):
return self.choice_text
test1/polls/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from polls.models import Questions, Choices # Create your views here. def index(request):
questions = Questions.objects.all()
return render(request, 'polls/index.html', {'title': '投票首页', 'questions': questions}) def detail(request, question_id):
question = Questions.objects.get(pk=question_id)
context = {'title': '投票选项', 'question': question}
return render(request, 'polls/detail.html', context) def result(request, question_id):
question = Questions.objects.get(pk=question_id)
return render(request, 'polls/result.html', {'title': '投票结果', 'question': question}) def vote(request, question_id):
try:
choice = get_object_or_404(Choices, pk=request.POST['choice'])
except(KeyError, Choices.DoesNotExist):
question = Questions.objects.get(pk=question_id)
context = {'title': '投票选项', 'question': question, "error_message": "请选择后提交"}
return render(request, 'polls/detail.html', context) choice.votes += 1
choice.save()
return redirect(reverse('polls:result', args=(question_id, )))
test1/polls/urls.py
from django.urls import path from . import views app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/detail', views.detail, name='detail'),
path('<int:question_id>/vote', views.vote, name='vote'),
path('<int:question_id>/result', views.result, name='result'),
]
test1/templates/polls/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>投票首页</title>
</head>
<body>
<h1>{{ title }}</h1>
{% if error_msg %}
<p>{{ error_msg }}</p>
{% endif %} <ul>
{% for question in questions %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
</body>
</html>
test1/templates/polls/detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>投票选项</title>
</head>
<body>
<h1>{{ question.question_text }}的{{ title }}</h1> <form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choices_set.all %}
<div>
<input type="radio" name="choice" id="{{ forloop.counter }}" value="{{ choice.id }}">
<label for="{{ forloop.counter }}">{{ choice.choice_text }}</label>
</div>
{% endfor %}
<button type="submit">提交</button>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
</form>
<div><a href="{% url 'polls:index' %}">返回首页</a></div>
</body>
</html>
test1/templates/polls/result.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>投票结果</title>
</head>
<body>
<h1>{{title}}</h1>
{% for choice in question.choices_set.all %}
<div>
<p>{{choice.choice_text}}------{{choice.votes}}票</p>
</div>
{% endfor %}
<div><a href="{% url 'polls:detail' question.id %}">继续投票?</a></div>
<div><a href="{% url 'polls:index' %}">返回首页</a></div>
</body>
</html>
测试数据.sql
INSERT INTO `polls_questions`(`id`, `quetion_text`, `pub_date`) VALUES
(1, '今天吃什么?', '2020-10-31 14:40:30.000000'),
(2, '你的休闲方式?', '2020-10-31 14:40:56.000000'); INSERT INTO `polls_choices`(`id`, `choice_text`, `votes`, `questions_id`) VALUES
(1, '麻辣火锅', 0, 1),
(2, '串串', 0, 1),
(3, '吃饭', 0, 2),
(4, '睡觉', 0, 2),
(5, '打豆豆', 0, 2);
对于 test1/polls/views.py 文件中的 detail() 和 results() 视图都很精简 。用来显示一个投票列表的 index() 视图也和它们类似。
这些视图反映基本的 Web 开发中的一个常见情况:根据 URL 中的参数从数据库中获取数据、载入模板文件然后返回渲染后的模板。 由于这种情况特别常见,Django 提供一种快捷方式,叫做“通用视图”系统。
通用视图将常见的模式抽象化,可以使你在编写应用时甚至不需要编写Python代码。
让我们将我们的投票应用转换成使用通用视图系统,这样我们可以删除许多我们的代码。我们仅仅需要做以下几步来完成转换,我们将:
- 转换 URLconf。
- 删除一些旧的、不再需要的视图。
- 基于 Django 的通用视图引入新的视图。
1、改良 URLconf
首先,打开 polls/urls.py 这个 URLconf 并将它修改成:
from django.urls import path from . import views app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
注意,第二个和第三个匹配准则中,路径字符串中匹配模式的名称已经由 <question_id> 改为 <pk>。
2、改良视图
下一步,我们将删除旧的 index, detail, 和 results 视图,并用 Django 的通用视图代替。打开 polls/views.py 文件,并将它修改成:
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from polls.models import Questions, Choices
from django.views import generic
from django.utils import timezone from django.http import HttpResponse # def index(request):
# questions = Questions.objects.all()
# return render(request, 'polls/index.html', {'title': '投票首页', 'questions': questions}) # 改成通用视图
class IndexView(generic.ListView):
# 关联模板名称
template_name = 'polls/index.html' # 也可以在urls的.as_view()中当成参数传入
# 指定模板上下文的名称
context_object_name = 'questions' # 数据过滤
def get_queryset(self):
"""返回 pub_date小于等于当前时间的数据,并按pub_date倒序排序"""
questions = Questions.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
print(questions)
return questions # 提供额外的上下文变量
def get_context_data(self, *, object_list=None, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context["title"] = '投票项'
if not context["questions"]:
context["error_msg"] = "No polls are available."
return context # def detail(request, pk):
# question = Questions.objects.get(pk=pk)
# return render(request, 'polls/detail.html', {'title': '投票选项', 'question': question}) # 改成通用视图
class DetailView(generic.DetailView):
template_name = 'polls/detail.html'
# 关联模型
model = Questions
context_object_name = 'question' def get_queryset(self):
return Questions.objects.filter(pub_date__lte=timezone.now()) # 提供额外的上下文变量
def get_context_data(self, *, object_list=None, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context["title"] = '投票详情'
return context # def result(request, question_id):
# question = Questions.objects.get(pk=question_id)
# return render(request, 'polls/result.html', {'title': '投票结果', 'question': question}) # 改成通用视图
class ResultView(generic.DetailView):
template_name = 'polls/result.html'
model = Questions
context_object_name = 'question' # 提供额外的上下文变量
def get_context_data(self, *, object_list=None, **kwargs):
context = super(ResultView, self).get_context_data(**kwargs)
context["title"] = '投票结果'
return context # 保持不变
def vote(request, question_id):
try:
choice = get_object_or_404(Choices, pk=request.POST['choice'])
except(KeyError, Choices.DoesNotExist):
question = Questions.objects.get(pk=question_id)
context = {'title': '投票详情', 'question': question, "error_message": "请选择后提交"}
return render(request, 'polls/detail.html', context) choice.votes += 1
choice.save()
return redirect(reverse('polls:result', args=(question_id,)))
template_name 属性来告诉视图使用哪个模板,
model 属性决定每个通用视图作用于哪个模型。
我们在这里使用两个通用视图: ListView 和 DetailView 。这两个视图分别抽象“显示对象列表”和“显示一个特定类型对象的详细信息页面”这两种概念。
DetailView 期望从 URL 中捕获参数为 "pk" 的主键值,所以我们为通用视图把 question_id 改成 pk 。
默认情况下,通用视图 DetailView 默认使用一个叫做 <app name>/<model name>_detail.html 的模板,在我们的例子中,它将使用 "polls/question_detail.html" 模板。
通用视图 DetailView 使用一个叫做 <app name>/<model name>_detail.html 的模板。在我们的例子中,它将使用 "polls/question_detail.html" 模板。
类似地,ListView 使用一个叫做 <app name>/<model name>_list.html 的默认模板;我们使用 template_name 来告诉 ListView 使用我们创建的已经存在的 "polls/index.html" 模板。
在之前的教程中,提供模板文件时都带有一个包含 question 和 latest_question_list 变量的 context。
对于 DetailView , question 变量会自动提供——因为我们使用 Django 的模型 (Question), Django 能够为 context 变量决定一个合适的名字。
然而对于 ListView, 自动生成的 context 变量是 question_list。为了覆盖这个行为,我们提供 context_object_name 属性,表示我们想使用 questions。
作为一种替换方案,你可以改变你的模板来匹配新的 context 变量 —— 这是一种更便捷的方法,告诉 Django 使用你想使用的变量名。
Django_通用视图(五)的更多相关文章
- 使用pycharm开发web——django2.1.5(五)表单和通用视图
看了刘江老师教程这么多天,卧槽,我才发现他也曾跻身于行伍之间,interesting 刘老师这波讲解很到位,告诉你如何编写单例视图的时候忽然告诉你,其实不用这么麻烦,我们有通用视图,那些总是要做相似的 ...
- ASP.NET MVC 视图(五)
ASP.NET MVC 视图(五) 前言 上篇讲解了视图中的分段概念.和分部视图的使用,本篇将会对Razor的基础语法简洁的说明一下,前面的很多篇幅中都有涉及到视图的调用,其中用了很多视图辅助器,也就 ...
- Django 1.6 基于类的通用视图
Django 1.6 基于类的通用视图 最初 django 的视图都是用函数实现的,后来开发出一些通用视图函数,以取代某些常见的重复性代码.通用视图就像是一些封装好的处理器,使用它们的时候只须要给出特 ...
- django 创建一个通用视图
创建一个通用视图 抽取出我们代码中共性的东西是一个很好的编程习惯. 比如,像以下的两个Python函数: def say_hello(person_name): print 'Hello, ...
- Django:之Sitemap站点地图、通用视图和上下文渲染器
Django中自带了sitemap框架,用来生成xml文件 Django sitemap演示: sitemap很重要,可以用来通知搜索引擎页面的地址,页面的重要性,帮助站点得到比较好的收录. 开启si ...
- Django通用视图执行过程
使用通用视图后,Django请求处理过程(以ListView为例):在我们自定义的视图中: class IndexView(ListView): template_name = 'blog/index ...
- django系列8:优化vote页面,使用通用视图降低代码冗余
修改detail.html,将它变为一个可用的投票页面 <h1>{{ question.question_text }}</h1> {% if error_message %} ...
- 5 第一个Django第4部分(表单和通用视图)
上一节完成了视图编写,这一节为应用添加投票功能,也就是表单提交. 5.1编写一个简单的表单 5.2使用通用视图 5.3改良视图 5.1编写一个简单的表单 在网页设计中添加Form元素 polls/te ...
- Django通用视图APIView和视图集ViewSet的介绍和使用
原 Django通用视图APIView和视图集ViewSet的介绍和使用 2018年10月21日 14:42:14 不睡觉假扮古尔丹 阅读数:630 1.APIView DRF框架的视图的基类是 ...
随机推荐
- JS - 字符串转换成数组,数组转换成字符串
1.字符串转换成数组: var arr = "1, 2, 3, 4, 5, 6"; arr.split(","); // ["1",&quo ...
- [BUUCTF]PWN——ez_pz_hackover_2016
ez_pz_hackover_2016 题目附件 解题步骤: 例行检查,32位,开启了RELRO保护,二进制的保护机制看这里 由于没有开启nx保护,对于这题一开始想到的是利用写入shellcode来获 ...
- 日程表(Project)
<Project2016 企业项目管理实践>张会斌 董方好 编著 Project默认打开时,在功能区下面会有一个[日程表],如果不见了,那肯定里什么时候手贱关掉的,不要紧,还可以到[视图] ...
- Java编程思想—读书笔记(更新中)
第1章 对象导论 1.4 被隐藏的具体实现 访问控制的原因: 让客户端程序员无法触及他们不应该触及的部分(不是用户解决特定问题所需的接口的一部分) 允许库设计者可以改变类内容的工作方式而不用担心会影响 ...
- LuoguB2103 图像相似度 题解
Content 给定两个 \(m\times n\) 的矩阵 \(A,B\),求 \(A,B\) 两个矩阵的相似度,精确到小数点后 \(2\) 位. 定义两个矩阵的相似度为两个矩阵对应相同元素个数占矩 ...
- Docker容器自动更新
前言: Watchtower 是一个可以实现自动化更新 Docker 基础镜像与容器的实用工具.它监视正在运行的容器以及相关的镜像,当检测到registry中的镜像与本地的镜像有差异时,它会拉取最新 ...
- response 返回js的alert()语句,中文乱码如何解决
response 返回js的alert()语句,中文乱码如何解决, 步骤1:在后台加上如下代码: response.setCharacterEncoding("utf-8"); r ...
- ESP8266学习实战之UdpClient与UdpSever(FreeRTOS)
Udpclient 任务流程 ①判断是否获取ip地址 新建状态变量 STATION_STATUS stastatus; 调用wifi接口,并判断是否获取IP地址 ·do { stastatus = w ...
- JAVA微信公众号网页开发——将接收的消息转发到微信自带的客服系统
如果公众号处于开发模式,普通微信用户向公众号发消息时,微信服务器会先将消息POST到开发者填写的url上,无法直接推送给微信自带的客服功能.如果需要把用户推送的普通消息推送到客服功能中,就需要进行代码 ...
- 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)[本文] 再谈多线程模型之生 ...