第一个Django app
测试环境:
Python版本:python-3.4.0.amd64
下载地址:https://www.python.org/downloads/release/python-340/
Win7 64位
Django 1.11.4
下载地址:https://www.djangoproject.com/download/
安装django
python setup.py install
测试是否成功
>>> import django
>>> print(django.get_version())
1.10.6
>>>
或者
python -m django --version
1.10.6
参考连接:
https://docs.djangoproject.com/en/1.10/intro/install/
https://docs.djangoproject.com/en/1.10/intro/tutorial01/
第一个 Django app Part1
新建项目,选择存放项目的目录(例F:\project\Django\FirstApp),进入该目录,执行django-admin命令
例:新建mysite项目
C:\Users\laiyu>cd /d F:\project\Django\FirstApp
F:\project\Django\FirstApp>django-admin startproject mysite
注意:项目名称不能和python内置组件,或Django组件命名项目,特别是django(和Django自身冲突)或test(和python内置模块冲突)。
运行命令后,生成文件如下:
FirstApp/
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
说明:
最外层mystie: 项目根目录。
manage.py:提供各种方式同Django项目交互的命令行工具。
内层的mysite:python包,存放项目python文件目录。
mystie/__init__.py:一个空文件,告诉python,该目录应该被解析为python包
mysite/settings.py:包含Django项目的配置/设置。
mysite/urls.py:包含Django项目的url声明。
mysite/wsgi.py:服务项目的WSGI-compatible。
确认项目是否能正常运行,切换到根目录,即例中的mysite,运行如下命令:
F:\project\Django\FirstApp\mysite>python manage.py runserver
运行结果:控制台输出如下信息
Performing system checks...
System check identified no issues (0 silenced).
You have 13 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.
March 13, 2017 - 23:14:26
Django version 1.10.6, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
运行服务时,可指定端口,如下
python manage.py runserver 8080
也可以用指定ip来访问服务,放入如下
1.运行如下命令
python manage.py runserver 0.0.0.0:8000
2.编辑project_dir/settings.py文件,把服务所在ip添加到 ALLOWED_HOSTS列表中,如下
ALLOWED_HOSTS = ['192.168.1.103']
点击runserver查看更多关于runserver的说明
创建投票app
项目(project) vs 应用(app)
应用:即一个web应用,比如web 博客系统,存放公共记录的数据库,或者一个简单的投票系统。
项目:特定网站应用和配置的集合。一个项目包含多个应用,而一个应用只能在一个项目中。
接下来,在项目根目录下,创建poll应用,这样方便作为顶级模块导入。
例:在manage.py所在目录,即项目根目录下运行命令来创建polls app
F:\project\Django\FirstApp\mysite>python manage.py startapp polls
运行后生成polls文件:
mysite/
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
编写第一个view
编辑polls/views.py文件,添加python代码(带背景色部分)如下
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
def index(request):
return HttpResponse("hello, world. You're at the polls index")
为了调用这个index view,需要把它映射到一个URL,因此需要一个URL 配置。
在polls目录下,新建一个名为urls.py的文件,以创建URLConf。现在app目录看起来如下:
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
编辑urls.py,添加如下代码
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
配置项目URLConf
编辑mysite/urls.py文件,如下
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
浏览器访问
说明:
1) 正则表达式:$, xxx$:匹配xxx结尾的字符串)。
2) 当Django遇到include()时,会先把请求中的url同include()函数对应的正则表达式匹配(例中按先后顺序分别为:'^polls/','^admin/',如果匹配到,则把URL中匹配到的字符串之后的剩余URL扔给include引用的app URLconf进行后续处理。
例子:修改polls/urls.py内容如下
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'test', views.index, name='index'),
]
修改访问连接:
http://127.0.0.1:8000/polls/testview
访问结果同上。
3)当且仅当需要包含其它应用的URLConf式时使用include()。这里admin.site.urls是个特例。
url函数
url函数接收4个参数:必选参数regex,view,可选参数 kwargs和name。
参数regex: 字符串类型的正则表达式。Django会从urlpatterns list中第一个正则表达式子开始匹配查找直到找到一个匹配的。
注意:正则表达匹配查找时,不搜索GET和POST参数以及域名。比如请求 https://www.example.com/myapp/, URLconf只查找myapp/,又如https://www.example.com/myapp/?page=3,URLconf只查找myapp/
注:正则表达式在第一次加载URLconf模块时就进行了编译,只要不是太复杂的正则表达式,查找速度都很快。
参数view:当Django找到匹配正则表达式的字符串时,会调用view函数,并把一个HttpRequest对象当作第一个函数参数,把通过正则表达式“捕获”的其它值作为其它参数。如果使用simple capture,那么捕获的值以位置参数传递,如果使用named capture则以关键词参数传递。
参数kwargs:关键词参数,以字典方式传递给目标view的关键词参数。
参数name:命名URL,以便在Django其它地方引用时不产生歧义。
参考连接:
https://docs.djangoproject.com/en/1.10/intro/tutorial01/
第一个 Django app Part2
建立数据库
打开mysite/settings.py。这是个普通的python模块,拥有代表Django配置的模块级变量。
默认的,配置使用SQLite。如果你对数据库不熟悉,或者仅是想使用试用Djano,这是个最容易的选择。SQLite包含在python中,所以不要安装其它任何东西来提供数据库支持。但是开始真正的项目时,可能需要使用其它更有伸缩性的数据库比如PostgreSQL。
如果想使用其它数据库,安装数据库并改变DATABASE 'default'项中的关键词来匹配数据库连接,如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
说明:
ENGINE:可选值是'django.db.backends.sqlite3', 'django.db.backends.postgresql', 'django.db.backends.mysql', 或者'django.db.backends.oracle'。其它后端也可以,查看详情
NAME:数据库名字。
如果使用SQLite,数据库文件将存放在电脑上,这种情况下,NAME应该为绝对路径,包含数据库文件的文件名。默认值如上,把数据库文件存放在项目根目录下。
如果不使用SQLite,需要设置额外参数如 USER, PASSWORD,和HOST。更多详情参考DATABASES.
另外,确保提供的USER具备“create database”权限。
编辑mysite/settings.py,设置TIME_ZONE为你的时区。
注意INSTALLED_APPS设置,该设置包含了Django实例中激活的所有Django应用。应用可在多个项目中使用,可以打包并发布给其它项目使用。
默认的,INSTALLED_APPS包含以下来自Django应用:
django.contrib.admin - 管理后台
django.contrib.auth - 授权系统
django.contrib.contenttypes - content type框架
django.contrib.sessions - 会话框架
django.contrib.message - 消息框架
django.contrib.staticfiles - 管理静态文件的框架
其中,一些应用使用了数据库表,所以,我们需要在使用它们之前创建数据库表。为了达到这个目的,执行以下命令:
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying sessions.0001_initial... OK
F:\project\Django\FirstApp\mysite>
migrate查找INSTALLED_APPS设置,然后根据mysite/setting.py中的数据库设置和应用程序的数据库迁移
创建必要的数据库。查看创建的表:数据库客户端输入命令\dt(PostgreSQL),.shema(MySQL), SELECT TABLE_NAME FROM USER_TABLES(Oracle);
提醒:一些默认的应用我们不需要,可以在运行migrate之前删除、注释掉。
创建模块
将在poll应用中创建两个模块:Question和Choice。每个Question包含一个问题和发布日期,每个Choice有两个域:选项文字和投票计数器。每个Choice同一个Question关联。
编辑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的子类表示,类变量代表model中数据库Field。
每个域由一个Field类(比如代表字符串的CharField,代表时间的DateTimeField)实例表示,告诉Django每个field可容纳什么类型的数据。
Field实例(比如 question_text、pub_date)的名字,即为域的名字,可在python代码中使用,同时数据库也将把它当表字段名使用。
给Field提供的第一个可选的位置参数可用来生成便于人易读的名字。如果未提供,则使用机器易读的名字作为人类易读的名字。例中,我们仅为Question.pub_date提供了人类易读的名字date published,其它模块Field实例则使用机器易读的名字,比如choice_text。
一些Field需要必选参数,比如CharField,需要提供max_length。这不仅是用于数据库模式(schema),还用于合法性验证(validation)。
Field还有各种可选参数,比如例中把votes的default值设置为0。
最后,注意这里使用ForeignKey来确立关系,这告诉Django每个Choice和单个Question关联。Django支持所有公共数据库关系:多对一,多对多,一对一。
激活模块
上述模块代码给Django提供了许多信息,拥有它,Django可:
1)为该app创建数据库模式(CREATE TABLE语句)
2)为访问Question和Choice对象创建Python 数据库访问api
但是,要先告诉项目已安装polls应用。
为了在项目中包含该app,需要在INSTALLED_APPS设置中添加引用。PollsConfig类位于polls/apps.py文件中,点分路径为jango.apps.PollsConfig,如下:
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'
编辑mysite/settings.py,添加点分路径(带背景色内容)
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
运行命令:
F:\project\Django\FirstApp\mysite>python 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你对模块做了些改动,并且希望记录这些改动(但不立即执行这些改动),这些改动存在在磁盘文件,上例中文件为polls/migrations/0001_initial.py。可易方式读取这些改动,查看migration带来的sql执行。
python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "c
hoice_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, "c
hoice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integ
er NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice" ("question_id", "choice_text", "votes", "id") SELECT
NULL, "choice_text", "votes", "id" FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
COMMIT;
注意:
1)Django会自动添加主键 id(可重写)
2)约定的,Django会添加”_id”到外键域(可重写)
可执行python manage.py check,在不执行迁移或改动数据库的情况下,来检查项目中的问题
接着,执行migrate在数据库中创建模块表,即让上述存储的改动在应用中生效。
F:\project\Django\FirstApp\mysite>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
阅读django-admin documentation查看manage.py工具的更多功能。
API交互
调用python shell
python manage.py shell
Python 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:25:23) [MSC v.1600 64 bit (AM
D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
同直接运行python不一样,因为manage.py设置DJANGO_SETTINGS_MODULE环境变量,为mysite/settings.py文件提供python导入路径。
注:也可以不用manage.py,直接设置DJANGO_SETTINGS_MODULE环境变量,然后运行python并设置Django
set DJANGO_SETTINGS_MODULE=mysite.settings
python
Python 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:25:23) [MSC v.1600 64 bit (AM
D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.setup()
按这种方式,必须在manage.py所在目录下开启python。或者确保这个目录在python的path中,这样import mystie才起作用。
调用数据库api
>>> from polls.models import Question, Choice
# 系统中还没有问题
>>> Question.objects.all()
<QuerySet []>
# 创建一个新的Question
>>> from django.utils import timezone
>>> q = Question(question_text="what's up?", pub_date=timezone.now())
# 保存对象到数据库。
>>> q.save()
# 输出也可能是1L,而不是1,取决于数据库。
>>> q.id
1
# 通过python属性访问模块field
>>> q.question_text
"what's up?"
>>> q.pub_date
datetime.datetime(2017, 3, 22, 12, 57, 18, 103269, tzinfo=<UTC>)
# 通过修改属性来修改field
>>> q.question_text = "what's up?"
>>> q.save()
# objects.all()展示数据库中的所有问题。
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>
为了更清楚点的显示对象,可编辑polls/models.py文件,添加一个__str__()方法到Question和Choice。
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible # 如果需要支持python2
Question(models.Model):
# ...
def __str__(self):
return self.question_text
@python_2_unicode_compatible # 如果需要支持python2
# ...
def __str__(self):
return self.choice_text
添加自定义方法
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
再次运行python manage.py shell
>>> from polls.models import Question, Choice
# 确认 __str__() 是否起作用
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
# Django提供了一个完全由关键词参数驱动的丰富的数据库API。
>>> 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) #注意 pub_date和year中间有两下划线
<Question: What's up?>
# 如果请求的id不存在,将抛出异常.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...DoesNotExist: Question matching query does not exist.
# 按主键查询,以下命令等同于Question.objects.get(id=1)
>>> Question.objects.get(pk=1)
<Question: What's up?>
# 确认自定义方法起作用
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# 给Question多个Choice。调用create函数构造一个新的Choice对象,执行INSERT 语句,添加choice到#获取的choice set,然后返回新建的Choice对象。Django创建了一个集合以容纳ForeignKey 关系的另一方#(如 question’s choice)。
>>> q = Question.objects.get(pk=1)
# 展示相关对象集的choice - 目前为空
>>> q.choice_set.all()
<QuerySet []>
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
# Choice 对象有API可访问与其相关的Question对象。
>>> c.question
<Question: What's up?>
# 反之,Question 对象可访问Choice对象。
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
# 只要你需要,API自动跟随关系。关系之间用下划线关联。
# 找出同Choice关联的question,要求qub_date在今年以内
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# 删除其中一个choice
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
查看更多关于对象关系:Accessing related objects,更多关于使用双下划线进行域查找:Field lookups,数据库API完整信息:Database API reference