1)关于模型类属性的类型,和数据库中的类型有对应关系,但事实上django扩展了一些新的类型。这些类型最终还是会被转化成数据库支持的类型,但这些新类型会自动获得一些验证的作用(提交表单时,会进行正则匹配)。
CharField和TextField都是保存文本,但CharField是定长的,而TextField的长度则可以是无限的。EmailField、URLField和IPAddressField这三个变量其实就是在CharField加上一点额外的验证。BooleanField和NullBooleanField的区别是后者允许为空。FileField是最复杂的变量之一,它只在数据库是保存了一个文件的路径。
2)模型之间的关系。ForeignKey()可以传模型类进去,也可以传字符串进去,如果传模型类进去,那么模型必须在被传之前先定义,如果传模型进去,那么模型定义的顺序就没有要求了。
class Author(models.Model):
>> name = models.CharField(max_length=100)
class Book(models.Model):
>> title = models.CharField(max_length=100)
>> author = models.ForeignKey(Author) #=> Author必须在前面先定义
=================================================================
class Book(models.Model):
>> title = models.CharField(max_length=100)
>> author = models.ForeignKey(‘Author’) #=> Author不必在前面先定义
class Author(models.Model):
>> name = models.CharField(max_length=100)
3)虽然ForeignKey只定义了关系的一端,不过另一端却能根据关系追溯回来(和rails两边都要写has_one不同)。外键从技术上说是一个“多对一”的关系,即可以有多个子对象引用同一个父对象。因此子对象只有一个父对象的引用,而父对象却能访问到一组子对象。
book = Book.objects.get(title="Myby Dick")
author = book.author
books = author.book_set.all()
可以看到从Author到Book的“反向关系”是通过Author.book_set属性来表示的,你可以通过在ForeignKey里指定related_name参数来改变它的名字。在上面的例子里,我们如果把author定义成ForeignKey("Author",related_name="books")的话,最后就是访问author.books而不是author.book_set了。
对于简单的对象层次来说,related_name不是必需的,但是在更复杂的关系里,比如当你有多个ForeignKey的时候就一定要指定了。这时,ORM需要你明确告诉它在ForeignKey的另一端如何区分两个不同的反向关系。如果你忘了的话,Django的数据库管理工具会抛出错误信息警告你!
4)处理多对多关系可以用ManyToManyField,它的用法和外键关系里的“多”的那一端差不多:
book = Book.objects.get(title="Python")
authors = book.author_set.all()
books = authors[2].book_set.all()
5)一对一可以用OneToOneField。
6)ForeignKey和ManytoManyField都可以指定一个limit_choices_to参数,它是个字典类型,用以限制关系。
class Author(models.Model):
>> name = models.CharField(max_length=100)
class SmithBook(models.Model):
>> title = models.CharField(max_length=100)
>> authors = models.ManyToManyField(Author,limit_choices_to={'name_endswith':'Smith'})
7)django的模型对应的是数据库中的表,而模型其实是类,可以被继承的。在django中模型继承有两种方式,一种称为抽象继承,另一种称为多表继承。抽象继承是让基类成为抽象类,不会对应数据库中的表,而多表继承就是普通的python类继承,基类并非抽象类,也会对应于数据库中的表。抽象类是如何实现的呢?是依靠在Meta嵌套类中设置abstract=True实现的。
class Author(models.Model):
>> name = models.CharField(max_length=100)
class Book(models.Model):
>> title = models.CharField(max_length=100)
>> genre = models.CharField(max_length=100)
>> num_pages = models.IntegerField()
>> authors = models.ManyToManyField(Author)
>> class Meta:
>>>> abstract = True
class SmithBook(Book):
>> authors = models.ManyToManyField(Author,limit_choices_to={'name_endswith':'Smith'})
给Book的Meta嵌套类设置了abstract=True,所以在创建数据库的时候,只会有Author和SmithBook两张表。如果去掉abstract,那么即为多表继承,包括Book在内,会创建三张表。
8)django用manage.py syncdb来同步数据库,但它只关心“有无数据库表”,不关心“是否修改了数据库表”,如果没有,那么创建。如果已经有了,就不再关心。所以如果对模型进行修改了,再运行syncdb,不会同步我们的修改的。需要手动修改数据库,或者干脆删除表甚至数据库,重新创建。
9)模型类的常用查询方法有如下这些:
1》all() 返回所有
2》filter() 返回满足条件的所有(复数形式)
3》exclude() 和filter()正相反,不满足条件的所有
4》get() 获取单个符合条件的记录(没找到或有超过一个结果都会抛出异常)
5》order_by() 排序
6》distinct() 去重
10)给filter()等方法传参,除了name="adang"之类的,还可以用下划线连接一些特殊字符来拼成特定的sql语句。例如name__contains="adang"、age_gt=25,此外还有icontains(大小写无关的LIKE),startswith、endswith、in等。
11)查询返回的数据类型为QuerySet,它和列表很像,但有所不同,包括[:]等方法都是改造后的,比起列表会更节约内存。