Django: many to many table queries, aggregated packet, FQ queries, transactions,

1 table-many relational query

  • Preparations create the table structure
from django.db import models

# Create your models here.

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
  • Import data (relationship table)

  • Object-based query
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day62exercise.settings")
import django

django.setup()

from app01 import models
#基于对象查询


#多对多外键在作者
# 作者 ----> 书  对象
# 查询作者id为1的作者出版的书
obj = models.Author.objects.get(pk=1)
print(obj.books.all())
# 书 ---->  作者 对象
#查询书名为"八卦掌"的所有作者
#当不设置related_name  用法  类_set(类为小写)
obj = models.Book.objects.get(title="八卦掌")
print(obj.author_set.all())

#当在关联外键设置,related_name = "authors"
obj = models.Book.objects.get(title="八卦掌")
print(obj.authors.all())


# 作者--->书 ----> 出版社
#查询作者id为1,写的所有书的出版社
obj = models.Author.objects.get(pk=1)
print(obj.books.all().values("pub__name").distinct())


#出版社 ---->书 ------>作者
#查找在大灰狼出版社出过书的作者
obj = models.Publisher.objects.get(name="大灰狼出版社")
print(obj.book_set.all().values("author__name"))

  • Methods relationship management objects

    • "Association Manager" is used in many or many-associated context's manager.

    • It exists in the following two cases:

      1. Reverse Lookup foreign key relationships

      2. to-many relationship

    • It is simply a later point when there may be multiple objects can use the following method.

  • create()

    Create a new object, saving the object, and add it to the associated object set in, returns the newly created object.

  • add()

    Add the specified model object to the associated object set.

    Add an object

  • remove()

    Centralized model objects removed from the execution of the associated object

  • clear()

    Removes all objects from the related object.

#all() #获取所关联所有对象
obj = models.Author.objects.get(pk=2)
print(obj.books.all())


#set() 设置多对多关系  参数可以传入[id,id],[对象,对象]
#把 id为2的作者关联的书的id设置为3,4
# 法1:传入id
obj = models.Author.objects.get(pk=2)
obj.books.set([3,4])
# print(obj.books.all())
# 法2:传入对象
obj.books.set(models.Book.objects.filter(pk__in =[1,2,3]))
print(obj.books.all())


#add() 添加多对多关系 参数可以传入(d,id),(对象,对象)
#id为2的作者关联的书的id添加4,5
# 法1:传入id
obj.books.add(4,5)
# 法2:传入对象
obj.books.add(*models.Book.objects.filter(pk__in=[4,5]))#   *   号作用是打散



#remove 删除多对多的关系   参数可以传入(d,id),(对象,对象)
#id为2的作者关联的书的id 4,5 给移除
# 法1:传入id
obj = models.Author.objects.get(pk=2)
obj.books.remove(4,5)
# 法2:传入对象
obj.books.remove(*models.Book.objects.filter(pk__in=[4,5]))  #     *   号作用是打散



# create()
obj = models.Author.objects.get(pk=2)
ret = obj.books.create(title="打狗棒法",pub_id=2,price=56,sale=23,kucun=44)
# print(ret)

#获取id为1的book对象,创建author
res = models.Book.objects.get(pk=1)
print(res)
rep = res.authors.create(name="关羽")

#clear() #清除多对多关系
#清楚作者id为5的与书的关系
res = models.Author.objects.get(pk=5)
res.books.clear()

  • clear () and remove () method to avoid the pit
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, 
                            on_delete=models.CASCADE)
                            
#ForeignKey字段没有在pub字段设置null=True.
#当删除一个Publisher字段(此字段有数据关联Book表),执行:                        
res = models.Publisher.objects.get(pk=5).book_set.clear()
print(res)

#此时会报错没有clear()和remove()方法:
#>>> models.Publisher.objects.first().book_set.clear()
#Traceback (most recent call last):
# File "<input>", line 1, in <module>
#AttributeError: 'RelatedManager' object has no attribute 'clear'

#显示没有此方法

#当ForeignKey字段设置null=True时,执行
res = models.Publisher.objects.get(pk=5).book_set.clear()
print(res)
可以删除!
  • Publisher deleted records, associate Book pub_id display table is null

note:

  • For all types of related fields, add (), create (), remove () and clear (), set () will immediately update the database. In other words, at any end of the association, it does not need to call the save () method.

Aggregation and grouping 2.2

  • Or reference on the operating table!

1. polymerization

  • aggregate()It is QuerySeta termination clause, meaning that it returns a dictionary that contains a number of key-value pairs. The aggregate value is the name of the key identifier, the value is computed aggregate value. Name of the key is automatically generated out according to the name field and aggregate functions. Used built-in functions:

    from django.db.models import Avg, Sum, Max, Min, Count
    import os
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day62exercise.settings")
    import django
    
    django.setup()
    
    from app01 import models
    from django.db.models import Avg, Sum, Max, Min, Count
    #统计Book表 id大于3的价格最高的字典
    ret = models.Book.objects.filter(pk__gt=3).aggregate(Max("price"))
    print(ret)
    #{'avg': 179.211111}
    #统计Book表, 书的平均价格
    ret = models.Book.objects.all().aggregate(avg=Avg("price"))
    print(ret)
    #{'avg': 179.211111}
    #统计Book表,平均卖书的数量,和最高卖书数量
    ret = models.Book.objects.all().aggregate(avg=Avg("sale"),max=Max("sale"))
    print(ret)
    #{'avg': 111.0, 'max': 550}

2. Group

#统计每个出版社出的书的平均价格
res = models.Book.objects.values("pub__name").annotate(avg=Avg("price")).values("avg","pub__name")
print(res)

# 统计每一本书的作者个数
ret = models.Book.objects.annotate(作者数 = Count("author")).values("title","作者数")
print(ret)


#统计每个出版社出的书的平均价格
ret = models.Book.objects.values("pub__name").annotate(avg=Avg("price")).values("avg","pub__name")
print(ret)
#统计每个出版社最便宜的书的价格
ret = models.Book.objects.values("pub__name").annotate(min=Min("price")).values("min","pub__name")
print(ret)
# 法1
ret = models.Book.objects.values("pub_id").annotate(min=Min("price"))
print(ret)
# 法2
ret = models.Publisher.objects.values("name").annotate(min=Min("book__price"))
print(ret)

# 统计不止一个作者的图书
ret = models.Book.objects.annotate(count = Count("author")).filter(count__gt=1)
print(ret)

#同级各个作者出的书的总价
ret = models.Author.objects.values("name").annotate(sum = Sum("books__price")).values()
print(ret)

3.F queries and query Q

  • We construct the filter field values ​​are just some constant comparison. If we want to compare the values ​​of two fields, then how to do it?
  • Django provides F () to do such a comparison. Examples F. () Can be referenced in the query field, the value to compare different fields of the same model instance two.
F query:
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day62exercise.settings")
import django

django.setup()

from app01 import models

#F查询
# ret = models.Book.objects.filter(price__gt=10000)
# print(ret)


from django.db.models import F
# 比较书的销量大于库存的书
ret = models.Book.objects.filter(sale__gt=F("kucun"))
print(ret)

#更新字段

# 书的价格更新为100 ,只更新1个
ret = models.Book.objects.get(pk=1)
ret.sale = 100
ret.save()
# 更新所有sale字段为100
models.Book.objects.all().update(sale=100)

#取某个字段的值进行操作
models.Book.objects.all().update(sale=F("sale")*2+10)
  • Advanced:

    把所有书名后面加上(第一版)
    from django.db.models.functions import Concat
    from django.db.models import Value
    
    models.Book.objects.all().update(title=Concat(F('title'),Value("("),Value("第一版"),Value(")")))
    
Q query:
  • filter()Keyword argument query methods are carried out with the "AND" of. If you need to perform more complex queries (eg ORstatements), you can use Q对象.
  • You can use the &, | or, non ~
from django.db.models import Q
#查询pk大于3的所有Book记录
ret = models.Book.objects.filter(Q(pk__gt=3))
print(ret)

#查询pk<2 或 pk>5 的所有Book记录
ret = models.Book.objects.filter(Q(pk__gt=5)|Q(pk__lt=2))
print(ret)

#查询2<=pk<=5并且price大于50的所有记录
ret = models.Book.objects.filter(~Q(Q(pk__gt=5)|Q(pk__lt=2))&Q(price__gt=50))
print(ret)

4. Transaction

  • Database has four properties: atomicity, consistency, isolation, durability
    • Atomic: A transaction includes all operations either all succeed, or all fail rollback
    • Consistency: Before executing the transaction and the execution of the word must be in a consistent state, each time the data changes will lead to a state database migration
    • Isolation: multiple users concurrent access to the database, such as access to the same table, between multiple concurrent transactions, should be isolated from each other.
    • Persistence: Once submitted, for database data change is permanent, even if the database failure can not be lost has been submitted to change the firm completed.
  • Import module

    from django.db import transaction
try:
    with transaction.atomic():
        models.Publisher.objects.create(name="xxxxxx")
        # int("stasd")
        models.Publisher.objects.create(name="xx2")
except Exception as e:
    print(e)

The native SQL execution

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day62exercise.settings")
import django

django.setup()


from django.db import connection,connections
cursor = connection.cursor()

cursor.execute("""select * from app01_publisher where id=%s""",(3,))
# all = cursor.fetchall()
# print(all)
row = cursor.fetchone()
print(row)

6.Django terminal print SQL statements

  • In Django project settings.py file, copy and paste the following code in the final
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
  • That is, your Django project configuration named django.db.backends instance logger to see the translated SQL statements.

7. Call Django environment in a Python script

  • Django project directory and sibling
import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day62exercise.settings")
    import django
    django.setup()
    from app01 import models
    book =models.Book.objects.all()
    print(book)

8.QuerySet Daquan

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 获取所有的数据对象

def filter(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def exclude(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def select_related(self, *fields)
    性能相关:表之间进行join连表操作,一次性获取关联的数据。

    总结:
    1. select_related主要针一对一和多对一关系进行优化。
    2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。

def prefetch_related(self, *lookups)
    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。

    总结:
    1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
    2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。

def annotate(self, *args, **kwargs)
    # 用于实现聚合group by查询

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

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用于distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct进行去重

def order_by(self, *field_names)
    # 用于排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 构造额外的查询条件或者映射,如:子查询

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列数据

 def only(self, *fields):
    #仅取某个表中的数据
     models.UserInfo.objects.only('username','id')
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的数据库,参数为别名(setting中的设置)


##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################

def raw(self, raw_query, params=None, translations=None, using=None):
    # 执行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
    models.UserInfo.objects.raw('select id as nid from 其他表')

    # 为原生SQL设置参数
    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

    # 将获取的到列名转换为指定列名
    name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

    # 指定数据库
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


def values(self, *fields):
    # 获取每行数据为字典格式

def values_list(self, *fields, **kwargs):
    # 获取每行数据为元祖

def dates(self, field_name, kind, order='ASC'):
    # 根据时间进行某一部分进行去重查找并截取指定内容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 并获取转换后的时间
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates('ctime','day','DESC')

def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo时区对象
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def none(self):
    # 空QuerySet对象


####################################
# METHODS THAT DO DATABASE QUERIES #
####################################

def aggregate(self, *args, **kwargs):
   # 聚合函数,获取字典类型聚合结果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
   ===> {'k': 3, 'n': 4}

def count(self):
   # 获取个数

def get(self, *args, **kwargs):
   # 获取单个对象

def create(self, **kwargs):
   # 创建对象

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的个数
    objs = [
        models.DDD(name='r11'),
        models.DDD(name='r22')
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 如果存在,则获取,否则,创建
    # defaults 指定创建时,其他字段的值
    obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})

def update_or_create(self, defaults=None, **kwargs):
    # 如果存在,则更新,否则,创建
    # defaults 指定创建时或更新时的其他字段
    obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})

def first(self):
   # 获取第一个

def last(self):
   # 获取最后一个

def in_bulk(self, id_list=None):
   # 根据主键ID进行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 删除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有结果


QuerySet方法大全

Guess you like

Origin www.cnblogs.com/xujunkai/p/11847553.html