Django学习笔记〇五——DJango中ORM的外键的使用
我们在前面讲了Django中ORM的大致使用方法,我们今天要了解一些常用的外键的使用方法。
一对多的模型
我们在建立模型的时候可以直接在类中对外键直接定义好。结合在下一章要用的案例,我们做这样一个一对多的数据库模型
因为一个出版社可以对应很多本书籍,这就是最常见的一个一对多的外键模型。
用代码反应出来这两个类,就是这样的:
class Publisher(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(null = False,max_length=16) class Books(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(null=False,max_length=32) publisher = models.ForeignKey(to='Publisher',on_delete=models.CASCADE)
注意books里的字段——我们在创建的时候是定义的publisher,但是通过makemigrations和migrate创建的表的对应字段看看MySQL里的字段
那个publusher自动加了个_id,我们还可以下面的代码查一下app_books这个表的创建代码来了解一下table的结构。
show create table app_books;
CREATE TABLE `app_books` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(32) NOT NULL, `publisher_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `app_book_publisher_id_74fff6a5_fk_app_publisher_id` (`publisher_id`), CONSTRAINT `app_book_publisher_id_74fff6a5_fk_app_publisher_id` FOREIGN KEY (`publisher_id`) REFERENCES `app_publisher` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
查询
下面几种方法写明了通过外键获取指定字段的一步步的过程(分步说明,当然可以直接用最后一个方法),比方我们要知道某本书籍对应的出版社,就可以这么做:
#获取book对象 book = models.Books.objects.get(id=3) #获取book对象内指定的字段publisher_id(外键) publisher_id = book.publisher_id # 获取book对象对应的publisher对象 publisher_obj = book.publisher #获取book对象获取通过外键映射到另外表的指定字段 publisher = book.publisher.name
反向查询
但是如果我们想了解某个出版社出版了那些书,SQL的语句是这样的:
select * from app_books left join app_publisher on app_books.publisher_id=app_publisher.id where app_publisher.name='机械工业出版社';
又该怎么做呢?下面只放下核心代码
publisher = models.Publisher.objects.get(name = '机械工业出版社') books = publisher.books_set.all() print(type(books)) for book in books: print(book.title)
这样就可以打印出指定的出版社出版了哪些书。知道这里,我才发现了Django的牛X之处。
下面我们再看看多对多的外键是怎么使用的。补充一下数据库模型
在上面的表中补充一个作者表,书籍和作者的对应关系,有可能一个书是几个作者同时写的,也有可能一个作者写了好几本书。为了把书籍和作者关联起来,就要建立第三个表——book_to_author
看看两个类是怎么构建的
class Books(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(null=False,max_length=32) publisher = models.ForeignKey(to='Publisher',on_delete=models.CASCADE) #这里在创建的时候ORM会直接把外键的名字设置为publisher_id class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(null=False,max_length=10,unique=True) book = models.ManyToManyField(to='Books') #用了多对多的关联
可以发现,Books的代码跟前面的是一样的,但是在author里定义了一个多对多的外键——ManytoManyField
通过manage.py文件刷新一下数据库,可以发现多出来了一个table
看看author表和author_books表的构造方法
mysql> show create table app_author; +------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | app_author | CREATE TABLE `app_author` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 | +------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
mysql> show create table app_author_book; +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | app_author_book | CREATE TABLE `app_author_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `author_id` int(11) NOT NULL, `books_id` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `app_author_book_author_id_books_id_226f32e6_uniq` (`author_id`,`books_id`), KEY `app_author_book_books_id_92880518_fk_app_books_id` (`books_id`), CONSTRAINT `app_author_book_author_id_ac226197_fk_app_author_id` FOREIGN KEY (`author_id`) REFERENCES `app_author` (`id`), CONSTRAINT `app_author_book_books_id_92880518_fk_app_books_id` FOREIGN KEY (`books_id`) REFERENCES `app_books` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 | +-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec)
仔细看一下,还有一个表:app_author_book,这个表其实不是我们通过类直接创建的,而是通过ManytoManyField的方式直接创建的。
正向查询
因为我们是通过author表里的属性关联到book的,那么从author获取到book就是正向查询,比方我们需要查询张三都出了什么书
author = models.Author.objects.get(name = '张三') author_book = author.book.all() for book in author_book: print(book.title)
要注意的是我们通过all()获取的是一个用book对象构成的可迭代的对象,所以用for循环可以取出每一个book对象,然后直接调用属性可以获取值。
反向查询
和前面说的一对多的外键一样,因为在book里我们并没有定义过author这个字段,所以是不能直接找author的,那么如果我们想获取某一本书的作者都有谁,就要用到反向查询
book = models.Books.objects.get(title = '学习Linux') authors = book.author_set.all() for author in authors: print(author.name)
所以,一定要注意到那个最牛X的用法_set()