Django教程笔记
这是Django官方教程《初次使用 Django 创建应用程序》,包括第1到第5部分的笔记。
这只是一张普通的便条。
这是我们的官方网站链接:https://docs.djangoproject.com/ja/3.1/intro/tutorial01/
1. 安装
创建Python环境并使用pip进行安装。
pip install django
我来确认一下你是否在里面。
(Please note that Chinese translation can vary depending on the context. This is a common way to express the sentence, but there can be alternative ways as well.)
$ python -m django --version
3.1.2
似乎已经安装了Django 3.1.2。
创建一个Django项目。
执行django-admin startproject hoge命令时,会自动为项目创建必要的最基本文件夹和文件。
django-admin startproject mysite
生成的文件具有以下的结构。
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
DB已经是Python的标准库sqlite3。
我们先试试在这个状态下能否显示示例页面。运行manage.py runserver会启动一个简易的开发服务器。
python manage.py runserver
请注意,这个简易服务器只是为了开发中的使用而设计的,所以在官方教程中明确写着“绝对不要在运营环境中使用”。在生产环境中,应该使用Apache等进行发布。
在项目中创建应用程序。
Django可以协调多个应用程序的使用。只需按以下步骤执行,它将自动为应用程序生成必需的最小文件。
python manage.py startapp polls
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
由于可以制作很多个应用程序,因此如果能够按功能进行有效分割,生产力可能会提高。
创建用于投票应用的视图
将view写在views.py中。
当用户访问/polls/index.html时,将通过HTTP返回”Hello, world. You’re at the polls index.”的视图。
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
我们将上述的views.py相关联写入urls.py。
如果在django.urls.path()中写入,它会关联。按照以下的方式编写,它会先参考mysite/urls.py,然后是polls/urls.py,最后是polls/views.py,从而找到polls/views.py中的index()函数。
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
我们可以使用这个来进行关联,然后启动简易服务器进行确认。
python manage.py runserver
http://localhost:8000/polls/ 是一个网址,它可以连接到 polls/views.py 中的内容并进行等待。
5. 数据库的更改
默认情况下,我们使用sqlite3作为数据库,所以即使不进行特别的数据库设置,也可以开始使用。在生产环境中,我们会考虑切换到postgreSQL或者mySQL,这种情况下,请参考以下链接:
https://docs.djangoproject.com/ja/3.1/intro/tutorial02/
6. 设置TIME_ZONE
标准设置为UTC。
TIME_ZONE = 'UTC'
如果要切換到日本標準時間,請按照以下方式進行更改。
TIME_ZONE = 'Asia/Tokyo'
USE_TZ = True
7. 移民到其他地方上班。
根据setting.py文件的内容构建数据库。
python manage.py migrate
Django能够将数据库的数据处理成对象,因此数据处理变得更加轻松。(目前我正在写的时候还不太清楚。)
8. 建立模型
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
让Django意识到模型有所变更
python manage.py makemigrations polls
使用Django shell
为了增加生产力,Django通过强制规定的目录结构来提高效率,但它存在一个问题,即文件之间的连接变得复杂,在Django中执行函数时很难确认会发生什么。为了便于确认,Django提供了Django shell,可以通过python manage.py shell命令来执行。
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet []>
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()
>>> q.id
1
>>> q.question_text = "What's up?"
>>> q.save()
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
>>> q.question_text
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
python manage.py shell
In [1]:
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
>>> Question.objects.get(pk=1)
<Question: What's up?>
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
<QuerySet []>
>>> q.choice_set.create(choice_text='Not much', votes=0)
>>> q.choice_set.create(choice_text='The sky', votes=0)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?>
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
10. 创建管理员用户
为Django项目创建一个项目监理superuser。这个superuser与Linux操作系统的用户是不同的,它专为Django而设。
python manage.py createsuperuser
只要输入ID和密码,就可以完成注册。通过这样做,您可以登录管理页面并启动简易服务器。让我们登录管理页面并启动简易服务器。
python manage.py runserver
11. 通过管理员页面编辑应用程序
from django.contrib import admin
from .models import Question
admin.site.register(Question)
因为这比通过shell操作更容易理解,所以我想善于使用这个。
12. 一路向前去看 +
第三节:初次创建 Django 应用程序
https://docs.djangoproject.com/ja/3.1/intro/tutorial03/
通过URL改变打开的视图
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
当你在终端输入python manage.py runserver并在浏览器中打开以下链接时,polls/views.py中的detail()、results()和vote()将会被依次执行。
http://127.0.0.1:8000/polls/34/
http://127.0.0.1:8000/polls/34/results/
http://127.0.0.1:8000/polls/34/vote/
制作索引页
在 polls/views.py 文件的 index() 函数中,将其重新编写为以下方式:
将 Question. 重新修改成其他内容。
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
13. 制作模板
我们在上述代码中直接在views.py文件中写入了界面布局,但为了更容易进行修改,我们应将代码分离到模板中。我们在views.py文件中写入loader.get_template(‘polls/index.html’),以便读取template/polls/index.html文件。
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
渲染
将读取模板并渲染它的方法替换为render()可以让代码变得更简洁,同时也减少了导入的包的数量。
from django.shortcuts import render
from .models import Question
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)
14. 显示404错误
当发生异常时,使用try/except语句以返回404错误。
from django.http import Http404
from django.shortcuts import render
from .models import Question
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):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
找到对象或返回404
由于每次尝试/捕获都很麻烦,我们可以尝试使用一个函数get_object_or_404(),它会尝试获取对象,如果失败则返回404。
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
15. 应用程序的命名空间
如果在polls/urls.py中指定了app_name,就可以从应用的命名空间中引用它。如果不这样做,在另一个应用中有相同名称的视图时,可能会出现问题,所以我认为在创建视图的时候最好记得指定它。
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
这将导致参考视图从detail更改为polls:detail。让我们重新指定其他视图,例如polls:hoge。
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
16. 写表格
开发第一个 Django 应用程序,第4步
https://docs.djangoproject.com/zh-hans/3.1/intro/tutorial04/
在这里添加投票按钮。
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% 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 %}
<input type="submit" value="Vote">
</form>
投票:在polls/urls.py中,查看的视图是这样写的,所以只需在poll/views.py中写下即可。
path('<int:question_id>/vote/', views.vote, name='vote'),
我会添加一个选择项到/polls/results/,并将其重定向。
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, 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):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
我也会写一个调用”/polls/results/”视图函数的重定向。
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
17. 使用通用视图
使用通用视图可以减少冗余的编写。
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'),
]
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 Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
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'
还有很多继续,但这只需要一个选择:https://docs.djangoproject.com/ja/3.1/intro/tutorial05/