有一段时间没用过django了,此次项目中有需要,紧跟官方django的最新版本,所以学习整理一下笔记
一张图看懂Django:
一、第一个项目
1.创建应用
cd desktop // 切换到桌面 mkdir testProject // 新建一个文件夹testProject cd testProject // 打开testProject文件夹 django-admin startproject mysite // 在当前目录下生成一个mysite 的 django应用
在对应的 testProject
目录下,创建第一个项目 mysite
项目目录:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
2.运行服务
python3 manage.py runserver 0:8000
会生成如下代码:
Performing system checks... System check identified no issues (0 silenced). You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. Run 'python manage.py migrate' to apply them. October 10, 2018 - 17:30:51 Django version 2.1.2, using settings 'mysite.settings' Starting development server at http://0:8000/ Quit the server with CTRL-BREAK.
如果是在外网服务器上,那么其他的用户通过互联网就可以访问此WEB项目
二、第一个应用
项目和应用有啥区别?应用是一个专门做某件事的网络应用程序——比如博客系统,或者公共记录的数据库,或者简单的投票程序。项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。
依然在 testProject
目录下创建一个投票调查应用
python3 manage.py startapp polls
应用目录:
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
三、第一个视图
Django
中的视图的概念是「一类具有相同功能和模板的网页的集合
」
在目录 polls/views.py
文件中添加如下代码
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.")
这是 Django
中最简单的视图。如果想看见效果,我们需要将一个 URL
映射到它——这就是我们需要 URLconf
的原因。
在 polls
目录下新建一个 urls.py
文件
在该文件下,写入如下代码:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
下一步是要在根 URLconf
文件中指定我们创建的 polls.urls
模块。在 mysite/urls.py
文件的 urlpatterns
列表里插入一个 include()
, 如下:
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ]
函数 include()
允许引用其它 URLconfs
。每当 Django
遇到 :func:~django.urls.include
时,它会截断与此项匹配的 URL
的部分,并将剩余的字符串发送到 URLconf
以供进一步处理。
我们设计 include()
的理念是使其可以即插即用。因为投票应用有它自己的 URLconf( polls/urls.py )
,他们能够被放在 "/polls/"
, "/fun_polls/"
,"/content/polls/"
,或者其他任何路径下,这个应用都能够正常工作。
- 当包括其它 URL 模式时你应该总是使用 include() , admin.site.urls 是唯一例外。
函数 path()
具有四个参数,两个必须参数:route
和 view
,两个可选参数:kwargs
和 name
。
四、配置
打开 mysite/settings.py
设置文件中 DATABASES 'default'
项目中的一些键值:
ENGINE
— 可选值有 ‘django.db.backends.sqlite3
‘,’django.db.backends.postgresql
‘,’django.db.backends.mysql
‘,或 ‘django.db.backends.oracle
‘。其它 可用后端。
NAME
— 数据库的名称。如果使用的是 SQLite
,数据库将是你电脑上的一个文件,在这种情况下, NAME
应该是此文件的绝对路径,包括文件名。默认值 os.path.join(BASE_DIR, 'db.sqlite3')
将会把数据库文件储存在项目的根目录。
如果不使用 SQLite
,则必须添加一些额外设置,比如 USER
、 PASSWORD
、 HOST
等等
INSTALLED_APPS = [ 'django.contrib.admin', //管理员站点 'django.contrib.auth', //认证授权系统 'django.contrib.contenttypes', //内容类型框架 'django.contrib.sessions', //会话框架 'django.contrib.messages', //消息框架 'django.contrib.staticfiles', //管理静态文件的框架 ]
默认开启的某些应用需要至少一个数据表,所以,在使用他们之前需要在数据库中创建一些表,执行如下命令:
python manage.py migrate 这个 migrate 命令检查 INSTALLED_APPS 设置,为其中的每个应用创建需要的数据表,至于具体会创建什么,这取决于你的 mysite/settings.py 设置文件和每个应用的数据库迁移文件(我们稍后会介绍这个)。这个命令所执行的每个迁移操作都会在终端中显示出来。如果你感兴趣的话,运行你数据库的命令行工具,并输入 \dt (PostgreSQL), SHOW TABLES; (MySQL), .schema (SQLite)或者 SELECT TABLE_NAME FROM USER_TABLES; (Oracle) 来看看 Django 到底创建了哪些表。
五、创建模型
在这个简单的投票应用中,需要创建两个模型:问题 Question
和选项 Choice
。Question
模型包括问题描述和发布时间。Choice
模型有两个字段,选项描述和当前得票数。一个选项属于一个问题。
这些概念可以通过一个简单的 Python
类来描述。按照下面的例子来编辑 polls/models.py
文件:
from django.db import models # Create your models here. class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
每个模型被表示为 django.db.models.Model
类的子类。每个模型有一些类变量,它们都表示模型里的一个数据库字段。
每个字段都是 Field
类的实例 - 比如,字符字段被表示为 CharField
,日期时间字段被表示为 DateTimeField
。这将告诉 Django
每个字段要处理的数据类型。
每个 Field
类实例变量的名字(例如 question_text
或 pub_date
)也是字段名,所以最好使用对机器友好的格式。你将会在 Python
代码里使用它们,而数据库会将它们作为列名。
定义某些 Field
类实例需要参数。例如 CharField
需要一个 max_length
参数。
Field
也能够接收多个可选参数;在上面的例子中:将 votes
的 default
也就是默认值,设为0
。
使用 ForeignKey
定义了一个关系。这将告诉 Django
,每个 Choice
对象都关联到一个 Question
对象。Django
支持所有常用的数据库关系:多对一
、多对多
和 一对一
。
激活模型
上面的一小段用于创建模型的代码给了 Django
很多信息,通过这些信息,Django
可以:
- 为这个应用创建数据库
schema
(生成CREATE TABLE
语句)。 - 创建可以与
Question
和Choice
对象进行交互的Python
数据库API
。
首先得把 polls
应用安装到项目里。
需要在配置类 INSTALLED_APPS
中添加设置。因为 PollsConfig
类写在文件 polls/apps.py
中,所以它的点式路径是 ‘polls.apps.PollsConfig
‘。在文件 mysite/settings.py
中 INSTALLED_APPS
子项添加点式路径后,它看起来像这样:
INSTALLED_APPS = [ 'polls.apps.PollsConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
接着输入如下命令:
python3 manage.py makemigrations polls
输出:
Migrations for 'polls':
polls\migrations\0001_initial.py
- Create model Choice
- Create model Question
- Add field question to choice
通过运行 makemigrations
命令,Django
会检测你对模型文件的修改(在这种情况下,你已经取得了新的),并且把修改的部分储存为一次 迁移。
迁移是 Django
对于模型定义(也就是你的数据库结构)的变化的储存形式 - 没那么玄乎,它们其实也只是一些你磁盘上的文件。如果你想的话,你可以阅读一下你模型的迁移数据,它被储存在 polls/migrations/0001_initial.py
里。别担心,你不需要每次都阅读迁移文件,但是它们被设计成人类可读的形式,这是为了便于你手动修改它们。
Django
有一个自动执行数据库迁移并同步管理你的数据库结构的命令 - 这个命令是 migrate
,我们马上就会接触它 - 但是首先,让我们看看迁移命令会执行哪些 SQL
语句。sqlmigrate
命令接收一个迁移的名称,然后返回对应的 SQL
:
python3 manage.py sqlmigrate polls 0001
输出:
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
INSERT INTO "polls_choice" ("id", "choice_text", "votes", "question_id") SELECT "id", "choice_text", "votes", NULL FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
这个 sqlmigrate
命令并没有真正在你的数据库中的执行迁移
再次运行 migrate 命令,在数据库里创建新定义的模型的数据表:
C:\Users\stdy\Desktop\testdjango\mysite>python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
这个 migrate
命令选中所有还没有执行过的迁移(Django
通过在数据库中创建一个特殊的表 django_migrations
来跟踪执行过哪些迁移)并应用在数据库上 - 也就是将你对模型的更改同步到数据库结构上。迁移是非常强大的功能,它能让你在开发过程中持续的改变数据库结构而不需要重新删除和创建表 - 它专注于使数据库平滑升级而不会丢失数据。
改变模型需要这三步:
- 编辑
models.py
文件,改变模型。 - 运行
python manage.py makemigrations
为模型的改变生成迁移文件。 - 运行
python manage.py migrate
来应用数据库迁移。
六、初试API
打开命令行:
python3 manage.py shell
运行过程:
C:\Users\stdy\Desktop\testdjango\mysite>python3 manage.py shell
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice,Question
>>> Question.objects.all()
<QuerySet []>
>>> from django.utils import timezone
>>> q = Question(question_text = 'What is new?',pub_date = timezone.now())
>>> q
<Question: Question object (None)>
>>> q.save()
>>> q.id
1
>>> q.question_text
'What is new?'
>>> q.pub_date
datetime.datetime(2018, 10, 10, 12, 4, 33, 172278, tzinfo=<UTC>)
>>> q.question_text
'What is new?'
>>> q.question_text = 'What is up?'
>>> q.question_text
'What is up?'
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
>>>
from django.db import models class Question(models.Model): # ... def __str__(self): return self.question_text class Choice(models.Model): # ... def __str__(self): return self.choice_text
给模型增加 __str__()
方法是很重要的,这不仅仅能给你在命令行里使用带来方便,Django
自动生成的 admin
里也使用这个方法来表示对象。
七、管理界面
1.创建管理账号
python3 manage.py createsuperuser
输出:
C:\Users\stdy\Desktop\testdjango\mysite>python3 manage.py createsuperuser
Username (leave blank to use 'dyboy'): dyboy
Email address: dyboy2017@qq.com
Password:***********
Password (again):***********
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
2.进入管理站点
地址:http://127.0.0.1:8000/admin/
将会看到几种可编辑的内容:组和用户。它们是由 django.contrib.auth
提供的,这是 Django
开发的认证框架。
3.向管理页面中加入投票应用
但是我们的投票应用在哪呢?它没在索引页面里显示。
只需要做一件事:我们得告诉管理页面,问题 Question
对象需要被管理。打开 polls/admin.py
文件,把它编辑成下面这样:
向管理页面注册了问题 Question
类
from django.contrib import admin # Register your models here. from .models import Question admin.site.register(Question)
八、概览
视图的概念是「一类具有相同功能和模板的网页的集合」
在我们的投票应用中,我们需要下列几个视图:
- 问题索引页——展示最近的几个投票问题。
- 问题详情页——展示某个投票的问题和不带结果的选项列表。
- 问题结果页——展示某个投票的结果。
- 投票处理器——用于响应用户为某个问题的特定选项投票的操作。
网页和其他内容都是从视图派生而来。每一个视图表现为一个简单的 Python
函数(或者说方法,如果是在基于类的视图里的话)。Django
将会根据用户请求的 URL
来选择使用哪个视图(更准确的说,是根据 URL
中域名之后的部分)。
在你上网的过程中,很可能看见过像这样美丽的 URL: “ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B
“ 。别担心,Django
里的 URL
规则 要比这优雅的多!
一个 URL
模式定义了某种 URL
的基本格式——举个例子:/newsarchive/<year>/<month>/
。
为了将 URL
和视图关联起来,Django
使用了 ‘URLconfs‘ 来配置。URLconf
将 URL
模式映射到视图。
现在让向 polls/views.py
里添加更多视图:
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)
把这些新视图添加进 polls.urls
模块里
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'), ]
写一个真正有用的视图
在 index()
函数里插入了一些新内容,位于 polls/views.py
,让它能展示数据库里以发布日期排序的最近 5
个投票问题,以空格分割:
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)
模版
新建一个模版文件 polls/templates/polls/index.html
在 polls/templates/polls/index.html
:
{% 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 %}
在 polls/views.py
:
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()
「载入模板,填充上下文,再返回由它生成的 HttpResponse
对象」是一个非常常用的操作流程。于是 Django
提供了一个快捷函数,我们用它来重写 index()
视图:
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)
注意到,我们不再需要导入 loader 和 HttpResponse 。不过如果你还有其他函数(比如说 detail, results, 和 vote )需要用到它的话,就需要保持 HttpResponse 的导入。
九、抛出 404 错误
在 polls/views.py
:
from django.http import Http404 from django.shortcuts import render from .models import Question # ... 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})
在 polls/templates/polls/detail.html
:
{{ question }}
一个快捷函数: get_object_or_404()
尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail() 视图代码:
#polls/views.py 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})
模版系统
# polls/templates/polls/detail.html <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
模板系统统一使用点符号来访问变量的属性。在示例 {{ question.question_text }} 中,首先 Django 尝试对 question 对象使用字典查找(也就是使用 obj.get(str) 操作),如果失败了就尝试属性查找(也就是 obj.str 操作),结果是成功了。如果这一操作也失败的话,将会尝试列表查找(也就是 obj[int] 操作)。
在 {% for %} 循环中发生的函数调用:question.choice_set.all 被解释为 Python 代码 question.choice_set.all() ,将会返回一个可迭代的 Choice 对象,这一对象可以在 {% for %} 标签内部使用。
reference: https://docs.djangoproject.com/zh-hans/2.0/topics/templates/
未完待续…
版权声明:《 [学习笔记]Django开发 》为DYBOY原创文章,转载请注明出处!
最后编辑:2018-10-10 19:10:49
2019-10-19 01:52
2019-05-01 21:56
2018-10-12 11:03