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)  # 可查看源码
posted @ 2020-02-13 10:51  Lowell  阅读(295)  评论(0编辑  收藏  举报