zoukankan      html  css  js  c++  java
  • ORM常用操作

    ORM初级简单操作

    • 可以操作数据表、数据行,不能建库、删库。

    不含外键的表操作

    • 查询表内容

      # 获取表中所有的数据
      # ret是 QuerySet 对象列表  【对象】
      ret = models.User.objects.all()  
      
      # 获取一个对象(有且唯一)
      # 获取不到或者获取到多个对象会报错
      obj = models.User.objects.get(username='alex')
      
      # 获取满足条件的对象
      ret = models.User.objects.filter(username='alex',password='dasb')  # QuerySet 对象列表,可获取用户名相同的内容
      
    • 增加数据

      obj = models.创建表的类名.objects.create(表字段名=publisher_name)
      # obj 是创建的数据对象
      # obj.字段名=该字段内创建数据的内容
      如:增加数据name = 'xiaoqi'  obj.name = 'xiaoqi'
      
    • 删除数据

      obj_list = models.创建表的类名.objects.filter(pk=pk)  # 获取对象列表
      obj_list.delete()
      
      obj = models.Publisher.objects.get(pk=pk)   # 获取指定行 对象
      obj.delete()
      
    • 编辑数据

      # 修改数据
      obj.name = publisher_name
      obj.save()  # 保存数据到数据库中
      
      # 修改数据
      obj.name = publisher_name
      obj.save(update=['name'])  # 指定更新字段
      

    含外键的表操作

    • 例:出版社与图书管理(图书管理多,多的设置外键,关联出版社)

    • 查询

      #########查询注意事项############
      all_books = models.Book.objects.all()
      
      for book in all_books:
          print(book.title)
          print(book.pub,type(book.pub))   #  ——> 所关联的出版社对象
          # 注:书籍直接点外键,book.pub是先到book表中获取外键pub_id的内容,然后通过pub_id去出版社表中获取对应的数据,封装成一个对象。相当于做了两次查询
          
          print(book.pub.pk)  #  查id 多一次查询
          print(book.pub_id)  # 直接在book表中查出的pub_id,只查询id推荐使用此方法。
          print(book.pub.name)
          print("*"*32)
      
    • 新增

      models.Book.objects.create(title=book_name,pub=出版社的对象) # pub是对应出版社信息的对象
      models.Book.objects.create(title=book_name,pub_id=pub_id)	# pub_id直接对应book表的外键值
      
    • 删除

      pk = request.GET.get('id')  # 获取到id
      models.Book.objects.filter(pk=pk).delete()
      
    • 编辑数据

      # 修改数据
      book_obj.title = book_name
      # book_obj.pub_id = pub_id
      book_obj.pub = models.Publisher.objects.get(pk=pub_id)
      book_obj.save()
      

    多对多表结构

    • 设计表结构

      ########django帮我们生成第三张表########
      ########多对多表结构创建#########
      作者与书的关系,一个作者写多本书,一本书可由多个人共同完成
      class Author(models.Model):
          name = models.CharFiled(max_length = 32)
          books = models.ManyToManyField('Book') # 多对多,作者表与Book表之间关系
      
      第三张表名 app名_author_books
      
      ###############自己创建第三张表#############
      class AuthorBook(models.Model):
          author = models.ForeignKey(Author, on_delete=models.CASCADE)
          book = models.ForeignKey(Book, on_delete=models.CASCADE)
          date = models.DateField()
      
      ######自建的表和 ManyToManyField 联合使用########
      class Author(models.Model):
          name = models.CharField(max_length=32)
          books = models.ManyToManyField('Book',through='AuthorBook')  # 不在Author表中生产字段,生产第三张表
      
      class AuthorBook(models.Model):
          author = models.ForeignKey(Author, on_delete=models.CASCADE)
          book = models.ForeignKey(Book, on_delete=models.CASCADE)
          date = models.DateField()
      
    • 查询

      obj_list = models.Author.objects.all()
      # 获取Author  QuerySet 对象列表<QuerySet [<Author: Author object>....]>
          for obj in obj_list:
              # 循环获取每行数据的对象 Author object <class 'app01.models.Author'>
              print(obj, type(obj))
              print(obj.author_name, type(obj.author_name))
              # 获取对应行的author_name字段的值 mjj <class 'str'>
              print(obj.books, type(obj.books))
              # 关系管理对象app01.Book.None
              print(obj.books.all(),type(obj.books.all()))
              # 获取Book表的QuerySet对象列表 <QuerySet [<Book: Book object>, <Book: Book object>]>
      
    • 展示

      # 展示作者
      def author_list(request):    # 查询所有的作者    
      	all_authors = models.Author.objects.all()    
      	return render(request,'author_list.html',{'all_authors':all_authors})
      
      # 写模板
      {% for author in all_authors %}
          <tr>
              <td>{{ forloop.counter }}</td>
              <td>{{ author.pk }}</td>
              <td>{{ author.name }}</td>
              <td>
                  {% for book in author.books.all %}
                      {% if forloop.last %}
                          《{{ book.title }}》
                      {% else %}
                          《{{ book.title }}》、
                      {% endif %}
                  {% endfor %}
              </td>
          </tr>
      {% endfor %}
      
    • 增加

      all_book = models.Book.objects.all()	# 获取Book表中对象列表
      book_name = request.POST.getlist('book_name')	# 获取提交的数据,getlist以列表形式
      author_obj = models.Author.objects.create(name=author_name) # 只插入book表中的内容
      author_obj.books.set(book_name)  # 设置作者和书籍多对多的关系 
      
    • 修改

      books = request.POST.getlist('books')
      
      # 修改对象的数据
      author_obj.name = name
      author_obj.save()
      # 多对多的关系
      author_obj.books.set(books)  #  每次重新设置
      

    批量插入

    bulk_create():批量插入数据,减少SQL查询次数,没插入一条数据就要查询一次

    querysetlist=[]
    for i in resultlist:
        # models.Account(name=i),
        querysetlist.append(models.Account(name=i))     
    models.Account.objects.bulk_create(querysetlist,batch_size=10)
    # querysetlist:对象列表
    # batch_size=10:单次插入数据量,一次插入10条,如果一共五十条数据,就插入五次
    

    ORM中的常用方法

    返回queryset对象列表的方法

    • all():获取所有数据,返回一个queryset对象列表

    • filter():获取指定内容的所有数据,返回一个queryset对象列表

    • exclude():获取不满足条件的所有数据

      ret = models.Person.objects.exclude(pk=1)	# 获取除了pk=1以外的所有数据
      
    • values():

      # values():获取对象所有的字段和字段的值,一个字典对应一行数据
      ret = models.Person.objects.values()	# Queryset [{'字段':'值'},{'字段':'值'}...]
      
      # values('name','pid'):获取对应字段和值
      ret = models.Person.objects.values('name','pid') # Queryset [{'name':'值','pid':'值'}...]
      
      # values(flat=True): 添加该参数可直接获取对象的id
      
    • values_list():

      # values_list():拿到对象所有字段的值,以元组形式存于列表中
      ret = models.Person.objects.values_list()  # QuerySet  [ () ,() ]
      # values_list('name','pid'):拿到对象指定字段的值,以元组形式存于列表中
      ret = models.Person.objects.values_list('name','pid')
      
    • order_by():排序

      # 默认是升序,如果按降序排列在字段前加-,如:-pid
      ret = models.Person.objects.all().order_by('age','-pid')
      # 先以age按照升序排列后,再按照pid按照降序排列
      
    • reverse():反转,反向排序

      # 注:必须是已经排序好的Queryset列表,才能使用反转
      ret = model.Person.objects.all().order_by('name')
      r = ret.reverse()
      
    • distinct():去重

      # 完全相同的内容才能去重
      ret = models.Person.objects.values('age').distinct()
      

    orm操作返回对象的方法

    • get():获取满足条件的一个数据

    • first():获取第一个元素,没有返回None

      ret = models.Person.objects.filter(pk=1).values().first()
      
    • last():取最后一个元素,没有返回None

      ret = models.Person.objects.filter(pk=1).first()
      

    orm操作返回数字的方法

    • count():计数

      ret = models.Person.objects.all().count()	# 计算列表中有多少个对象
      

    orm操作返回布尔值的方法

    • exists():查询数据是否存在

      ret = models.Person.objects.filter(pk=1000).exists() 
      

    单表的双下划线

    • __gt:大于 greater than

      ret = models.Person.objects.filter(pk__gt=1)  # 取pk>1的数据
      
    • __gte:大于等于 greater than equal

      ret = models.Person.objects.filter(pk__gte=1)	# 取pk>=1的数据
      
    • __lt:小于 less than

      ret = models.Person.objects.filter(pk__lt=1)  # 取pk<1的数据
      
    • __lte:小于等于 less than equal

      ret = models.Person.objects.filter(pk__lte=1)  # 取pk<=1的数据
      
    • __range:取范围数据

      ret = models.Person.objects.filter(pk__range=[1,4])	# 取pk在1-4之间的数据,包含1,4
      
    • __in:取成员

      ret = models.Person.objects.filter(pk__in=[1,2,4])	# 取pk在[1,2,4]中的数据
      
    • __contains:包含,相当于mysql中的模糊查询

      ret = models.Person.objects.filter(name__contains='A') # 取name包含A的数据
      ret = models.Person.objects.filter(name__icontains='A') # 忽略大小写
      
    • __startswith:以...开头

      ret = models.Person.objects.filter(name__startswith='A') # 取name以A开头的数据
      ret = models.Person.objects.filter(name__istartswith='A') # 忽略大小写
      
    • __endswith:以...结尾

      ret = models.Person.objects.filter(name__endswith='A') # 取name以A结尾的数据
      ret = models.Person.objects.filter(name__iendswith='A') # 忽略大小写
      
    • __year:筛选年份

      ret = models.Person.objects.filter(birth__year='2019') # 取birth年份是2019的数据
      
    • __isnull:判断是否为空

      ret  = models.Person.objects.filter(phone__isnull=False) # 取phone不为null的数据
      ""空字符串不为null。
      

    外键的操作

    • 外键表示了表与表之间的关系

    • 建表语句,以下操作均是基于此表

      from django.db import models
      class Publisher(models.Model):
          name = models.CharField(max_length=32, verbose_name="名称")
      
          def __str__(self): 
              return self.name
      
      class Book(models.Model):
          title = models.CharField(max_length=32)
          pub = models.ForeignKey(
              Publisher, related_name='books',related_query_name='xxx',on_delete=models.CASCADE
          )
          def __str__(self):	# 指定__str__,方便查看区分对象
              return self.title
      
    • 基于对象的

      # 正向查询
      book_obj = models.Book.objects.get(title='菊花怪大战MJJ')
      book_obj.pub  # 获取到title这本书的queryset关系管理对象
      book_obj.pub.all()	# 获取对应的出版社信息queryset对象
      # 反向查询
      pub_obj = models.Publisher.objects.get(pk=1)
      pub_obj.book_set	# 获取到出版社id=1的对应书的queryset关系管理对象
      pub_obj.book_set.all()  # 获取出版社信息对应的书queryset对象
      # book_set 类名小写_set	没有指定related_name时使用
      # 如果指定related_name,则不使用“类名小写_set”,直接使用related_name的值
      
    • 基于字段的

      # 查询老男孩出版社的书
      ret = models.Book.objects.filter(pub__name='老男孩出版社')  # __表示跨表,从pub所在表跨到name所在表
      print(ret)	# 得到book表 Queryset对象列表
      
      # 查询出版菊花怪大战MJJ的出版社
      ret= models.Publisher.objects.filter(books__title='菊花怪大战MJJ') #设置related_name的值
      ret= models.Publisher.objects.filter(book__title='菊花怪大战MJJ')  # 未设置related_name的值,用类名小写
      
      ret= models.Publisher.objects.filter(xxx__title='菊花怪大战MJJ')  # 如果设置了related_query_name='xxx',就要用他的值xxx
      
    • 关系管理对象:外键中不能使用id只能使用对象

      # set方法
      pub_obj.books.set(models.Book.objects.filter(pk__in=[4,5]))  # 不能用id  只能用对象
      # add方法
      pub_obj.books.add(*models.Book.objects.filter(pk__in=[1,2]))
      # create方法
      pub_obj.books.create(title='python')
      
      # 外键可为空时才有remove  clear
      pub_obj.books.remove(*models.Book.objects.filter(pk__in=[1,2]))
      pub_obj.books.clear()
      

    一对多关系管理对象的方法

    • 关系管理对象

      pub_obj = models.Publisher.objects.get(pk=1)	# pk=1对应的出版社对象
      pub_obj.books	# 关系管理对象
      
    • set():设置一对多关系

      # 只能为对象
      pub_obj.books.set(models.Book.objects.filter(pk__in=[1,2,4,5]))
      
    • add():添加一对多关系

      # 只能为对象
      pub_obj.books.add(*models.Book.objects.filter(pk__in=[4,5]))
      # 添加对象时,由于filter获取的是对象关系列表,所以要获取其中每个对象,通过*解包
      
    • remove():删除一对多关系,只有当外键设置null=True时才行

      # 只能为对象
      pub_obj.books.remove(*models.Book.objects.filter(pk__in=[4,5]))
      
    • clear():清空所有多对多关系,只有当外键设置null=True时才行

      pub_obj.books.clear() # 清空所有obj对应书籍的一对多关系
      

    多对多

    • 建表代码

      class Publisher(models.Model):
          name = models.CharField(max_length=32, verbose_name="名称")
      
          def __str__(self):
              return self.name
      
      class Book(models.Model):
          title = models.CharField(max_length=32)
          price = models.DecimalField(max_digits=6, decimal_places=2)  # 9999.99
          sale = models.IntegerField()
          kucun = models.IntegerField()
          pub = models.ForeignKey(Publisher, null=True,on_delete=models.CASCADE)
      
          def __str__(self):
              return self.title
      
      class Author(models.Model):
          name = models.CharField(max_length=32, )
          books = models.ManyToManyField(Book)
      
          def __str__(self):
              return self.name
      
    • 基于对象的

      """正向查询"""
      obj = models.Author.objects.get(pk=1)
      obj.books	# 关系管理对象
      obj.books.all()	# 获取book的queryset对象列表
      
      """反向查询"""
      book_obj = models.Book.objects.filter(title='桃花怪大战菊花怪').first()
      # 不指定related_name
      book_obj.author_set	# 关系管理对象
      book_obj.author_set.all()	# 获取author的queryset对象列表
      # related_name='authors'
      book_obj.authors	# 关系管理对象
      book_obj.authors.all()
      
    • 基于字段的

      obj = models.Author.objects.filter(books__title='菊花怪大战Mjj')	# 这里的__表示跨表
      # 查询'菊花怪大战Mjj'这本书对应作者的对象列表,从books跨到title所在这个表
      
      obj = models.Book.objects.filter(author__name='Mjj')	# 不指定related_name
      # 查询作者'Mjj'对应的书的对象列表
      obj = models.Book.objects.filter(authors__name='Mjj')	# related_name='authors'
      obj = models.Book.objects.filter(xxx__name='Mjj')	# related_query_name='xxx'
      

    多对多关系管理对象的方法

    author_obj = models.Author.objects.get(pk=1)	# pk=1对应的作者对象
    author_obj.books	# 关系管理对象
    

    set():设置多对多关系

    # 参数可以是id,也可以是对象
    author_obj.books.set([1,2,3])	# 将查询出的obj对应作者与pk为[1,2,3]的书设置多对多关系
    # 内部是先将原来的删除,然后把新的内容添加进去
    author_obj.books.set(models.Book.objects.filter(pk__in=[1,2,4,5]))
    

    add():添加多对多关系

    author_obj.books.add(4,5)	# 给obj对应的作者添加pk为4和5的多对多关系
    内部已经有的不会再新增
    author_obj.books.add(*models.Book.objects.filter(pk__in=[4,5]))
    # 添加对象时,由于filter获取的是对象关系列表,所以要获取其中每个对象,通过*解包
    

    remove():删除多对多关系

    author_obj.books.remove(4,5) # 给obj对应的作者删除pk为4和5的多对多关系
    author_obj.books.remove(*models.Book.objects.filter(pk__in=[4,5]))
    

    clear():清空所有多对多关系

    author_obj.books.clear() # 清空所有obj对应作者的多对多关系
    

    create():创建一个所关联的对象,并且和当前对象添加多对多关系

    author_obj.books.create(title='天龙八部',pub_id=1) 
    # 通过作者对象创建书的内容,书中有title和pub外键
    
    book_obj = models.Book.object.filter(pk=2).first() # 通过书籍对象创建作者的内容
    book_obj.author_set.create(name='xiaoqi')
    

    update():批量更新数据

    models.Customer.objects.filter(pk__in=pk).update(consultant=self.request.user_obj)
    # 筛选出pk字段在pk中的数据,所有数据更新consultant字段值为self.request.user_obj
    

    分组聚合

    建表代码

    class Publisher(models.Model):
        name = models.CharField(max_length=32, verbose_name="名称")
    
        def __str__(self):
            return self.name
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=6, decimal_places=2)  # 9999.99
        sale = models.IntegerField()
        kucun = models.IntegerField()
        pub = models.ForeignKey(Publisher, null=True,on_delete=models.CASCADE)
    
        def __str__(self):
            return self.title
    
    class Author(models.Model):
        name = models.CharField(max_length=32, )
        books = models.ManyToManyField(Book)
    
        def __str__(self):
            return self.name
    

    聚合

    from django.db.models import Max,Min,Sum,Avg,Count	# 先导入聚合函数
    ret = models.Book.objects.filter(pk__gt=3).aggregate(Max('price'),avg=Avg('price'))
    # avg=Avg('price')等于是给平均函数重新命名,关键字参数
    # 获取pk大于3的最大值,和平均值
    # aggregate返回的是一个字典,可以.keys()等字典操作,后面不能在查其他的,比如.filter
    # aggregate聚合
    

    分组

    annotate 注释的意思,将聚合的结果作为一个注释放到原来的对象里,
    官方解释:每个参数annotate()都是一个注释,将被添加到QuerySet返回的每个对象中。
    
    # 统计每一本书的作者个数
    ret = models.Book.objects.annotate(count = Count('author')).values()
    for i in ret:
        print(i)
    {'id': 1, 'title': '跟金老板学开车', 'publish_date': datetime.date(2018, 8, 3), 'price': Decimal('12.90'), 'memo': None, 'publisher_id': 1, 'count': 2}
    可以看出将查询的内容添加至queryset并返回到每个对象中。 
    
    # 统计出每个出版社的最便宜的书的价格
    方式一:
    ret = models.Publisher.objects.annotate(Min('book__price')).values()
    方式二:
    ret = models.Book.objects.values('pub_id').annotate(Min('price')).values()
    	# objects后面.values表示分组的条件,参数是按照谁分组
    # 统计不只一个作者的图书
    ret = models.Book.objects.annotate(count = Count('author__name')).filter(count__gt=1)
    
    # 查询每个作者出的书的总价格
    ret = models.Author.objects.annotate(Sum('books_price')).values() 
    

    F查询 & Q查询

    F:两个字段之间对比,或操作数据表的某列

    from django.db.models import F
    models.Book.objects.filter(sale__gt=F('kucun')) # 找到销量大于kucun的书籍,两个字段之间的比较
    
    update:批量更新
    models.Book.objects.all().update(sale=F('sale')*2+10) # 取某个字段的值进行操作
    

    Q(条件):对对象进行复杂查询,并支持与&,或|,非~操作符

    from django.db.models import Q
    ret = models.Book.objects.filter(~Q(Q(pk__gt=3) | Q(pk__lt=2)) & Q(price__gt=50))
    # 与&,或|,非~
    
    q = Q()
    q.connector = 'OR'	# 表示Q中的元素之间的关系是或的关系,默认是与的关系。
    q.children	# 表示Q()中的元素,是一个列表。
    q.children.append(Q(pk=1))
    q.children.append(Q(pk=2))	# Q(pk=1),Q(pk=2)这两个元素都在q = Q()中
    Q(('pk',1))-->等价于Q(pk=1)  # 可查看源码
    
  • 相关阅读:
    BZOJ 2142: 礼物
    八校联考前3场记录
    BZOJ1115:[POI2009]石子游戏Kam (博弈论)
    IE10、IE11解决不能播放Flash的问题!
    ClientAbortException 异常解决办法
    WeX5学习笔记-建立项目且从SVN获取版本
    WeX5学习笔记-创建本地APP相关问题
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )屏幕适配
    ERROR 1130 (HY000):Host'localhost'解决方法
    一台机器运行多个JBoss 4.2.3多实例,或多个同一版
  • 原文地址:https://www.cnblogs.com/liuweida/p/12302626.html
Copyright © 2011-2022 走看看