Django 4.0文档学习(三)

时间:2023-04-01 14:56:27

上篇文章Django 4.0文档学习(二)

编写你的第一个 Django 应用,第 4 部分

编写一个简单的表单

polls/templates/polls/detail.html
更新一下在上一个教程中编写的投票详细页面的模板

<form action="{% url 'polls:vote' question.id %}" method="post">
    {%csrf_token %}
    <fieldset>
    <legend><h1>{{question.question_text}}</h1></legend>
    {% if error_message%}<p><strong>{{error_message}}</strong></p>{%endif%}
    {% for choice in question.choice_set.all%}
    <input type="radio" name="choice" id="choice{{forloop.counter}}" value="{{choice.id}}">
    <label for="choice{{forloop.counter}}">{{choice.choice_text}}</label><br>
    {%endfor%}
    </fieldset>
    <input type="submit" value="Vote">
</form>

创建一个 Django 视图来处理提交的数据。
polls/views.py

from django.http import HttpResponse,HttpResponseRedirect
from django.shortcuts import get_object_or_404,render
from django.urls import reverse
from .models import Question,Choice
def index(request):
    latest_question_list=Question.objects.order_by('-pub_date')[:5]
    context={'latest_question_list':latest_question_list,}
    return render(request,'polls/index.html',context)
def detail(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    return render(request,'polls/detail.html', {'question':question})
def results(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    return render(request,'polls/results.html', {'question':question})
def vote(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except(KeyError,Choice.DoesNotExist):
        return render(request,'polls/detail.html',{
            'question':question,
            'error_message':"You didn't select a choice.",
        })
    else:
        selected_choice.votes+=1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results',args=(question_id,)))

创建一个 polls/results.html 模板

<h1>{{question.question_text}}</h1>
<ul>
  {% for choice in question.choice_set.all%}
  <li>{{choice.choice_text}} -- {{choice.votes}} vote{{choice.votes|pluralize}}</li>
  {%endfor%}
</ul>
<a href="{% url 'polls:detail' question.id%}">Vote again?</a>

启动程序

python .\manage.py runserver
http://127.0.0.1:8000/polls/1/

Django 4.0文档学习(三)
Django 4.0文档学习(三)
将我们的投票应用转换成使用通用视图系统,这样我们可以删除许多我们的代码。我们仅仅需要做以下几步来完成转换,我们将:

  • 转换 URLconf。
  • 删除一些旧的、不再需要的视图。
  • 基于 Django 的通用视图引入新的视图。

改良 URLconf

polls/urls.py

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'),
]

改良视图

polls/views.py

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404,render
from django.urls import reverse
from django.views import generic
from .models import Question,Choice
class IndexView(generic.ListView):
    template_name ='polls/index.html'
    context_object_name='latest_question_list'
    def get_queryset(self):
        return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
    model=Question
    template_name ='polls/detail.html'
class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'
def vote(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except(KeyError,Choice.DoesNotExist):
        return render(request,'polls/detail.html',{
            'question':question,
            'error_message':"You didn't select a choice.",
        })
    else:
        selected_choice.votes+=1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results',args=(question_id,)))

这里使用两个通用视图: ListView 和 DetailView 。这两个视图分别抽象“显示一个对象列表”和“显示一个特定类型对象的详细信息页面”这两种概念。

  • 每个通用视图需要知道它将作用于哪个模型。 这由 model 属性提供。
  • DetailView 期望从 URL 中捕获名为 "pk"的主键值,所以我们为通用视图把 question_id 改成 pk 。

浏览器查看页面是否正常显示
Django 4.0文档学习(三)

Django 4.0文档学习(三)
Django 4.0文档学习(三)

编写你的第一个 Django 应用,第 5 部分

自动化测试是什么?
测试代码,是用来检查你的代码能否正常运行的程序。

我们的 polls 应用现在就有一个小 bug 需要被修复:我们的要求是如果 Question 是在一天之内发布的, Question.was_published_recently() 方法将会返回 True ,然而现在这个方法在 Question 的 pub_date 字段比当前时间还晚时也会返回 True(这是个 Bug)。

python .\manage.py shell
>>> from django.utils import timezone
>>> from polls.models import Question
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True

修复这个 bug
polls/models.py

def was_published_recently(self):
    now=timezone.now()
    return now - datetime.timedelta(days=1) <= self.pub_date <= now

测试视图

python manage.py shell
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()
>>> from django.test import Client
>>> client = Client()
>>> response = client.get('/')
Not Found: /
>>> response.status_code
404
>>> from django.urls import reverse
>>> response = client.get(reverse('polls:index'))
>>> response.status_code
200
>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/2/">Which you like?</a></li>\n    \n        <li><a href="/p
olls/1/">What&#x27;s up?</a></li>\n    \n    </ul>\n'
>>> response.context['latest_question_list']
<QuerySet [<Question: Which you like?>, <Question: What's up?>]>

改善视图代码

polls/views.py

class IndexView:中改善
	def get_queryset(self):
	    return Question.objects.filter(
	        pub_date__lte=timezone.now()
	    ).order_by('-pub_date')[:5]
class DetailView:中添加
	def get_queryset(self):
	    return Question.objects.filter(pub_date__lte=timezone.now())

Django数据迁移SQLite3->MySQL8

导出SQLite数据

python manage.py dumpdata >data.json

新建MySQL数据库

mysql> create database django_polls;

更改配置文件settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_polls',
        'USER':'root',
        'PASSWORD': 'root',
        'HOST':'localhost',
        'PORT':'3306',
    }
}

添加python的pymysql库
添加完后
修改该配置文件所在目录下的__init__.py文件

import pymysql
pymysql.install_as_MySQLdb() 

运行

python manage.py migrate

出现类似输出,表示成功
Django 4.0文档学习(三)
向MySQL数据库导入数据

python manage.py loaddata data.json

如出现以下报错

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

通过vs code或notepad++这种软件以uft8的格式重新保存之前导出的data.json文件。

python manage.py loaddata data.json

成功显示
Installed 48 object(s) from 1 fixture(s)

查看数据库表中的数据
Django 4.0文档学习(三)
成功了。