• 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代码。

    让我们将我们的投票应用转换成使用通用视图系统,这样我们可以删除许多我们的代码。我们仅仅需要做以下几步来完成转换,我们将:

    1. 转换 URLconf。
    2. 删除一些旧的、不再需要的视图。
    3. 基于 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、改良视图

     下一步,我们将删除旧的 indexdetail, 和 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 使用你想使用的变量名。
  • 相关阅读:
    我是这样在Google paly上赚美刀的
    休闲英语:超经典实用的英文短信缩写
    休闲英语:揭秘7招最有效的拍马屁技巧
    laravel5数据库配置及其注意事项
    帮助函数
    Laravel报错Call to undefined function Illuminate\Encryption\openssl_cipher_iv_length()
    NetBeans 时事通讯(刊号 # 67 Aug 04, 2009)
    JavaEE 6 将包括 JSR330 和 JSR299
    苯事两则
    NetBeans 时事通讯(刊号 # 66 Jul 30, 2009)
  • 原文地址:https://www.cnblogs.com/testlearn/p/13908850.html
Copyright © 2020-2023  润新知