djangoproject/first_django_app.md

226 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# First Django App
Target: create a basic poll application, with 2 parts a **public site** and a **admin site**
* **public site**: let's pp view polls and vote
* **admin site**: let's you(admin) add/change/delete poll
## Part 1
1. Create web project
2. Create 1st app
3. Create 1st view
4. Add view & app into web url
### Creating a project
In the source directory, create project by
```
$ django-admin startproject <project_name>
```
Constraint on `<project_name>`:
* don't use names that conflict with django
* e.g. `django`, `test` (test with built-in test file)
```
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
```
Explain file structure:
* top-level `mysite/`: container of the project, can be renamed latter w/o affect Django framework
* `manage.py`: cmd-line utility let us to interact (admin) with Django projects.
* inner `mysite/` dir: actual Python package for the project.
* Importing any package from here: e.g. `mysite.urls`
* `mysite/__init__.py`: empty file, tell python start from here.
* `mysite/settings.py`: settings/config for this django project.
* `mysite/urls.py`: URL declarations for this Django pjt; a "table of contents" of this Django website.
* `mysite/asgi.py`: An entry-point for ASGI-compatible webservers
* `mysite/wsgi.py`: Entry-point for WSGI-compatible webservers
### The development server
Start server steps:
1. cd into outer `mysite/` dir
2. Start server via: `python manage.py runserver`
Outcome:
* A development server is started. So no need to config a production server (e.g. Apache)
* Note: don't use it as production environment.
### Creating the Polls app
> Projects vs. apps
>
> Whats 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 small 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.
Create a poll app along `mysite/`. For what?
```
$ python manage.py startapp polls
```
app hierarchy
```
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
```
### Write the first view
#### Step 1: Create a simple view of `polls` app
modify `polls/views.py` as
```python
from django.http import request
from django.shortcuts import render
def index(request):
return HttpResponse("Hello, world. You're at the polls index")
```
* `def index(request):...` is the simplest view
#### Step 2: In `polls` app, map the URL to this view
After creating a view, map it to a URL so we can call it. Create `polls/urls.py`, and setup mapping `urlpatterns`
```python
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
```
#### Step 3: Point the root URLconf for polls
To point the root URLconf at `polls.urls` module:
1. In `mysite/urls.py`
1. add import for `django.urls.inclue`
2. insert a `include()` in `urlpatterns` list
i.e.
```python
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
```
##### django.urls.include()
> django.urls.include(): A function that takes a full Python import path to another URLconf module that should be “included” in this place.
* new imported `include()` function allows referencing other URLconfs.
* `'polls.urls'` is the package that we are using, hence `mysite` can connect to `polls` app
##### path()
Here `path()` function is passed **route** and **view**; two additional option available **kwargs**, and **name**
* `path()` argument **route**: a string that contains a URL pattern. When Django processing a request, it starts at the first pattern in `urlpatterns` and go down the list, comparing requested URL against each pattern
* `path()` argument **view**: when Django finds a matching pattern, it calls specified view function (a `HttpRequest` obj as the 1st argument, and others captured values as keyword argument)
* `path()` argument **kwargs**: passed in a dictionary to the target view
* `path()` argument **name**: naming URL, so we can refer to it elsewhere.
## Part 2
### Database setup
1. Modify `mysite/settings.py` for database binding
2. `python manage.py migrate` create database for each app
### Models Creation
在 Django 里写一个数据库驱动的 Web 应用的第一步: **定义模型** - 也就是数据库结构设计和附加的其它元数据 Meta Data
### Activate Models
改变模型需要这三步:
* 编辑 models.py 文件,改变模型
* 运行 python manage.py makemigrations 为模型的改变生成迁移文件。
* 运行 python manage.py migrate 来应用数据库迁移。
在这之前确认polls已经在 INSTALLED_APPS的settings中。
详情如何使用 `manage.py` 可check [Django后台文档](https://docs.djangoproject.com/zh-hans/3.1/ref/django-admin/)
### Test API
进入 `python manage.py shell` 可以使用Django创建的各种API如[数据库抽象API database API(建议细看)](https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/)
## Part 3
* In Django, web content & HTML come from Views models. Every view is a Python function/class. Django use customer requested URL to decide which View to generate.
* Django use 'URLconfs' to map btw URL and Views. Details of[pURL manager](https://docs.djangoproject.com/zh-hans/3.1/topics/http/urls/)
* URL's general form: `/newsarchive/<year>/<month>/`
### 3.1 Create more Views
> 当某人请求你网站的某一页面时——比如说, "/polls/34/" Django 将会载入 mysite.urls 模块,因为这在配置项 ROOT_URLCONF 中设置了。然后 Django 寻找名为 urlpatterns 变量并且按序匹配正则表达式。在找到匹配项 'polls/',它切掉了匹配的文本("polls/"),将剩余文本——"34/",发送至 'polls.urls' URLconf 做进一步处理。在这里剩余文本匹配了 "<int:question_id>/",使得我们 Django 以如下形式调用 polls.urls.detail():
> `detail(request=<HttpRequest object>, question_id=34)`
### 3.2 Create a true useful View
每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404 。至于你还想干些什么,随便你。
你的视图可以从数据库里读取记录,可以使用一个模板引擎(比如 Django 自带的,或者其他第三方的),可以生成一个 PDF 文件,可以输出一个 XML创建一个 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 库。
`django.shortcuts.render` 可以“载入模板,填充上下文,再返回由它生成的 HttpResponse 对象“
#### shortcut function: `render()`
「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数 render
> The render() function takes the request object as its first argument, a template name as its second argument and a dictionary as its optional third argument. It returns an HttpResponse object of the given template rendered with the given context.
### 3.3 Throw 404 error
如果指定问题 ID 所对应的问题不存在,这个视图就会抛出一个 Http404 异常。
尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数, 从而取代try/except语句
> 什么我们使用辅助函数 get_object_or_404() 而不是自己捕获 ObjectDoesNotExist 异常呢?还有,为什么模型 API 不直接抛出 ObjectDoesNotExist 而是抛出 Http404 呢?
> 因为这样做会增加模型层和视图层的耦合性。指导 Django 设计的最重要的思想之一就是要保证松散耦合。一些受控的耦合将会被包含在 django.shortcuts 模块中。
### 3.4 Using template system
[Templates in Django](https://docs.djangoproject.com/en/3.1/topics/templates/)
`polls/detail.html` 模板里正式的代码:
```html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
```
模板系统统一使用点符号来访问变量的属性