Django Official Torurial

学习Django的官方教程时记录的笔记

Writing your first Django app, part 1

1.1 Basic command

  1. python -m django --version 查询当前django版本

  2. django-admin startproject mysite 在当前目录下创建一个Django应用

    note: You’ll need to avoid naming projects after built-in Python or Django components. In particular, this means you should avoid using names like django (which will conflict with Django itself) or test(which conflicts with a built-in Python package).

  3. Automatic reloading of runserver

    The development server automatically reloads Python code for each request as needed. You don’t need to restart the server for code changes to take effect. However, some actions like adding files don’t trigger a restart, so you’ll have to restart the server in these cases.

  4. Projects vs. apps

    What’s the difference between a project and an app? An app is a Web application that does something – e.g., a Weblog system, a database of public records or a simple poll app. A project is a collection of configuration and apps for a particular website. A project can contain multiple apps. An app can be in multiple projects.

    通过$ python manage.py startapp polls指令,创建一个名称为polls的web app

1.2 URLconfs

下面以mysite/mysite/urls.py中的URLconfs对其结构进行说明

1
2
3
4
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
  1. The include() function allows referencing other URLconfs. Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing.

    When to use include()

    You should always use include() when you include other URL patterns. admin.site.urls is the only exception to this.

    也就是说,在需要从urls.py指向另外一个应用中的urls.py时,需要使用include来指向另外一个页面的URLconfs

  2. The path() function is passed four arguments, two required: route and view, and two optional: kwargs, and name.

    • route is a string that contains a URL pattern. When processing a request, Django starts at the first pattern in urlpatterns and makes its way down the list, comparing the requested URL against each pattern until it finds one that matches.
    • When Django finds a matching pattern, it calls the specified view function with an HttpRequest object as the first argument and any “captured” values from the route as keyword arguments.
    • Arbitrary keyword arguments can be passed in a dictionary to the target view
    • Naming your URL lets you refer to it unambiguously from elsewhere in Django, especially from within templates. This powerful feature allows you to make global changes to the URL patterns of your project while only touching a single file.

Writing your first Django app, part 2

Model

Now we’ll define your models – essentially, your database layout, with additional metadata.

A model is the single, definitive source of truth about your data. It contains the essential fields and behaviors of the data you’re storing. Django follows the DRY Principle. The goal is to define your data model in one place and automatically derive things from it.

Install App

That small bit of model code gives Django a lot of information. With it, Django is able to:

  • Create a database schema (CREATE TABLE statements) for this app.
  • Create a Python database-access API for accessing Question and Choice objects.

But first we need to tell our project that the polls app is installed.

To include the app in our project, we need to add a reference to its configuration class in the INSTALLED_APPS setting.

$ python manage.py makemigrations polls

Migrations are how Django stores changes to your models (and thus your database schema) - they’re just files on disk. You can read the migration for your new model if you like; it’s the file polls/migrations/0001_initial.py. Don’t worry, you’re not expected to read them every time Django makes one, but they’re designed to be human-editable in case you want to manually tweak how Django changes things.

自动生成的辅助文件可以让我们对生成的数据库有一个更加直观的理解,并且通过指令python manage.py sqlmigrate polls 0001,可以解读等价的SQL指令

The sqlmigrate command doesn’t actually run the migration on your database - it just prints it to the screen so that you can see what SQL Django thinks is required. It’s useful for checking what Django is going to do or if you have database administrators who require SQL scripts for changes.

在安装过app之后,需要进行迁移以创建相应的数据库,这是增量进行的,并不是每次重新创建全部的数据库

python manage.py migrate

值得注意的是,在我使用DB Browers打开数据库的时候,是没有办法对该数据库文件更新的,提示的错误信息是django.db.utils.OperationalError: database is locked

这说明在我打开数据库的时候,它是锁定的,没有办法进行写操作

The Whole Procedure

Migrations are very powerful and let you change your models over time, as you develop your project, without the need to delete your database or tables and make new ones - it specializes in upgrading your database live, without losing data. We’ll cover them in more depth in a later part of the tutorial, but for now, remember the three-step guide to making model changes:

The reason that there are separate commands to make and apply migrations is because you’ll commit migrations to your version control system and ship them with your app; they not only make your development easier, they’re also usable by other developers and in production.

How to create one super user

python manage.py createsuperuser

Make the poll app modifiable in the admin

But where’s our poll app? It’s not displayed on the admin index page.

Just one thing to do: we need to tell the admin that Questionobjects have an admin interface. To do this, open the polls/admin.py file, and edit it to look like this:

1
2
3
4
5
from django.contrib import admin

from .models import Question

admin.site.register(Question)

Writing your first Django app, part 3

Writing more views

通过搭配views.py & urls.py,我进一步对urlpatterns的作用有了清楚的认识

在views中通过定义函数,表明在该目录polls下将会存在哪些子目录,并且规定其中的显示内容

之后在urls中规定什么样的url将会激发什么样的views,甚至可以通过规定url中的格式来向其中传参

Write views that actually do something

尽管上述通过views的方法定义了一些静态页面,但是它们的作用不是很大,django引入了自己的一套html框架,其中使用中括号作为一种自动化的措施,该框架大致如下

但是也可能是因为自己对html还没有掌握好,因此尚未深入到这样的程度

并且,上面的html模板定义的位置还有一个讲究,上述index.html文件,需要定义在polls/templates/polls/文件夹下面,这是为了避免出现查找模板的时候遭遇冲突

Template namespacing

Now we might be able to get away with putting our templates directly in polls/templates (rather than creating another pollssubdirectory), but it would actually be a bad idea. Django will choose the first template it finds whose name matches, and if you had a template with the same name in a different application, Django would be unable to distinguish between them. We need to be able to point Django at the right one, and the easiest way to ensure this is by namespacing them. That is, by putting those templates inside another directory named for the application itself.

同时,为了调用这个模板,需要在polls/view.py文件中定义这样的index()方法

1
2
3
4
5
6
7
8
9
10
11
12
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))

render(context=None, request=None)方法通过context参数传入html模板里面将会出现的各种参数,而request属性是由目前的http请求得到的

同时,该render还有另外的一个简便版本

1
2
3
4
5
6
7
8
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)

虽然上面的render方法的设计只是为了简化操作,但是类似的方法get_object_or_404()则起到了解耦的作用

Philosophy

Why do we use a helper function get_object_or_404() instead of automatically catching the ObjectDoesNotExist exceptions at a higher level, or having the model API raise Http404 instead ofObjectDoesNotExist?

Because that would couple the model layer to the view layer. One of the foremost design goals of Django is to maintain loose coupling. Some controlled coupling is introduced in the django.shortcutsmodule.

Writing your first Django app, part 4

这一部分通过新建两个html文件detail.html & results.html;建立一个通过vote更新数据的函数,使得poll应用已经能够正常使用了,下面依次记录我对它们的理解

detail.html

内部结构

该页面用于进行投票,所以必须有一个数据的转移

具体的实现放在了form标签的action属性中,需要注意的是,action中的内容使用了解耦的方式来编写,前面的url的内容,与urls.py文件中对应项的内容一致,后面的内容目前还不了解

软编码

在part 3的最后一部分,学习了一下软编码的使用方法。所谓的软编码,就是通过向上搜索urls.py中定义的url路径,来填充html中的相应url。具体的使用方法为url url_name,其中url_name出现在urlpatternspath方法的第二个参数,如果这条url中存在变量,那么其格式将是url url_name variable_name

另外一个需要注意的点,是URL的命名空间。也就是在指定url_name的时候,必须加上对应的前缀。

与软编码使用方式相同的还有django.urls包中的reverse()函数,用于给定url_name,返回对应的url。需要注意的是,如果其中含有变量,那么需要第二个参数来指定变量

调用过程

当在浏览器中输入localhost:8000/polls/1的时候,这条url匹配到了位于polls/urls.pyurlpatterns中的第三条路径,根据其中的参数,将会在views.py中寻找DetailView的实现

根据其中指定的template_name,将会调用位于template/polls/detail.html的模板

views.py

内部结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from .models import Question, Choice
from django.template import loader
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.http import Http404
from django.urls import reverse
from django.views import generic
# Create your views here.


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,)))
# return HttpResponse("You're voting on question %s" %question_id)

调用工程

detail.html中首先读取目前已经submit的选项,如果没有选择,发出错误信息;如果读取到了选择的结果,那么更新成员变量,并且返回一个reuslts.html视图

Writing your first Django app, part 5

本节介绍了Django的测试框架

相对于Python的原生测试框架,十分易用,也因此屏蔽了更多的底层内容

调用过程

What happened is this:

  • manage.py test polls looked for tests in the polls application
  • it found a subclass of the django.test.TestCase class
  • it created a special database for the purpose of testing
  • it looked for test methods - ones whose names begin with test
  • in test_was_published_recently_with_future_question it created a Question instance whose pub_date field is 30 days in the future
  • … and using the assertIs() method, it discovered that itswas_published_recently() returns True, though we wanted it to return False

The test informs us which test failed and even the line on which the failure occurred.

测试原则

As long as your tests are sensibly arranged, they won’t become unmanageable. Good rules-of-thumb include having:

  • a separate TestClass for each model or view
  • a separate test method for each set of conditions you want to test
  • test method names that describe their function
0%