1、建立表结构
三个表:book、Author、publisher。
书籍和作者是多对多的关系,一本书可以有多个作者,一个作者可以有多本书。
出版社和书籍是一对多的关系,一个出版社可以出版多本书(多方,多方定义外键),一本书只能由某一个出版社出版(现实情况可能不同,只是我们这里这样规定。)
from django.db import models
# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=100, verbose_name='书名')
authors = models.ManyToManyField('Author', verbose_name='作者')
publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE, verbose_name='出版社')
class Meta:
verbose_name = '图书'
verbose_name_plural = '图书'
def __str__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=50, verbose_name='作者名')
date_of_birth = models.DateField(verbose_name='出生日期', blank=True, null=True)
class Meta:
verbose_name = '作者'
verbose_name_plural = '作者'
def __str__(self):
return self.name
class Publisher(models.Model):
name = models.CharField(max_length=100, verbose_name='出版社名')
address = models.CharField(max_length=255, verbose_name='地址', blank=True, null=True)
website = models.URLField(verbose_name='网站', blank=True, null=True)
class Meta:
verbose_name = '出版社'
verbose_name_plural = '出版社'
def __str__(self):
return self.name
2、一对多(ForeignKey)
数据添加
一对多添加数据需要先添加“一”端,否则多端没有外键引用无法添加,所以需要先有出版社信息
我们这里手工添加一个:
Publisher.objects.create(name="中信出版社", address="河北省廊坊市", website="www.publisher.com")
添加书籍信息,所属”中信出版社“
# 先查询取得出版社的对象
publisher = Publisher.objects.get(id=1)
book = Book.objects.create(title="射雕英雄传", publisher=publisher)
数据查询
查询数据有两个方向,根据多方查询一方称为“正向”,根据一方取得多方数据称为“反向”
正向:有了书籍(多方)数据,查询出版社数据(一方)
方式:直接用“.”关联数据
book = Book.objects.filter(title="射雕英雄传").first()
print(book) # 射雕英雄传
print(book.publisher) # 中信出版社
print(book.publisher.address) # 河北省廊坊市
反向:有了出版社,查询书籍
方式:小写类名_set.all(),book_set.all()
publisher = Publisher.objects.filter(name="中信出版社").first()
# 方式一:用两步,通过一个变量引用所有书籍
books = publisher.book_set.all()
for book in books:
print(book)
# 方式二,不要中间变量,直接输出
print(publisher.book_set.all()[0]) # 输出 queryset的第一个对象
3、多对多
在后台,多对多关系在Django里,实际上是将两个多方的表名作为字段名,新增了一个表,来维护多对多关系。
数据添加
多对多的情况下,虽然两个都是“多方”,是对称的。但是在models中构建的时候,是把一个对象名称+s,作为另一个对象的ManyToManyField字段
class Book(models.Model):
authors = models.ManyToManyField('Author', verbose_name='作者')
这样在编程的时候就不是对称的,所以添加的时候两方添加方式是有区别的。
book.authors.add(author1, author2) # book 里面有authors字段,所以这样添加
author.book_set.add(book1, book2) # author里面没有books字段
正向,从定义对方字段的那一方开始
# 方式一,传单独的对象
rong = Author.objects.filter(name="黄蓉").first() # 这里必须用.first(),否则返回的是queryset,而不是对象
jing = Author.objects.filter(name="郭靖").first()
bird = Book.objects.filter(title="射雕英雄传").first()
bird.authors.add(rong, jing) # 将rong、jing两个Author对象关联到book
# 方式二,传queryset
from django.db.models import Q
authors = Author.objects.filter(Q(name="黄蓉") | Q(name="郭靖"))
bird = Book.objects.filter(title="射雕英雄传").first()
bird.authors.add(*authors) # 注意前面要用*
# 或者传id列表,假设1、3为两个作者的id
bird.authors.add(*[1, 3]) # 注意前面要用*
删除所有关联关系,不会删除对象
bird.authors.clear()
反向,没有定义另一方字段的一方
bird = Book.objects.get(title="射雕英雄传")
rong = Author.objects.filter(name="黄蓉").first()
rong.book_set.add(bird) # 也可以添加多本书,如果有的话
创建新对象,并加入关联对象集
publisher = Publisher.objects.filter(name="中信出版社").first()
author = Author.objects.filter(name="黄蓉").first()
book = author.book_set.create(title="神雕侠侣", publisher=publisher) # 这里创建的是book类,也可以返回创建的对象
删除对象关联
author.book_set.remove(bird) # 删除其中一个对象的关联
author.book_set.clear() # 删除所有关联关系,不会删除对象
数据查询
多对多的数据查询根据“谁定义了以对方表名为名字的字段”也有正向、反向。方法同一对多。