快速上手
-
创建项目
django-admin startproject test
-
创建应用
django-admin startapp hello
-
安装应用
在
test/settings.py
中的INSTALLED_APPS
增加hello
:INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello', )
-
处理请求
在
hello/views.py
中增加如下内容:from django.http import HttpResponse def home(request): return HttpResponse("Hello Django!")
-
增加路由
在
test/urls.py
中增加如下内容:urlpatterns = [ url(r'^$', 'hello.views.home'), url(r'^admin/', include(admin.site.urls)), ]
-
启动服务
python manage.py runserver
Model
ORM抽象层,可将Model自动映射成数据库中的表。
Field(字段)
一个Field
就对应数据库中的一个字段(或列)。
Field Type
可自动映射为数据库中字段的类型;如果使用Form,也可自动生成相应的表单以及作相应的表单验证。
Field Options
是传递给Field的参数,可用于指定数据库列的约束、表单验证等。
null与blank
null
作用于数据库。null=True
,表示数据库中该列可为NULL,上层接口不传实参(无缺省值情况下)或者实参为None到数据库中都是NULL。
blank
作用于表单验证。blank=True
,表示表单中该字段不是必须填的(可见admin页面)。
关系
Many-to-one
Model:
class Manufacturer(models.Model):
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
SQLite:
CREATE TABLE "relationships_manufacturer" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT);
CREATE TABLE "relationships_car" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \
"manufacturer_id" integer NOT NULL REFERENCES "relationships_manufacturer" ("id"));
CREATE INDEX "relationships_car_4d136c4a" ON "relationships_car" ("manufacturer_id");
就是普通的外键,
manufacturer
映射成manufacturer_id
。
Many-to-many
Model:
class Topping(models.Model):
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
SQLite:
CREATE TABLE "relationships_pizza" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT);
CREATE TABLE "relationships_topping" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT);
CREATE TABLE "relationships_pizza_toppings" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \
"pizza_id" integer NOT NULL REFERENCES "relationships_pizza" ("id"), \
"topping_id" integer NOT NULL REFERENCES "relationships_topping" ("id"), \
UNIQUE ("pizza_id", "topping_id"));
CREATE INDEX "relationships_pizza_toppings_c3c2621e" ON "relationships_pizza_toppings" ("pizza_id");
CREATE INDEX "relationships_pizza_toppings_3a22b0a0" ON "relationships_pizza_toppings" ("topping_id");
toppings
非数据库字段,而是映射成一张关系表pizza_toppings
(注意Unique约束)。
操作:
t1 = Topping()
t1.save()
p1 = Pizza()
p1.save()
p1.toppings.add(t1)
p1.toppings.create() # create and add
p1.toppings.all()
t1.pizza_set.all() # xxx_set
Toppings.objects.get(id=2).pizza_set.all()
t1.delete() # 关系也会清除
p1.delete() # 关系也会清除
p1.toppings.clear() # 清除关系
t1.pizza_set.clear() # 清除关系
p1.toppings = [] # 清除关系
t1.pizza_set = [] # 清除关系
Extra fields on many-to-many
Model:
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
SQLite:
CREATE TABLE "relationships_person" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(128) NOT NULL);
CREATE TABLE "relationships_group" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(128) NOT NULL);
CREATE TABLE "relationships_membership" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \
"date_joined" date NOT NULL, \
"invite_reason" varchar(64) NOT NULL, \
"group_id" integer NOT NULL REFERENCES "relationships_group" ("id"), \
"person_id" integer NOT NULL REFERENCES "relationships_person" ("id"));
CREATE INDEX "relationships_membership_0e939a4f" ON "relationships_membership" ("group_id");
CREATE INDEX "relationships_membership_a8452ca7" ON "relationships_membership" ("person_id");
参数
through
用来指定关系表Membership
,而非使用按规则自动创建的group_memebers
表,这样就可以往关系表中增加额外字段。
操作:
grp1.members.add(john) # Error
grp1.members.create(name='John') # Error
grp1.members = [john, paul] # Error
grp1.memebers.clear() # 清除所有grp1的关系
不能使用普通many-to-many里面的
add
,create
,=
等操作,官方文档的说法是信息量太少,它搞不定了。。。
One-to-one
Model:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
place_2 = models.OneToOneField(Place)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
name = models.CharField(max_length=50)
def __str__(self): # __unicode__ on Python 2
return "%s the waiter at %s" % (self.name, self.restaurant)
SQLite:
CREATE TABLE "relationships_place" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(50) NOT NULL, "address" varchar(80) NOT NULL);
CREATE TABLE "relationships_restaurant" ("place_id" integer NOT NULL PRIMARY KEY REFERENCES "relationships_place" ("id"), "serves_hot_dogs" bool NOT NULL, "serves_pizza" bool NOT NULL);
CREATE TABLE "relationships_waiter" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(50) NOT NULL, "restaurant_id" integer NOT NULL REFERENCES "relationships_restaurant" ("place_id"));
CREATE INDEX "relationships_waiter_ee9d9d3e" ON "relationships_waiter" ("restaurant_id");
One-to-one = ForeignKey + (unique=True or primary_key=True)
操作:
r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False); r.save()
r.place
p1.restaurant
hasattr(p1, 'restaurant')
r.place = p2; r.save()
p1.restaurant = r
w = r.waiter_set.create(name='Joe'); w.save()
自引用
models.ForeignKey('self')
models.ManyToManyField('self')
自定义主键
缺省情况下,会自动生成主键:
CREATE TABLE "hello_person" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, ...);
也可以自定义,指定primary_key=True
即可:
id = models.AutoField(primary_key=True)
数据库导入、导出
-
从文件导入
python manage.py loaddata init.yaml # 可以是json,xml,yaml格式
-
从默认文件导入
执行
migrate
时会自动读取initial_data.[xml/yaml/json]
文件并导入。首次migrate要加参数(因为表还没建,无法导入数据),否则会报错:
python manage.py migrate --no-initial-data
-
Data Migrations
文件导入的方法已废弃,但在Django 1.8.2中还可以工作。 1.9开始应该就只能用Migrations来导入数据了。
首先,创建一个新的migration文件模板,比如
migrations/0004_initial_data.py
:python manage.py makemigrations --empty hello -n initial_data
然后,编辑成如下:
def load_data(apps, schema_editor): Person = apps.get_model("hello", "Person") db_alias = schema_editor.connection.alias Person.objects.using(db_alias).bulk_create([ Person(first_name="Michael", last_name="Jordan"), Person(first_name="Kobe", last_name="Bryant"), Person(first_name="LeBron", last_name="James"), ]) class Migration(migrations.Migration): dependencies = [ ('hello', '0003_person_addr'), ] operations = [ migrations.RunPython( load_data, ), ]
最后,执行migrate即可。
Why Data Migrations?
这样就不会出现Model更新后,初始化数据和Model不匹配的问题。
-
导出
python manage.py dumpdata # 导出全部 python manage.py dumpdata APP # 仅导出app python manage.py dumpdata APP.MODEL # 仅导出app.model python manage.py dumpdata APP.MODEL --format yaml # 默认json格式