本文参考:https://docs.djangoproject.com/en/1.9/intro/tutorial02/
设置数据库:
在mysite/setting.py里设置数据库类型,默认如下:
1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.sqlite3', 4 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 5 } 6 }
其中EGINE可以替换为其他数据库。
1 'django.db.backends.sqlite3', 2 'django.db.backends.postgresql', 3 'django.db.backends.mysql', 4 'django.db.backends.oracle'
python默认内置了sqlite,Django同样可以使用。
然后运行 python manage.py migrate ,会根据setting.py里的 INSTALLED_APPS 设置数据库表。
接下来设置模版:
编辑polls/model.py
1 from django.db import models 2 3 4 class Question(models.Model): 5 question_text = models.CharField(max_length=200) 6 pub_date = models.DateTimeField('date published') 7 8 9 class Choice(models.Model): 10 question = models.ForeignKey(Question, on_delete=models.CASCADE) 11 choice_text = models.CharField(max_length=200) 12 votes = models.IntegerField(default=0)
每个类都是 dango.db.models.Model 的子类,每个类具有许多类变量,每个都是模版数据库的字段。每个字段由 Field 字段的实例表示,如 CharField , DateTimeField ,分别表示字符字段和日期时间字段。
字段的实例(如 question_text 和 pub_date ),是对机器友好的格式,可以在Python代码中使用,也可以在数据库的列名中使用。
一些字段类需要参数,以 CharField 为例,需要 max_length 参数,它不仅仅用在数据库模式 ,验证也会用到(保留疑问,原文说稍后提及)。一些字段也有可选参数,在这种情况下,我们设置 default 为0.
它们的关系是由 ForeignKey 建立的,这告诉Django每个 Choice 都会联系到一个 Question 上,Django支持很多常见的数据库关系:多对一,多对多,一对一。
激活模版:
首先需要告诉项目polls app已经安装了
再次编辑mysite/setting.py
1 INSTALLED_APPS = [ 2 'polls.apps.PollsConfig', #加入这行,告诉Django已经加入了polls App 3 'django.contrib.admin', 4 'django.contrib.auth', 5 'django.contrib.contenttypes', 6 'django.contrib.sessions', 7 'django.contrib.messages', 8 'django.contrib.staticfiles', 9 ]
接下来运行 python manage.py makemigration polls .
虽然只有一行代码,却做了很多事情:
1:为这个APP创建数据库架构(CREATE TABLE语句)
2:为了访问Question 和 Choice 创建了一套python的连接数据库的API
然后出现了如下文字
1 Migrations for 'polls': 2 0001_initial.py: 3 - Create model Choice 4 - Create model Question 5 - Add field question to choice
makemigration 实际是告诉Django,模版已经做了改变(在这里是增加了创建了新的模版),需要将该改变的部分 migrate 。
Migration是Django存储模版的方式,它仅仅是硬盘上的文件,你可以读取它。就像polls/migration/0001_initial.py一样。你可以读取它,并且它是可以修改的,以方便必要的时候手动修改。文件如下:
1 # -*- coding: utf-8 -*- 2 # Generated by Django 1.9.4 on 2016-03-14 04:46 3 from __future__ import unicode_literals 4 5 from django.db import migrations, models 6 import django.db.models.deletion 7 8 9 class Migration(migrations.Migration): 10 11 initial = True 12 13 dependencies = [ 14 ] 15 16 operations = [ 17 migrations.CreateModel( 18 name='Choice', 19 fields=[ 20 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 ('choice_text', models.CharField(max_length=200)), 22 ('votes', models.IntegerField(default=0)), 23 ], 24 ), 25 migrations.CreateModel( 26 name='Question', 27 fields=[ 28 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 ('question_text', models.CharField(max_length=200)), 30 ('pub_date', models.DateTimeField(verbose_name='date published')), 31 ], 32 ), 33 migrations.AddField( 34 model_name='choice', 35 name='question', 36 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), 37 ), 38 ]
也就是说,这些代码是 makemigration 生成用于 migrate 的。
接下来运行 python manage.py sqlmigrate polls 0001
运行结果如下
1 BEGIN; 2 -- 3 -- Create model Choice 4 -- 5 CREATE TABLE "polls_choice" ( 6 "id" serial NOT NULL PRIMARY KEY, 7 "choice_text" varchar(200) NOT NULL, 8 "votes" integer NOT NULL 9 ); 10 -- 11 -- Create model Question 12 -- 13 CREATE TABLE "polls_question" ( 14 "id" serial NOT NULL PRIMARY KEY, 15 "question_text" varchar(200) NOT NULL, 16 "pub_date" timestamp with time zone NOT NULL 17 ); 18 -- 19 -- Add field question to choice 20 -- 21 ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL; 22 ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT; 23 CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id"); 24 ALTER TABLE "polls_choice" 25 ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id" 26 FOREIGN KEY ("question_id") 27 REFERENCES "polls_question" ("id") 28 DEFERRABLE INITIALLY DEFERRED; 29 30 COMMIT;
不同的数据库会产生不同的结果,这是PostgreSQL的结果。
其中创建的表名是根据APP的名字(polls)和模版名的小写(questionh和choice)(可以重写),主键是自动生成的(可以重写),为了方便起见, 外键被加上了_id后缀(也可以重写),外键关系由 FOREIGN KEY 明确做出了约束。
sqlmigrate 并不会真正对数据库执行 migration ,它只是把SQL Django认为需要执行的命令打印出来,以方便数据库管理员做SQL脚本上的修改。
你还可以执行 python manage.py check ,检查是否做了 migrations 或者有没有使用数据库。
现在执行 python manage.py migrate ,应用 migration 。
现在来总结一下:
1:首先编辑models.py
2:运行 python manage.py makemigrations ,创建 migrations
3:运行 python manage.py migrate ,应用 migrations
为什么要将第二步和第三步拆开呢?这样会使开发变得简单,有效率。
试试API吧!
执行 python manage.py shell 这条指令代替 python 直接打开python环境,是为了设置 DJANGO_SETTINGS_MODULE 环境变量,这个环境变量是告诉Django你所使用的setting。
在现在这个环境中,你可以试试数据库的API了。
>>> from polls.models import Question, Choice
# Import the model classes we just wrote. # 这个系统里还没有提问. >>> Question.objects.all() [] # 创建一个新的提问. # 为默认设置的时区提供支持, Django可以用tzinfo为pub_date提供时间,使用 # timezone.now()来代替datetime.datetime.now() >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # 把对象存入数据库 >>> q.save() # 现在它有id了 >>> q.id 1 # 可以通过python的属性来访问模版字段值. >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # 通过改变属性,调用save来更改值 >>> q.question_text = "What's up?" >>> q.save() # objects.all() 显示数据库中所有的提问. >>> Question.objects.all() [<Question: Question object>]
但是 [<Question: Question object>] 这样的信息对我们毫无帮助,现在让我们为 Question 和 Chocie 类来添加 __str__ 方法
1 class Question(models.Model): 2 # ... 3 def __str__(self): 4 return self.question_text 5 6 class Choice(models.Model): 7 # ... 8 def __str__(self): 9 return self.choice_text
这样不仅方便自己查看,更重要的是在整个Django的自动生成过程都会出现。
__str__是普通的类方法,放我们来加一个自定义的类方法修饰一下。
1 import datetime 2 3 from django.db import models 4 from django.utils import timezone 5 6 7 class Question(models.Model): 8 # ... 9 def was_published_recently(self): 10 return self.pub_date >= timezone.now()
在这里我们加入了 datetime 和 timezone 模块,前者是python标准库的内置模块,后者是Django内置模块
重新打开环境,测试
1 >>> from polls.models import Question, Choice 2 3 # 测试 __str__() 是否工作 4 >>> Question.objects.all() 5 [<Question: What's up?>] 6 7 # Django可以使用关键字参数使用很多查看数据库的API 8 >>> Question.objects.filter(id=1) 9 [<Question: What's up?>] 10 >>> Question.objects.filter(question_text__startswith='What') 11 [<Question: What's up?>] 12 13 # 获取一个今年提出的问题 14 >>> from django.utils import timezone 15 >>> current_year = timezone.now().year 16 >>> Question.objects.get(pub_date__year=current_year) 17 <Question: What's up?> 18 19 # 查看的id不存在,抛出异常 20 >>> Question.objects.get(id=2) 21 Traceback (most recent call last): 22 ... 23 DoesNotExist: Question matching query does not exist. 24 25 #通过主键查找是最常见的情况,所以Django提供了一套和主键看起来一样#的shortcut(不知道这个单单词该如何准确的翻译,是捷径的意思) 26 #下面的语句和Question.objects.get(id=1)意思一样 27 >>> Question.objects.get(pk=1) 28 <Question: What's up?> 29 30 # 确保自定义类方法可以工作 31 >>> q = Question.objects.get(pk=1) 32 >>> q.was_published_recently() 33 True 34 35 # 给Question类一对Choices类. 这叫创建新Choice的对象, 相当于执行 #INSERT语句, 增加选项到集合并返回一个新的Choice对象 36 # Django创建了一个集合来保存这些“外部”的主键关系 37 # (例如 一个提问的选项) 可以通过API连接. 38 >>> q = Question.objects.get(pk=1) 39 40 # 打印选项的集合 41 >>> q.choice_set.all() 42 [] 43 44 # 增加三个选项. 45 >>> q.choice_set.create(choice_text='Not much', votes=0) 46 <Choice: Not much> 47 >>> q.choice_set.create(choice_text='The sky', votes=0) 48 <Choice: The sky> 49 >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0) 50 51 # Choice对象和Question对象通过API联系 52 >>> c.question 53 <Question: What's up?> 54 55 # 反之亦然 56 >>> q.choice_set.all() 57 [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] 58 >>> q.choice_set.count() 59 3 60 61 # 这些API会自动跟随你需要的数据关系 62 # 用双下划线来分隔这些关系 63 # 你可以建立很多层的关系,这是没有限制的 64 # 查找所有pub_date在今年的的Choices 65 # (重用我们分刚刚创建的 'current_year' 变量). 66 >>> Choice.objects.filter(question__pub_date__year=current_year) 67 [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] 68 69 # 删除一个选项 70 >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') 71 >>> c.delete()
Django管理员
创建管理员 python manage.py createsuperuser
按照指示输入用户名,邮箱,密码。
然后运行server python manage.py runserver
打开网站 http://127.0.0.1/8000/admin 各种玩去吧!
如果是英文界面的话,设置setting.py 里的 LANGUAGE_CODE = 'zh-CN' ,就变成中文了。