一般一个模型映射一张单独的数据表。
基本概念:python
下面的模型定义了一个“人”,它具备first_name和last_name属性git
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
上面的代码,至关于下面的原生sql语句:sql
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
注意:数据库
建立了model以后,在使用它以前,你须要先在settings文件中的INSTALLED_APPS 处,注册models.py文件所在的APP。例如:django
INSTALLED_APPS = [ #... 'myapp', #... ]
当你每次在INSTALLED_APPS处增长新的APP时,请务必执行命令python manage.py migrate
。有可能要先make migtrations。app
model中最重要也是必须定义的部分。请不要使用clean、save、delete等model API内置的名字,防止命名冲突。
范例:ide
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, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
fileds类型的做用:工具
<input type=“text” />
在admin后台和自动生成的form表单中最小的数据验证需求网站
3.22节《Making queries》
6.15节《model field reference》《Field API reference》
4.3节《Writing custom model fields.》ui
AutoField
一个自动增长的整数类型。一般你不须要使用它,Django自动帮你添加下面的字段:
id = models.AutoField(primary_key=True)
BigAutoField
(1.10新增)
64位整数,相似AutoField。1 to 9223372036854775807
BigIntegerField
64位整数,相似IntegerField ,-9223372036854775808 to 9223372036854775807。
在默认的form类型是textinput(用django的form功能自动生成的input标签)。
BinaryField
二进制数据类型。使用受限,慎用。
BooleanField
布尔值类型。默认值是None。
默认的form类型是input checkbox。
若是要接收null值,请使用NullBooleanField。
CharField
字符串类型。必须接收一个max_length参数。
默认的form类型是input text。
最经常使用的filed!
CommaSeparatedIntegerField
逗号分隔的整数类型。必须接收一个max_length参数。
经常使用于表示较大的金额数目,例如1,000,000元。
DateField
class DateField(auto_now=False, auto_now_add=False, **options)
日期类型。
一个Python中的datetime.date的实例。
在form中的默认类型是text。在admin后台,Django会帮你自动添加一个js的日历表和一个“Today”快捷方式,以及附加的日期合法性验证。
参数:(全部参数互斥,不能共存)
auto_now:每当对象被保存时将字段设为当前日期,经常使用于保存最后修改时间。
注意,只有在使用save()方法时才更新,其它操做不更新。
auto_now_add:每当对象被建立时,设为当前日期,经常使用于保存建立日期。
注意,它是不可修改的。
设置上面两个参数就至关于给field添加了editable=False and blank=True属性。若是想具备修改属性,请用default参数:
对于 DateField: default=date.today - from datetime.date.today()
对于 DateTimeField: default=timezone.now - from django.utils.timezone.now()
DateTimeField
class DateTimeField(auto_now=False, auto_now_add=False, **options)
日期时间类型。
Python的datetime.datetime的实例。与DateField相比就是多了小时、分和秒的显示,其它功能、参数、用法、默认值等等都同样。
DecimalField
class DecimalField(max_digits=None, decimal_places=None, **options)
固定精度的十进制小数。
至关于Python的Decimal实例,必须提供两个指定的参数!
参数:
max_digits:最大的位数,必须大于或等于小数点位数
decimal_places:小数点位数,精度。
范例:储存最大不超过999,带有2位小数位精度的数,定义以下:
models.DecimalField(..., max_digits=5, decimal_places=2)
5来自3+2!
当 localize=False,它在form中默认为NumberInput 类型。不然,是text类型。
DurationField
持续时间类型
存储必定期间的时间长度。相似python中的timedelta。在不一样的数据库实现中有不一样的表示方法。经常使用于进行时间之间的加减运算。可是当心了,这里有坑,PostgreSQL等数据库之间有兼容性问题!
EmailField
class EmailField(max_length=254, **options)
邮箱类型。
使用EmailValidator进行合法性验证。
FileField
class FileField(upload_to=None, max_length=100, **options)
上传文件类型
Field options选项
详细看6.15节《field option》
除了相似max_length是对CharFiled的必须参数外。还有一些是可选的经常使用参数:
choices:用于选择框,须要先提供一个二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容。例如:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
要显示一个choices的值,可使用get_FOO_display()方法,其中的FOO用字段名代替。
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 'L' >>> p.get_shirt_size_display() 'Large'
primary_key:主键。设置为True时,当前字段变为主键,并关闭Django自动生成的id主键功能。另外,主键字段不可修改,若是你赋个新值则会建立个新记录。
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
fruit = Fruit.objects.create(name='Apple')
fruit.name = 'Pear'
fruit.save()
Fruit.objects.values_list('name', flat=True)
['Apple', 'Pear']
unique:true时,在整个表内该字段的数据不可重复。
默认状况下,Django给你提供了自动的主键:
id = models.AutoField(primary_key=True)
除了外键、多对多和一对一字段外,全部的字段均可以有一个可选的第一位置参数:verbose name。若是没给这个参数,Django会利用字段的属性名自动建立它,并将下划线转换为空格。
下面这个例子verbose name是"person’s first name":
first_name = models.CharField("person's first name", max_length=30)
下面这个例子verbose name是"first name":
first_name = models.CharField(max_length=30)
对于外键、多对多和一对一字字段,因为第一个参数须要用来指定模型类,所以必须用关键字参数verbose_name来指定详细名。以下:
poll = models.ForeignKey( Poll, on_delete=models.CASCADE, verbose_name="the related poll", ) sites = models.ManyToManyField(Site, verbose_name="list of sites") place = models.OneToOneField( Place, on_delete=models.CASCADE, verbose_name="related place", )
from django.db import models class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ...
外键关系字段放在多的一方,好比上面的多种汽车出自同一厂商。
也能够建立递归关系(本身多对一关联本身,使用self做为指向的模型名),或者关联到还没有建立的模型。
建议将外键字段名设置为关联类的小写名称。非强制。
更多ForeignKey相关,请查看6.15节《the model field reference》
from django.db import models class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
同一对一同样,也能够创建递归的本身关联本身的多对对,或关联到一个还没有定义的模型。
建议将字段名取成关联模型的小写复数,例如toppings。
多对多字段放在关联双方的任何一方均可以,可是只能在一方,不能同时。但一般会考虑现实的逻辑,将其放在更符合基本状况的一方。
更多ManyToManyField相关,请查看6.15节《the model field reference》
from django.db import models 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, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
对于中间模型,有一些限制:
from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64)
下面是一些使用例子:
>>> 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() <QuerySet [<Person: Ringo Starr>]> >>> ringo.group_set.all() <QuerySet [<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() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
与普通的多对多不同,使用中间模型的多对多不能使用add(), create(),remove(), 和set()方法来建立、删除关系,看下面:
>>> # 无效 >>> beatles.members.add(john) >>> # 无效 >>> beatles.members.create(name="George Harrison") >>> # 无效 >>> beatles.members.set([john, paul, ringo, george])
为何?由于上面的方法没法提供加入时间、邀请缘由等中间模型须要的字段内容。惟一的办法只能是经过建立中间模型的实例来建立这种类型的多对多关联。
可是clear()方法是有效的,它能清空全部的多对多关系。
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() <QuerySet []>
一旦你经过建立中间模型实例的方法创建了多对多的关联,你马上就能够像普通的多对多那样进行查询操做:
# Find all the groups with a member whose name starts with 'Paul' >>> Group.objects.filter(members__name__startswith='Paul') <QuerySet [<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)) <QuerySet [<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 '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 'Needed a new drummer.'
举例,你设计一个“场所”的模型,包括地址、电话等等。而后,你又想建立一个基于“场所”的餐馆模型,你不须要重复上面的场所的字段,只须要在餐馆模型中创建一个OneToOneField关联到“场所”模型。(事实上,一般咱们会使用继承的方法,它隐含了一个一对一关系)。
一样,一对一也能够递归关联本身,或关联未定义模型。
一对一还有一个可选的parent_link参数。
直接在文件顶部导入其它模块内的模型,而后正常使用!
from django.db import models from geography.models import ZipCode class Restaurant(models.Model): # ... zip_code = models.ForeignKey( ZipCode, on_delete=models.SET_NULL, blank=True, null=True, )
可是SQL的保留字,如join、where和select是能够用的。
参考4.3《Writing custom model fields》
方法:在模型内部建立class Meta
from django.db import models class Ox(models.Model): horn_length = models.IntegerField() class Meta: ordering = ["horn_length"] verbose_name_plural = "oxen"
metadata:指的是“任何非字段相关的内容”,例如排序依据(ordering),表名(db_table),或者人类可读的单数、复数名((verbose_name and verbose_name_plural)。全部的都是可选,非必须的。完整的参考表见6.15.6《model option reference》
objects:对于一个模型,最重要的属性是Manager(管理器)。它是模型用来查询、操做数据的接口。若是没有自定义Manager,那么它的默认名字就是“objects”。它只能经过类名进行访问,不能经过类的实例访问。
下面是在模型中自定义方法的实例:
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" elif self.birth_date < datetime.date(1965, 1, 1): return "Baby boomer" else: return "Post-boomer" def _get_full_name(self): "Returns the person's full name." return '%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name) # 将方法转换为属性
下面是2个经常使用的常常被定义的方法:
str():python3版本,在打印模型时,指定显示的内容。
get_absolute_url():Django用它来获取对象的URL,每个包含URL的对象都必须定义这个方法。参考6.15.
例如,你想在save()方法执行先后先干点什么:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): do_something() # 调用内置的save()方法 super(Blog, self).save(*args, **kwargs) do_something_else()
或者阻止某些人没法进行save()。
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): if self.name == "Yoko Ono's blog": # 叫这个名字的博客没法保存 return else: # 其它的正常保存 super(Blog, self).save(*args, **kwargs)
注意三点:
全部的模型类必须继承django.db.models.Model。
Django有三种继承的方式:
值须要在Meta类里添加abstract=True,就能够将一个模型转换为抽象基类。Django不会为这种类建立实际的数据库表,他们也没有管理器,不能被实例化也没法直接保存,它们就是用来被继承的。例如:
from django.db import models class CommonInfo(models.Model): name = models.CharField(max_length=100) age = models.PositiveIntegerField() class Meta: abstract = True class Student(CommonInfo): home_group = models.CharField(max_length=5)
student模型将有name,age,home_group三个字段。基类和子类不能有同样的字段名。
Meta的继承:
若是子类没有声明本身的Meta类,那么它将继承抽象基类的Meta类。下面的例子则扩展了基类的Meta:
from django.db import models class CommonInfo(models.Model): # ... class Meta: abstract = True ordering = ['name'] class Student(CommonInfo): # ... class Meta(CommonInfo.Meta): db_table = 'student_info'
抽象基类也能够继承别的抽象基类,但不要忘记在Meta类里添加abstract=True。这个选项才是决定一个类是普通的类仍是抽象基类的根本。
区别related_name和related_query_name,当你在抽象基类中使用时应该包含’%(app_label)s’和’%(class)s’:
例如,对于common/models.py模块:
from django.db import models class Base(models.Model): m2m = models.ManyToManyField( OtherModel, related_name="%(app_label)s_%(class)s_related", related_query_name="%(app_label)s_%(class)ss", ) class Meta: abstract = True class ChildA(Base): pass class ChildB(Base): pass
对于另一个模块rare/models.py:
from common.models import Base class ChildB(Base): pass
对于上面的继承关系:
具体时候什么名字,取决你如何经过‘%(class)s’‘ and ’%(app_label)s构造名称字符串。可是,若是你忘了这个技术细节,那么在使用时会弹出异常。
这种继承方式,父类和子类都有本身的数据库表,内部隐含了一个一对一的关系。例如:
from django.db import models class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) class Restaurant(Place): serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False)
Restaurant类将包含Place类的字段,而且各有各的数据库表和字段,好比:
>>> Place.objects.filter(name="Bob's Cafe") >>> Restaurant.objects.filter(name="Bob's Cafe")
若是一个Place同时也是一个Restaurant,你可使用小写的子类名,在父类中访问它,例如:
>>> p = Place.objects.get(id=12) # If p is a Restaurant object, this will give the child class: >>> p.restaurant <Restaurant: ...>
可是,若是这个Place是个纯粹的Place,并非一个Restaurant,那么上面的调用方式会报错Restaurant.DoesNotExist。
Meta和多表继承
在多表继承的状况下,因为父类和子类都在数据库内有物理存在的表,父类的Meta类会对子类形成很差的影响,所以,Django在这种状况下关闭了子类继承父类的Meta功能。这一点和抽象基类的继承方式有所不一样。
可是,还有2个meta元素特殊一点,那就是ordering和get_latest_by,这两个参数是会被继承的。所以,若是在多表继承中,你不想让你的子类继承父类的上面两种参数,就必须在子类中显示的指出或重写。以下:
class ChildModel(ParentModel): # ... class Meta: # 移除父类对子类的排序影响 ordering = []
继承和反向关联
由于多表继承使用了一个隐含的OneToOneField来连接子类与父类,因此象上例那样,你能够用父类来指代子类。可是这个OnetoOneField字段默认的related_name值与ForeignKey和 ManyToManyField默认的反向名称相同。若是你与该父类的另外一个子类作多对一或是多对多关系,你就必须在每一个多对一和多对多字段上强制指定related_name。若是你没这么作,Django就会在你运行或验证(validation)时抛出异常。
仍以上面Place类为例,咱们建立一个带有ManyToManyField字段的子类:
class Supplier(Place): customers = models.ManyToManyField(Place)
这会产生下面的错误:
Reverse query name for 'Supplier.customers' clashes with reverse query name for 'Supplier.place_ptr'. HINT: Add or change a related_name argument to the definition for 'Supplier.customers' or 'Supplier.place_ptr'.
解决方法是:向customers字段中添加related_name:models.ManyToManyField(Place, related_name='provider')。
指定连接父类的字段
以前提到,Django会自动建立一个OneToOneField字段将子类连接至非抽象的父model 。若是你想指定连接父类的属性名称,你能够建立你本身的OneToOneField字段并设置 parent_link=True,从而使用该字段连接父类。
使用多表继承时,父类的每一个子类都会建立一张新数据表,一般状况下,这正是咱们想要的操做。这是由于子类须要一个空间来存储不包含在基类中的字段数据。但有时,你可能只想更改model在Python层的行为。好比:更改默认的manager,或是添加一个新方法。
代理模型能够实现这一点:为原始模型建立一个代理 。你能够建立,删除,更新代理model 的实例,并且全部的数据均可以像使用原始model同样被保存。不一样之处在于:你能够在代理model中改变默认的排序设置和默认的manager,而不会对原始model产生影响。
声明代理模型和声明普通模型没有什么不一样。设置Meta类中proxy的值为True,就完成了对代理模型的声明。
举例,假设你想给Person模型添加一个方法。你能够这样作:
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) class MyPerson(Person): class Meta: proxy = True def do_something(self): # ... pass
MyPerson类将操做和Person类同样的数据库表。而且,任何新的Person实例均可以经过MyPerson类进行访问,反之亦然。
>>> p = Person.objects.create(first_name="foobar") >>> MyPerson.objects.get(first_name="foobar") <MyPerson: foobar>
下面是经过代理实现排序,但原父类不排序的方法:
class OrderedPerson(Person): class Meta: ordering = ["last_name"] proxy = True
如今,普通的Person查询是无序的,而OrderedPerson查询会按照last_name排序。
查询集始终返回请求的模型
也就是说,没有办法让django在查询Person对象时返回MyPerson对象。Person对象的查询集会返回相同类型的对象。代理对象的要点是:它会使用依赖于原生Person的代码,而你可使用你添加进来的扩展对象(它不会依赖其它任何代码)。而并非将Person模型(或者其它)在全部地方替换为其它你本身建立的模型。
基类的限制
代理模型管理器
如不指定,则继承父类的管理器。若是你本身定义了管理器,那它就会成为默认管理器,可是父类的管理器依然有效。以下例子:
from django.db import models class NewManager(models.Manager): # ... pass class MyPerson(Person): objects = NewManager() class Meta: proxy = True
若是你想要向代理中添加新的管理器,而不是替换现有的默认管理器,你可使用自定义管理器管理器文档中描述的技巧:建立一个含有新的管理器的基类,并继承时把他放在主基类的后面:
# Create an abstract class for the new manager. class ExtraManagers(models.Model): secondary = NewManager() class Meta: abstract = True class MyPerson(Person, ExtraManagers): class Meta: proxy = True
代理继承与非托管模型之间的差别
代理继承看上去和使用Meta类中的managed属性的非托管模型很是类似。
在建立非托管模型时要谨慎设置Meta.db_table,这是由于建立的非托管模型映射某个已存在的模型,而且有本身的方法。若是你要保证这两个模型同步并对程序进行改动,那么就会变得繁冗而脆弱。
通常规则是:
注意,多重继承和多表继承是两码事,两个概念。
Django的模型体系支持多重继承,就像Python同样。同时,通常的Python名称解析规则也会适用。出现特定名称的第一个基类(好比Meta)是所使用的那个,这意味着若是多个父类都含有 Meta类,只有第一个父类的会被使用,剩下的会忽略掉。
一般,你不须要使用多重继承。最经常使用的状况是“混入”(mix-in):为每个继承了minx-in的类添加一个特别额外的字段或方法。
可是,尽可能让你的继承关系简单和直接,避免没必要要的混乱和复杂。
请注意,继承同时含有相同id主键域的类将抛出异常。为了解决这个问题,你能够在基类模型中显式的使用AutoField字段。以下例子所示:
class Article(models.Model): article_id = models.AutoField(primary_key=True) ... class Book(models.Model): book_id = models.AutoField(primary_key=True) ... class BookReview(Book, Article): pass
或者使用一个共同的祖先来持有AutoField字段,以下所示:
class Piece(models.Model): pass class Article(Piece): ... class Book(Piece): ... class BookReview(Book, Article): pass
在python中,子类能够重写全部的父类属性。但在Django中却不必定。若是一个非抽象模型基类有一个叫作author的字段,那么在它的子类中,你不能建立任何也叫作author的模型字段或属性(这个限制对抽象模型无效)。这些字段有可能被另外的字段或值重写,或经过设置filed_name=None而被移除。
警告:模型管理器继承自抽象基类。重写一个被继承管理器引用的继承字段可能致使小bug。参考3.2《Custom managers and model inheritance》
注意:一些字段会在模型上定义一些额外的属性,例如ForeighKey会定义一个额外的属性(将"_id"附加在字段名上)。就像related_name和related_query_name同样。这些额外的属性不可被重写,除非定义他们的字段被改变或移除了。
重写父类的字段会致使不少麻烦,好比:初始化实例(指定在Model.__init__中被实例化的字段)和序列化。而普通的Python类继承机制并不能处理好这些特性。因此Django的继承机制被设计成与Python有所不一样,这样作并非随意而为的。
这些限制仅仅针对作为属性使用的Field实例,并非针对Python属性,Python属性还是能够被重写的。 在 ython看来,上面的限制仅仅针对字段实例的名称:若是你手动指定了数据库的列名称,那么在多重继承中,你就能够在子类和某个祖先类当中使用同一个列名称。(由于它们使用的是两个不一样数据表的字段)。
若是你在任何一个祖先类中重写了某个 model 字段,Django 都会抛出 FieldError异常。
manage.py startapp命令的执行会建立一个app的文件结构,并包含一个models.py文件。可是,若是你有不少模型,那么将它们分隔放在不一样的文件中会是个好主意。
想这么作,只须要建立一个模型包。首先,移除models.py文件,再创建一个myapp/models/目录,在目录里建立个__init__.py文件,最后建立存放模型的文件。你必须在__init__.py中导入那些模型models。
例如,若是你有一个organic.py和synthetic.py文件在models目录里,那么,init.py文件里应该这么写代码:
myapp/models/init.py
from .organic import Person from .synthetic import Robot
在文件中显式的导入每个模型比使用from .models import * 这种一股脑的导入方式更好,这样不会致使命名空间的混乱,让代码更可读,更利于代码分析工具进行检查。
更多请查看6.15节的Models,这里包含了全部的API和细节,很长很长的文档.....