认认真真学Django,从现在开始。
学习资料来源于官方网站:https://docs.djangoproject.com/en/1.6/
1-新建一个models.py
from django.db import models class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
first_name 和 last_name 是 model 的 fields,对应于生成的数据库中的 column. 上述的Pesron model可以创建如下的数据库的表:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
注释:
1)-表的名称 myapp_person是从模型元数据中自动生成的,但是可以被重写。详见表的名称。
2)-id这个field也是被自动添加的,也是可以重写的。详见下文中的自动生成基本的key fields.
3)-例子中的CREATE TABLE 语句是用的PostgreSQL 语法,主要还是看你settings.py文件中的settings是怎么写的。
2-使用models
定义了models之后,需要告诉django你要使用它。如果你的例子model是在myapp.models,则在settings.py文件中的settings中的INSTALLED_APPS中添加如下:
INSTALLED_APPS = (
#...
'myapp',
#...
)
添加后,请运行python manage.py syncdb, 这个语句实际上就是创建了数据的表(table),如前所述的CREATE TABLE。
3-Fields
fields 是 models中最重要,也是唯一的必须部分。注意避免跟models API重名了,例如clean, save等。
from django.db import models class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100) class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
Field Types:
django用fields来决定以下三件事情:
1)-数据表中的column的数据类型,例如 INTEGER, VARCHAR
2)-渲染一个表单form时默认的HTML中间件(widget)用到的,例如<input type="text">, <select>
3)-django'admin所有的最小的需求,当自动生成表单的时候。
在 model field reference 中有全部的field信息,也可以自己写field,参考writing custom model fields.
每个field都需要根据特点设定自己的一些参数,例如CharField需要有参数max_length,来规定database中的column的 VARCHAR的大小。
也有一些共同那个的参数:
null:如果True, django会把空值作为NULL存在database中。默认值为False
blank:如果True, 这个field允许是空,默认值为False。注意与null值的不同。null值是纯粹与database相关的,而blank是用来作确认用的,例如,如果一个 field 的 blank=True, 表单 form 的确认就会允许这个 field 不填东西,如果 False 则该处必须填写。(可以理解为,先由 blank 来规定此处是否必填, 再由 null 来取值是空存 NULL 给 database 还是非空)
choices:作为某个field的选项的二元数组。如果给出 choices ,默认的表单中间件就会是 select box, 而不是 text field 了,而且选项会被限制为 choices 中给出的值。
有如下的例子:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
数组中的第一个值(FR),是被存进 database 中的值,第二个值是在默认 form 或 自己写的ModelChoiceField 中显示的。假设已经写好一个 model 的对象(database中已经存入数据),get_F00_display方法会对有choices的field的数据显示进行处理,例如:
from django.db import models class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
u'L'
>>> p.get_shirt_size_display()
u'Large'
default:
每个field的默认值。可以是一个值也可以是一个被调用的对象(callable object)。
help_text:
额外的help文字随着form中间件显示。即使你的这个field不会用在form表单上,这样对于文档也是有用的。
primary_key:
如果为True, 这个field是model的主关键字。如果你的model中没有primary_key=True的field,则django会自动给加上一个类型为IntegerField的field来存储主关键字。所以,除非你要重写默认的primary-key这个实现方法,那么就不需要设定primary_key=True。更多请参考Automatic primary key fields.
unique:
如果为True, 则这个field必须是整个table中的唯一的。
以上只是简单的一个介绍,完备的资料请参考common model field option reference.
Automatic primary key fields(自动生成主关键字的field):
默认的,django给每个model都会自动生成下面的field:
id = models.AutoField(primary_key=True)
这是一个自动增加的主关键字。
如果你要自己定义一个primary key,只要你在你需要的field中令primary_key=Ture,一旦django知道你设定了Field.primary_key, 它就不会自动创建id column了。
每个model都确切的需要有一个field , 其primary_key=True.不论是自己声明的,还是自动添加的。
Verbose field names:
除了ForeignKey, ManyToManyFiled, OneToOneField外,每个field类型,都有一个可选择的参数verbose name,它放在参数列表的第一个。如果verbose name没有指定,django会用field的名字自动生成一个,下面这个例子的verbose name是person's first name:
first_name = models.CharField("person's first name", max_length=30)
而下面的则是first name:
first_name = models.CharField(max_length=30)
ForeignKey, ManyToManyField, OneToOneField的第一个参数是model class的名字,所以他们的verbose_name用法如下:
poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")
转换不是把verbose_name的首字母大写,django会在需要的时候自动完成大写转换。
Relationships:
显然,相关联的database是依赖于相关联的tables的。django提供了常见的三种database关联方式:many-to-one, many-to-many, one-to-one。
Many-to-one relationships:
用djangol.db.models.ForeignKey来实现many-to-one关系的。像用其他的field类型一样,把ForeignKey当作你的model的类的属性。
ForeignKey需要一个位置的变量(即与谁建立关系)。例子如下:
from django.db import models class Manufacturer(models.Model):
# ...
pass class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
# ...
在the model field reference中有更详细的介绍。
一个建议(非必须),ForeignKey field的名字最好跟model的名字一样。也可以自己随便起名字,如下:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(Manufacturer)
# ...
注释:ForeignKey field 接受很多别的变量(the model field reference),这些都是可选变量,可以定义这个relationships怎样工作。更多的db的API可以参照Making querise.
Many-to-many relationships:
用ManyToManyField来定义many-to-many关系,像前文所述来使用。也需要一个位置的变量(与谁建立关系)。例如,一个Pizza有多个Topping对象,也就是一个Topping对象对应多个Pizza,同时每个Pizza有多个topping对应,即多对多的关系,可以如下使用:
from django.db import models class Topping(models.Model):
# ...
pass class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
获取更多参考Making querise.
同样建议使用相同名字来命名field,如上例,toppings.
一般来讲,ManyToManyField实例应该是在form表单中编辑的,在上例中,toppings放在Pizza中(而不是Topping有一个pizzas这样的ManyToManyField),这是由于pizaa含有toppings更自然一些,像上例中这样设定,Pizza这个表单会让用户从中选择toppings.
同样有很多非必须的变量,请参照Making querise.
更多many-to-many relationships的fields:
标准的ManyToManyField 对于简单的处理够用了,如果需要在两个model之间进行data的一些联系的话,需要更多的方法。
例如,建立一个app来追踪音乐家和其所属群组间的关系。人与组之间是个多对多的关系,而还有很多的其他数据想要搜集,例如某人加入某组的日期。可以在Group中通过through方法来绑定进来一个Membership,建立起联系,如下:
from django.db import models class Person(models.Model):
name = models.CharField(max_length=128) # On Python 3: def __str__(self):
def __unicode__(self):
return self.name class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership') # On Python 3: def __str__(self):
def __unicode__(self):
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)
注意,Membership中,用ForeignKey来建立与Person和Group的关系。
对于中间model有几个条件:
1)-中间model有且只有一个target model来做ForeignKey
2)-中间model有且只有一个source model来做ForeignKey
3)-唯一的例外是有一个model是他自身的many-to-many relationship, 这样的中间model就可以有2个一样的ForeignKey的model了,但是起作用不同,一个作为target,一个作为source.
4)-上一条情况下,要令symmetrical=False,见the model field reference
下面是一个实例来理解这个through是如何工作的:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<Group: The Beatles>]
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]
与正常的多对多fields不同,不能用add, create, assignment来建立关系:
# THIS WILL NOT WORK
>>> beatles.members.add(john)
# NEITHER WILL THIS
>>> beatles.members.create(name="George Harrison")
# AND NEITHER WILL THIS
>>> beatles.members = [john, paul, ringo, george]
因为用了through,写了一个中间model,所以就不能用add等方法来直接给多对多的关系来写入数据了,必须要用中间model来把target和source的数据连到一起(姑且这样理解),也就是说,没有额外数据->不用through->不用写中间model->可以用add等方法直接操作数据。
同样的原因导致remove()方法不能用,但是可以用clear()方法,如下:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
[]
一旦通过中间model(through)建立了多对多关系型数据库,就可以用query去访问了。
注意体会下面4段代码:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
[<Group: The Beatles>]
# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
[<Person: Ringo Starr]
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'
One-to-one relationships(一对一关系):
用OneToOneField来定义这种关系。当利用主键(primarykey)来拓展另一个model的时候,这种一对一关系型就显得比较重要,也可以说是较常用的。
one-to-one也需要一个位置的参数(与谁连接)。例如你要建立一个places的database,可能包括address, phone等信息,然后在它之上想要加一个school的database,就可以在school的model中添加OneToOneFiled(Places),实际上就是一种继承,毫无疑问是one-to-one的了。
更多信息请参考 the model field reference
很多地方理解不深,代码照搬官方指南,如有错误热盼指正。