django之多表操作

django中模型表在Terminal中测试:python manage.py shell

一、表与表之间的关系

  一对一:(OneToOneField)  关系字段无论建在哪张表里都可以,但是推荐建在查询频率比较高的那张表 

      【publish = models.ForeignKey(to='Publish')】---   django源码中,就是ForeignKey中unique=True

      class OneToOneField(ForeignKey)
        def __init__(self, to, on_delete=None, to_field=None, **kwargs):
         kwargs['unique'] = True

  一对多:(ForeignKey)   一对多字段建在多的那一方

  多对多:(ManyToManyField)    多对多字段无论建在哪张关系表里都可以,但是推荐建在查询频率比较高的那张表

  ps: 如何判断表与表之间到底什么关系

    换位思考:A能不能有多个B

         B能不能有多个A

     增改删:可以是一个或多个  【数字,也可以是对象】 

    add()        # 添加

    set()      #   修改

    remove()    #不能接收可迭代对象,可以* querySet对象

    clear()      #  清空 不用传参

  删中设置级联删除:

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)  # 取消级联删除一定要设置null=True
    
    CASCADE: 设置级联删除,即删除了出版社,对应的该出版社的书也会一块删除
    SET_NULL: 取消级联删除

 

models:

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publist_date = models.DateField(auto_now_add=True)
    # publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE,)
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    authors = models.ManyToManyField(to='Author')  # 虚拟字段

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.EmailField()  # 对应就是varchar类型

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authordetail = models.OneToOneField(to='AuthorDetail')

class AuthorDetail(models.Model):
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
View Code

 

增、改、删 操作

# -----------------------------
    # 多表查询

    #  一对多的增改删
    # 新增
    # 直接写id
    # models.Book.objects.create(title='红楼梦', price=66.66, publish_id=1)

    # 传数据对象
    # publist_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.create(title='三国演义', price=199.99, publish=publist_obj)

    # 修改
    # queryset修改[publish_id]
    # models.Book.objects.filter(pk=1).update(publish_id=3)

    # queryset修改[publish]
    # publish_obj2 = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.filter(pk=1).update(publish=publish_obj2)

    # 对象修改
    # book_obj = models.Book.objects.filter(pk=3).first()
    # book_obj.publish_id = 1  # 点表中真实存在的字段名
    # book_obj.save()

    # book_obj = models.Book.objects.filter(pk=3).first()
    # publish_obj = models.Publish.objects.filter(pk=3).first()
    # book_obj.publish = publish_obj  # 点orm中字段名,传字段对应表的数据对象
    # book_obj.save()

    # 删除
    # models.Book.objects.filter(pk=1).delete()
    # models.Publish.objects.filter(pk=1).delete()
    # models.Publish.objects.filter(pk=7).delete()

    # 基于对象删除
    # book_obj = models.Book.objects.filter(pk=8).first()
    # book_obj.delete()

    # 查询年
    # res = models.Book.objects.filter(publist_date__year=2017)
    # for row in res:
    #     print(row.title)

    # 查询名字包含字母n的用户 sqlite数据库大小写演示不出来
    # res = models.Author.objects.filter(name__contains='n')
    # print(res)

    # res = models.Author.objects.filter(name__icontains='n')
    # print(res)
#-------------------------------------------------------
    # 多对多之增删改

    # 添加关系:add支持传数字或对象,并且都可以传多个
    # 给书籍绑定与作者之间的关系
    # 加数字
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.add(1)
    # book_obj.authors.add(2, 3)  # 加多个数字

    # 传对象
    # authors_obj = models.Author.objects.filter(pk=1).first()
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.add(authors_obj)

    # 传多个对象
    # authors_obj1 = models.Author.objects.filter(pk=2).first()
    # authors_obj2 = models.Author.objects.filter(pk=3).first()
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.add(authors_obj1,authors_obj2 )



    # 修改书籍与作者的关系 set() set传的必须是可迭代对象

    # 可以传数字和对象,并且支持传多个
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.set((1,))  # 把id为2的书的作者改为1
    # book_obj.authors.set((2,3))  # 把id为2的书的作者改为1

    # 传多个对象
    # book_obj = models.Book.objects.filter(pk=1).first()
    # author_list = models.Author.objects.all()
    # book_obj.authors.set(author_list)

    # 删除书籍与作者之间的关系
    # book_obj = models.Book.objects.filter(pk=1).first()
    # 可以传数字和对象,并且支持多个
    # book_obj.authors.remove(1)
    # book_obj.authors.remove(2, 3)

    # author_obj = models.Author.objects.all().first()
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.remove(author_obj)


    # author_list = models.Author.objects.all()
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.remove(*author_list)  # 需要将queryset对象打散

    # 清空 clear() # 清空的是当前这个表记录对应的绑定关系
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.clear()
View Code

 

 

 正反向

    # 基于对象的表查询
    # 正向
    # 查询书籍是西游记的出版社邮箱
    # book_obj = models.Book.objects.filter(title='西游记').first()
    # print(book_obj.publish, type(book_obj.publish))  # publish_obj
    # print(book_obj.publish.email)

    # 查询书籍是python的作者的姓名
    # book_obj = models.Book.objects.filter(title='红楼梦').first()
    # print(book_obj.authors)  # app01.Author.None
    # print(book_obj.authors.all())


    # 查询作者为jason的电话号码
    # author = models.Author.objects.filter(name='jason').first()
    # print(author.authordetail.phone)


    # 反向
    # 查询出版社是东方出版社的书籍    一对多的反向查询
    # publish_obj = models.Publish.objects.filter(name="南方出版社").first()
    # print(publish_obj.book_set.all())

    # 查询作者egon写过的所有书        多对多的反向查询
    # author_obj = models.Author.objects.filter(name="egon").first()
    # print(author_obj.book_set)  # app01.Book.None
    # print(author_obj.book_set.all(), type(author_obj.book_set.all()))

    # 查询作者电话号码是110的作者姓名     一对一的反向查询
    # author_obj = models.AuthorDetail.objects.filter(phone='110').first()
    # print(author_obj.author)  #作者的名字jason [__str__ 中定义的打印内容]
    # print(author_obj.author.name)  # jason
View Code

 

下划线:

 # 基于双划线的正向查询
    # 查询书籍为python的出版社地址
    # res = models.Book.objects.filter(title='python').values('title', 'publish__addr')
    # print(res)

    # 查询书籍为西游记的作者的姓名
    # res = models.Book.objects.filter(title='西游记').values('authors__name', 'title')
    # print(res)

    # 查询作者为jason的家乡
    # res = models.Author.objects.filter(name='jason').values('authordetail__addr', 'name')
    # print(res)

    # 基于双划线的反向查询
    # 查询南方出版社的所有书
    # res = models.Publish.objects.filter(name='南方出版社').values('book__title', 'name')
    # print(res)

    # 查询电话号码为120的作者姓名
    # res = models.AuthorDetail.objects.filter(phone='120').values('author__name')
    # print(res)

    # 查询作者为jason的写的书的名字
    # res = models.Author.objects.filter(name='jason').values('book__title')
    # print(res)

    # 查询书籍为水浒传的作者的电话号码
    # res = models.Book.objects.filter(title='水浒传').values('authors__authordetail__phone')
    # print(res)

    # 查询jason作者的手机号
    # 正向
    # res = models.Author.objects.filter(name='jason').values('authordetail__phone')
    # print(res)

    # 反向
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
    # print(res)

    # 查询出版社为东方出版社的所有的图书的名字和价格
    # 正向
    # res = models.Publish.objects.filter(name="东方出版社").values('book__title', 'book__price')
    # print(res)

    # 反向
    # res = models.Book.objects.filter(publish__name='东方出版社').values('title', 'price')
    # print(res)

    # 查询东方出版社的价格大于19的书
    # 正向
    # res = models.Publish.objects.filter(name='东方出版社', book__price__gt=19)
    # res = models.Publish.objects.filter(name='东方出版社', book__price__gt=19).values('book__title', 'book__price')
    # print(res)

    # 反向
    # res = models.Book.objects.filter(publish__name='东方出版社', price__gt=19).values('title', 'price')
    # print(res)
View Code

 

聚合(aggregate)、分组(annotate类比为group by):

from django.db.models import Count, Avg, Min, Sum,

 #  聚合查询 aggregate
    from django.db.models import Count, Avg, Min, Sum
    # 查询书籍对应的作者人数
    # res = models.Book.objects.filter(pk=2).aggregate(authors_num=Count('authors'))
    # print(res)

    # 查询所有出版社书的平均价格
    # res = models.Publish.objects.aggregate(price_avg=Avg('book__price'))
    # print(res)

    # 统计东方出版社出版的书籍的个数
    # res = models.Publish.objects.filter(name='南方出版社').aggregate(book_num=Count('book'))
    # print(res)

    # 分组查询annotate 相当于group by
    # 查询没个出版社出的书的平均价格
    # res = models.Publish.objects.annotate(price_avg=Avg('book__price')).values('name', 'price_avg')
    # print(res)

    # 统计每本书的作者个数
    # res = models.Book.objects.annotate(authors_num=Count('authors')).values('title', 'authors_num')
    # print(res)

    #统计每个出版社最便宜的书
    # res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min')
    # print(res)

    # 查询每个作者出书的总价格
    # res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum')
    # print(res)
View Code

 

 

正向与反向的概念

 

【小结】 1. 正向查询按字段,反向查询按表名小写 【同样适用于双下划线之values()参数】

     2. 当被跨的表的中可能有多个数据时,就表名小写_set.all()  

     3.  基于对象【对象点语法】查询类比为子查询,   基于下划线的可类比成链表

     4.   author_obj.book_set     #  输出结果app01.Book.None, 

      author_obj.book_set.all()         #  queryset对象


一对一
  正向:author---关联字段在author表里--->authordetail 按字段
   反向:authordetail---关联字段在author表里--->author 按表名小写  
     查询jason作者的手机号 正向查询
     查询地址是 :山东 的作者名字 反向查询

一对多
  正向:book---关联字段在book表里--->publish 按字段
  反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书

多对多
  正向:book---关联字段在book表里--->author 按字段
  反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书

# 反向
# 查询出版社是东方出版社的书籍 一对多的反向查询
# publish_obj = models.Publish.objects.filter(name="南方出版社").first()
# print(publish_obj.book_set.all())

# 查询作者egon写过的所有书 多对多的反向查询
# author_obj = models.Author.objects.filter(name="egon").first()
# print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all())

# 查询作者电话号码是110的作者姓名 一对一的反向查询
# author_obj = models.AuthorDetail.objects.filter(phone='110').first()
# print(author_obj.author) #作者的名字jason [__str__ 中定义的打印内容]
# print(author_obj.author.name) # jason

 

 

  

 

posted @ 2019-07-28 19:12  胖啊  阅读(213)  评论(0编辑  收藏  举报