Django之ORM(三) F查询和Q查询,事务及其他

F与Q查询


Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。


settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'ORM2',
        'PORT': 3306,
        'HOST': '127.0.0.1',
        'USER': 'root',
        'PASSWORD': 123

    }
}


init.py

import pymysql
pymysql.install_as_MySQLdb()


models.py

from django.db import models


# Create your models here.

class Product(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    maichu = models.IntegerField()
    kucun = models.IntegerField()

    def __str__(self):
        return '对象的名字:%s'%self.name


执行命令创建表

pycharm菜单-tools-run manage.py TASK
$ makemigrations
$ migrate


tests.py

from django.test import TestCase

# Create your tests here.

import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ORM2.settings")
    import django
    django.setup()
    from app01 import models


初始数据


F查询


查询卖出数大于库存数的商品

from django.db.models import F,Q
    # F查询 给一个字段就能拿到字段的值
    res=models.Product.objects.filter(maichu__gt=F('kucun'))
    print(res)


将所有商品的价格提高100块

models.Product.objects.update(price=F('price')+100)


将所有商品的名字后面都加上一个爆款

from django.db.models.functions import Concat
    from django.db.models import Value
    models.Product.objects.update(name=Concat(F('name'),Value('爆款')))


Q查询


<1> 查询价格是288.88并且名字是衣服同款爆款的商品(与查询)

from django.db.models import Q
    from django.db.models import Q

    res = models.Product.objects.filter(Q(price='288.88'),Q(name='衣服爆款'))
    # 这里 第一个Q参数后面必须是传字符串,如果传数字(Q(price=288.88)),无法查询出对象
    print(res)


<2> 查询价格是288.88或者名字是帽子同款爆款的商品(或查询)

from django.db.models import Q
res = models.Product.objects.filter(Q(price='288.88') | Q(name='裤子爆款'))  # or
    print(res)
  # <QuerySet [<Product: 对象的名字:衣服爆款>, <Product: 对象的名字:裤子爆款>]>


<3> 查询价格不是288.88并且名字是裤子爆款的商品

混合使用 需要注意的是Q对象必须放在普通的过滤条件前面

res=models.Product.objects.filter(~Q(price='288.88'),Q(name='裤子爆款'))
print(res)


<4> 查询价格不是288.88或者名字是裤子爆款的商品

res=models.Product.objects.filter(Q(name='裤子爆款')|~Q(price='288.88'))
print(res)


Q对象补充

Q的源码

class Q(tree.Node):
    """
    Encapsulates filters as objects that can then be combined logically (using
    `&` and `|`).
    """
    # Connection types
    AND = 'AND'
    OR = 'OR'
    default = AND

    def __init__(self, *args, **kwargs):
        super(Q, self).__init__(children=list(args) + list(kwargs.items()

Q本身就是一个类,实例化一个对象,将所有的条件传入children这个属性中,而children这个属性是是列表,将条件写成一个小元组的方式作为一个整体传入children这个列表,小元组的第一个元素是字段名,第二个元素是写希望字段名符合的条件


例如

Q=q()

q.children.append((‘字段名’,‘条件’))


<1> 查询价格是288.88或者名字是帽子同款爆款的商品

  from django.db.models import F, Q 
  q = Q()
  q.connector = 'or'
  q.children.append(('price', '288.88'))
  q.children.append(('name', '裤子爆款'))
  res = models.Product.objects.filter(q) # # Q对象查询默认也是and
    print(res)


<2> 查询价格是288.88或者名字是衣服爆款的商品

  from django.db.models import F, Q 
  q = Q()
  q.children.append(('price', '288.88'))
  q.children.append(('name', '衣服爆款'))
  res = models.Product.objects.filter(q) # # Q对象查询默认也是and
    print(res)


事务

事务的ACID

原子性
一致性
隔离性
持久性

id=1的商品卖出去一件

    from django.db import transaction
    from django.db.models import F

    with transaction.atomic():
        # 在with代码块儿写你的事务操作
        models.Product.objects.filter(id=1).update(kucun=F('kucun') - 1)
        models.Product.objects.filter(id=1).update(maichu=F('maichu') + 1)


自定义ORM字段


models.py

from django.db import models


class MycharField(models.Field):
    def __init__(self,max_length,*args,**kwargs):
        self.max_length=max_length
        super().__init__(max_length=max_length,*args,**kwargs)

    def db_type(self,connection):
        return 'char(%s)'%self.max_length


class Product(models.Model):
    name = models.CharField(max_length=32) # 都是类实例化的对象
    price = models.DecimalField(max_digits=8, decimal_places=2)
    maichu = models.IntegerField()
    kucun = models.IntegerField()
    info=MycharField(max_length=32,null=True) # 该字段可以为空

    def __str__(self):
        return '对象的名字:%s'%self.name


执行manage.py命令

菜单-tools-Run manager.py Task
$ makemigrations
$ migrate


only与defer

res = models.Product.objects.filter(id=1).values('name').first()
print(res)

这个过程中执行了3条sql语句

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SELECT `app01_product`.`name` FROM `app01_product` WHERE `app01_product`.`id` = 1 LIMIT 21; args=(1,)

only

如果取only指定的字段,不去数据库取值,直接在应用程序的缓存中取值

案例1

res=models.Product.objects.filter(pk=1).only('name').first()
print(res.name)

这个过程执行了3条SQL语句

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SELECT `app01_product`.`id`, `app01_product`.`name` FROM `app01_product` WHERE `app01_product`.`id` = 1 ORDER BY `app01_product`.`id` ASC LIMIT 1; args=(1,)


案例2

res=models.Product.objects.filter(pk=1).only('name').first()
print(res.price)

这个过程中执行了4条SQL语句,因为price字段不在only里面配置,所以price字段的值是去数据库里面取

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SELECT `app01_product`.`id`, `app01_product`.`name` FROM `app01_product` WHERE `app01_product`.`id` = 1 ORDER BY `app01_product`.`id` ASC LIMIT 1; args=(1,)
(0.000) SELECT `app01_product`.`id`, `app01_product`.`price` FROM `app01_product` WHERE `app01_product`.`id` = 1; args=(1,)


defer

与only相反,如果取defer指定的字段,则是去数据库取值,其他的字段直接在应用程序的缓存中取值


案例1

res=models.Product.objects.filter(pk=1).defer('name').first()
print(res.name)

执行了4条SQL语句

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SELECT `app01_product`.`id`, `app01_product`.`price`, `app01_product`.`maichu`, `app01_product`.`kucun`, `app01_product`.`info` FROM `app01_product` WHERE `app01_product`.`id` = 1 ORDER BY `app01_product`.`id` ASC LIMIT 1; args=(1,)
(0.000) SELECT `app01_product`.`id`, `app01_product`.`name` FROM `app01_product` WHERE `app01_product`.`id` = 1; args=(1,)


案例2

res=models.Product.objects.filter(pk=1).defer('name').first()
print(res.price)

执行了3条SQL语句

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.001) SELECT `app01_product`.`id`, `app01_product`.`price`, `app01_product`.`maichu`, `app01_product`.`kucun`, `app01_product`.`info` FROM `app01_product` WHERE `app01_product`.`id` = 1 ORDER BY `app01_product`.`id` ASC LIMIT 1; args=(1,)


字段

choices

models.py

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=32) # 都是类实例化的对象
    price = models.DecimalField(max_digits=8, decimal_places=2)
    maichu = models.IntegerField()
    kucun = models.IntegerField()
    info=MycharField(max_length=32,null=True) # 该字段可以为空

    choices=((1,'男'),(2,'女'),(3,'其他'))
    gender=models.IntegerField(choices=choices,default=2)

    def __str__(self):
        return '对象的名字:%s'%self.name


更新字段操作

菜单-tools-Run manager.py Task
$ makemigrations
$ migrate


tests.py

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ORM2.settings")
    import django

    django.setup()
    from app01 import models  
    res=models.Product.objects.filter(id=1).first()
    print(res.get_gender_display()) # 获取编号对应的中文注释

猜你喜欢

转载自www.cnblogs.com/cjwnb/p/11802810.html