django database relations
注意Django的生成的默认api
from django.db import models class Place(models.Model): '''
pass class Restaurant(models.Model): place = models.OneToOneField( Place, on_delete=models.CASCADE, primary_key=True, ) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) def __str__(self): # __unicode__ on Python 2 return "%s the restaurant" % self.place.name class Waiter(models.Model): restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE) name = models.CharField(max_length=50) def __str__(self): # __unicode__ on Python 2 return "%s the waiter at %s" % (self.name, self.restaurant)
place_instance.restaurant 引用对应的 restaurant,为 Model `Restaurant`名称的 lower() 形式
restaurant.place,通过字段名称 `place` 引用
restaurant_instance.waiter_set 与 restaurant_instance.waiter 有什么不同?
现在发现时有 Manytomany 的一边引用另一个 model,不需要加 _set,反之,需要加 _set。两者都是相互引用的名称,没有区别
related_name 中可以定义这个名称,在 Manytomany 中两边的名称分别是什么?
django 官方教程
Django OneToOneField, ManyToManyField, Foreign Key
Imagine a database, which stores your book collection:
from django.db import models class Place(models.Model): address = models.CharField(max_length=50) country = models.CharField(max_length=50) class Publisher(models.Model): name = models.CharField(max_length=30) place = models.OneToOneField(Place, primary_key=True) class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) class Book(models.Model): title = models.CharField(max_length=100) publisher = models.ForeignKey(Publisher) authors = models.ManyToManyField(Author)
One-to-many/Foreign Key
Every Book has one Publisher, but a Publisher might have published multiple books. Therefore they are in a one-to-many (book-to-publisher) relationship. So,
class Book(models.Model):
publisher = models.ForeignKey(Publisher, realted_name='books')
should be read: "Book is the foreign key of publisher". `publisher` is a attribute of book, a book only has one publisher, `book.publisher` is a instance of `Publisher`.
`publisher` can access books by related_name `books`, `publisher.books` is a queryset of `Book`.
外键是 one to many 中 many 的一方, related_name 是 Publisher 访问 Book 的名称,是单获取多的名字。
外键的自联接
class City(BaseModel): ''' 城市 ''' name = models.CharField(max_length=64, verbose_name='名称') # 从1开始 level = models.SmallIntegerField(null=True, blank=True, verbose_name='级别') search_count = models.IntegerField(default=0, verbose_name="搜索次数") upper_city = models.ForeignKey('self', related_name='sub_cities', on_delete=models.CASCADE)
以国家--省--市的级别。
如广东省
广东省.upper_city = 中国 广东省.sub_cities = City Queryset [广州、深圳、珠海]
One-to-one
Every Publisher is located in one Place, and every Place can only hold one Publisher. Therefore they are in a one-to-one relationship. You could just have well have put the Place information (address and country) with the Publisher model in one table, but sometimes it is preferred to have seperate models. For example, if you do not know the Place for every Publisher, you don't need to take up a lot of space with empty rows.
Many-to-many
Every Book also has one or more Authors. However, an Author might have written multiple Books, so they are in a many-to-many relationship.
If you still need some guidance, I suggest taking a look at the model chapter of the Django Book.
The apis of different relations
base apis
manytomany
见 Related objects reference
add
remove
clear 等等
问:Related objects reference 中的方法是怎么实现的?
首先要弄懂 Foreignkey 的方法是怎么实现的
问:弄懂 Foreignkey 的方法是怎么实现的
1. 两个 models 之间如何相互引用的?
2. 增删查改
如何通过 intermediary model 取出数据?
通过对应的字段 id 取出,见 Associative_entity
intermediary model 的作用
可以用来储存关系之外的信息,比如这个关系的建立日期,建立条件等
用来取到不同的值,比如默认是取 pk,但是现在能取到 username
遇到的问题
AttributeError}Cannot set values on a ManyToManyField which specifies an intermediary model.
原因:many2many 自带的 api 不再适用
Unlike normal many-to-many fields, you can't use add, create, or assignment (i.e., beatles.members = [...]) to create relationships
解决:
在中间表加上
class Membership(models.Model): class Meta: auto_created = True
问:Django 自带的 ManyToManyField 是如何实现的,有没有使用 intermediary model?
搜索了一下,没有找到满意的答案。于是查看添加 ManyToManyField 后的 sql 语句。
下面是将一个 CharField 改为 ManyToManyField 后,Django 生成的 sql 语句
app_name: business, related_model_name: Client, Industry
BEGIN; -- -- Remove field industry from client -- ALTER TABLE `business_client` DROP COLUMN `industry` CASCADE; -- -- Add field industry to client -- CREATE TABLE `business_client_industry` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `client_id` integer NOT NULL, `industry_id` integer NOT NULL); ALTER TABLE `business_client_industry` ADD CONSTRAINT `business_client_industr_client_id_0cf3c644_fk_business_client_id` FOREIGN KEY (`client_id`) REFERENCES `business_client` (`id`); ALTER TABLE `business_client_industry` ADD CONSTRAINT `business_client_ind_industry_id_4e2c4fda_fk_business_industry_id` FOREIGN KEY (`industry_id`) REFERENCES `business_industry` (`id`); ALTER TABLE `business_client_industry` ADD CONSTRAINT `business_client_industry_client_id_06a60532_uniq` UNIQUE (`client_id`, `industry_id`); COMMIT;
从上面可以看出:
1. ManyToManyField 也生成了一个中间表 CREATE TABLE `business_client_industry`
2. 在中间表中创建外键
3. 自动增加了一个 UNQUE 约束
问:为什么使用 intermediary model 时不能使用 clear 之外的方法?
既然同样都是通过中间表引用,为什么到了这里那些方法就不能用了呢?
实际测试一下再来作答
因为要建立联系,必须要在中间表中建立数据。而 clear 之外的那些方法做不到。
You can’t just create a relationship between a
Person
and aGroup
- you need to specify all the detail for the relationship required by theMembership
model. The simpleadd
,create
and assignment calls don’t provide a way to specify this extra detail. As a result, they are disabled for many-to-many relationships that use an intermediate model. The only way to create this type of relationship is to create instances of the intermediate model.
clear 为什么能做到?
clear 是将那个属性设置为 None,只是破坏单边关系吧?为什么说破坏了 many to many relationship?
是不是一边为空就会破坏 many to many 的关系?
问:如何做城市选择?
问:Django model循环引用
解决:http://stackoverflow.com/questions/4813293/django-python-circular-model-reference
原理: 懒加载