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
image.png

请注意,这个简易服务器只是为了开发中的使用而设计的,所以在官方教程中明确写着“绝对不要在运营环境中使用”。在生产环境中,应该使用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
admin02.png

11. 通过管理员页面编辑应用程序

from django.contrib import admin
from .models import Question

admin.site.register(Question)
admin03t.png
image.png

因为这比通过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>
image.png

投票:在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/

广告
将在 10 秒后关闭
bannerAds