上篇文章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/
将我们的投票应用转换成使用通用视图系统,这样我们可以删除许多我们的代码。我们仅仅需要做以下几步来完成转换,我们将:
- 转换 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 应用,第 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'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
出现类似输出,表示成功
向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)
查看数据库表中的数据
成功了。