06-模型层2——多表操作之建立关联表及添加记录

几个小结

(1)一旦确立表关系是一对多:建立一对多关系————在多对应的表中创建关联字段。
(2)一旦确立表关系是多对多:建立多对多关系————创建第三张关系表————id和两个关联字段。
(3)一旦确定表关系是一对一:建立一对一关系————在两张表的任意一张表中建立关联字段+Unique。
(4)其实上面说的“关联字段”就是外键——foreign key。

假定下面这些概念、字段与关系:

(1)作者模型:一个作者有姓名和年龄。
(2)作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。
##作者详情模型和作者模型之间是一对一的关系(one-to-one)。
(3)出版社模型:出版社有名称,所在城市以及email。
(4)书籍模型: 书籍有书名和出版日期.
##一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);
##一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
(5)书跟作者是多对多关系,利用Django的建表语句我们可以新生成一张“关系表”——book2author

项目创建及文件配置略————详见单表操作的具体步骤

新建的应用app01的models.py文件中的内容

from django.db import models

#出版社
class Publish(models.Model):
    #主键
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=55)
    city = models.CharField(max_length=55)
    #email有特定的格式!
    email = models.EmailField()

#作者详细
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    #日期的格式
    birthday = models.DateField()
    #手机号
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=55)

#作者表
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=55)
    #年龄,int类型的小数字就可以
    age = models.IntegerField()
    #由于作者与作者详细表是一对一的关系:所以选择在作者表中这样建立外键
    #注意这里还是只写authordetail就可以了,_id 程序会自动给加的!
    #注意这里on_delete一定要加!而且to后面的表的名字要习惯性的加上1
    #一对一!
    authordetail = models.OneToOneField(to='AuthorDetail',to_field='nid',on_delete=models.CASCADE)


#书籍
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=55)
    #出版日期,日期格式
    pub_date = models.DateField()
    #价格,最大位数5位,小数后保留两位
    price = models.DecimalField(max_digits=5,decimal_places=2)
    #与出版社表关联的字段——publish_id
    #注意自己写的时候只写publish就可以了!Django会自动补上_id
    #注意:on_delete必须要加上!!!而且to后面的表的名字要习惯性的加上1
    #注意 null=true表示允许为空值
    # 一对多!
    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE,null=True)
    #书跟作者是多对多的关系。理论上需要新建一张关系表。
    #但是利用Django下面的语句既可以新建一张表,又可以分别将其与书籍表与作者表关联起来!
    #多对多!
    authors = models.ManyToManyField(to='Author')
    """
    create table book2author(
        id int primary_key auto_increment,
        book_id int,0
        author_id int,
        foreign_key (book_id) references Book(id),
        foreign_key (author_id) references Author(id),   
    );
    """

然后在terminal中运行:

python manage.py makemigrations
python manage.py migrate

查看一下数据库中是否生成了“5”张表

注意事项

(1)表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
(2)id字段是自动添加的
(3)对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
(4)这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL语句。
(5)定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
(6)外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 

添加记录

先在publish、author、authordetail表中加几条数据

批量创建数据库条目

book_list = []
for i in range(100):
    book = Book(title='book_%s'%i,price=i*i)
    book_list.append(book)
#批量创建:bulk_create()
Book.objects.bulk_create(book_list)

1、一对多添加记录

在book表中新增一条记录,由于publish表与book表是一对多的关系,关联字段为publish_id,因此我们先得找到对应的出版社,
这里有两种方法:

方法一:

publish_obj = Publish.objects.get(nid=1)
Book.objects.create(title='金瓶',price=100,pub_date='1922-2-3',publish=publish_obj)

方法二:

Book.objects.create(title='金瓶',price=100,pub_date='1922-2-3',publish_id=1)

注意理解publish_obj:

###查看水浒传书籍的出版社对应的邮箱——注意这里的first(),把QuerySet对象转化为Object对象###
book_obj = Book.objects.filter(title='水浒传').first()
##注意先.publish再.emali
print(book_obj.publish.email)

2、多对多添加记录

书籍与作者是多对多的关系。
创建一个book记录,将两个作者关联到这个记录中,这两个作者写同一本书。

##注意这里的first()得加!
book_obj = Book.objects.create(title='三国群英传2',price=200,pub_date='1900-3-4',publish_id=2)
whw = Author.objects.filter(nid=1).first()
www = Author.objects.filter(nid=2).first()
##绑定多对多关系的API。
##这个authors就是Book类里建多对多关系的时候的那个:authors = models.ManyToManyField(to='Author')
book_obj.authors.add(whw,www)

##注意如果从既有的数据里找得这样写,authors字段在Book类中,因此必须是Book的对象去add Author对象
##后面加上first()将QuerySet对象转换成model对象
author1 = Author.objects.filter(name='whw').first()
author2 = Author.objects.filter(name='www').first()
book1 = Book.objects.filter(title='金瓶').first()
book1.authors.add(author1,author2)

##解除多对多关系,注意first得加
    book = Book.objects.filter(nid=4).first()   
##注意这里的2代表author_id
book.authors.remove(2)
##也可以移除所有的关系:
book.authors.clear()

##重点来了!————all()
##与这本书关联的所有作者对象集合——QuerySet对象。[obj1,obj2,......]
ret = book.authors.all()
print(ret)
###
###查询主键为4的书籍的所有作者的名字###
book_o = Book.objects.filter(nid=4).first()
rets = book_o.authors.all().values('name')
print(rets)
###注意上面的结果是:<QuerySet [{'name': 'whw'}, {'name': 'www'}]>

3、多对多增删改表记录补充

  方式一: 多对多一般在前端页面上使用的时候是多选下拉框的样子来给用户选择多个数据,这里可以让用户选择多个书籍,多个作者
  # 当前生成的书籍对象
    book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
    # 为书籍绑定的做作者对象
    yuan=Author.objects.filter(name="yuan").first() # 在Author表中主键为2的纪录,注意取的是author的model对象
    egon=Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录
  #有人可能会说,我们可以直接给第三张表添加数据啊,这个自动生成的第三张表你能通过models获取到吗,是获取不到的,用不了的,当然如果你知道了这个表的名字,那么你通过原生sql语句可以进行书的添加,所以要通过orm间接的给第三张表添加数据,如果是你手动添加的第三张表你是可以直接给第三张表添加数据
    # 绑定多对多关系,即向关系表book_authors中添加纪录,给书添加两个作者,下面的语法就是告诉orm给第三张表添加两条数据
    book_obj.authors.add(yuan,egon)    #  将某些特定的 model 对象添加到被关联对象集合中。   =======    book_obj.authors.add(*[])
    #book_obj是书籍对象,authors是book表里面那个多对多的关系字段名称。
    #其实orm就是先通过book_obj的authors属性找到第三张表,然后将book_obj的id值和两个作者对象的id值组合成两条记录添加到第三张表里面去
方式二:
 book_obj.authors.add(1,2)
 book_obj.authors.add(*[1,2]) #这种方式用的最多,因为一般是给用户来选择,用户选择是多选的,选完给你发送过来的就是一堆的id值

多对多关系其它常用API

book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[1,2]),将多对多的关系数据删除
book_obj.authors.clear()       #清空被关联对象集合
book_obj.authors.set()         #先清空再设置   ===== 

删除示例

 book_obj = models.Book.objects.filter(nid=4)[0]
    # book_obj.authors.remove(2) #将第三张表中的这个book_obj对象对应的那个作者id为2的那条记录删除
    # book_obj.authors.clear()
    # book_obj.authors.set('2') #先清除掉所有的关系数据,然后只给这个书对象绑定这个id为2的作者,所以只剩下一条记录  3---2,比如用户编辑数据的时候,选择作者发生了变化,那么需要重新选择,所以我们就可以先清空,然后再重新绑定关系数据,注意这里写的是字符串,数字类型不可以
    book_obj.authors.set(['1',]) #这么写也可以,但是注意列表中的元素是字符串,列表前面没有*,之前我测试有*,感觉是版本的问题,没事,能够用哪个用哪个

一对一和一对多的删改和单表的删改是一样的,别忘了删除表的时候,咱们是做了级联删除的。

复制代码
更新:
book_obj = models.Book.objects.get(id=1) #获取一个书籍对象
data = {'title':'xxx','price':100} #这个书籍对象更新后的数据
models.Book.objects.filter(id=n).update(**data) #将新数据更新到原来的记录中
book_obj.authors.set(author_list) #将数据和作者的多对多关系加上

删除:
models.Book.objects.filter(id=1).delete()
posted on 2019-05-19 09:54  江湖乄夜雨  阅读(580)  评论(0编辑  收藏  举报