Django 模型

ORM
映射关系:
表名  <-------> 类名
字段  <-------> 属性
表记录 <------->类实例对象

Django 连接mysql:
setting.py

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


在项目文件夹下的__init__.py:
import pymysql
pymysql.install_as_MySQLdb()
为app配置单独的数据库:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'bms',      
        'USER':'root', 
        'PASSWORD':'', 
        'HOST':'127.0.0.1',       
        'PORT':3306         
    },
    'app01': { #可以为每个app都配置自己的数据,也可以指定sqlite等其他的数据库
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'bms',      
        'USER':'root',
        'PASSWORD':'',  
        'HOST':'127.0.0.1',       
        'PORT':3306         }
} 


mysql数据库名必须在连接前已经创建。数据库同步命令,在写好对应的model后运行该命令将数据写入数据库
python manage.py makemigrations
python manage.py migrate

def query(request):
    # 创建一条记录,增

    new_obj = models.UserInfo(
        id=2,
        name='子文',
        bday='2019-09-27',
        checked=1,

    )
    new_obj.save()  #翻译成sql语句,然后调用pymysql,发送给服务端  insert into app01_userinfo values(2,'子文','2019-09-27',1)

    return HttpResponse('xxx')


常用字段及参数:

CharField, 字符串字段,用于较短字符串, 要求必须有maxlength, 允许的最大字符数
IntegerField,保存一个整数
DecimalField, 一个浮点数,必须提供max_digits,不包括小数点和符号的总位数,decimal_places,小数位数
AutoField, 一个IntegerField,添加记录时它会自动增长。
BooleanField, True,False 用于单项选择框
TextField,大文本字段,<textarea>标签表示 一个多选文本编辑框
EmailField, 带有检查Email合法性的CharField,不接受maxlength
DateField, 一个日期字段 ,有:Argument,描述;auto_now,对象被保存时更新(更新或者添加都行),自动设置为当前时间,用于last-modified;auto_now_add,当对象
被首次创建时,自动将该字段的值设置为当前时间。
DateTimeField,日期时间字段,与DateField有相同的附加选项
ImageField, 有height_field, width_field两个可选参数,如果提供将按提供的高宽保存
FileField, 文件上传字段, 必须指定upload_to,指定文件保存的路径,如果有这个字段,一定要在settings中设置MEDIA_ROOT
UrlField,用于保存url, 有verify_exists参数,会预先检查是否存在,若没有则返回404
NullBooleanField, 类似BooleanField 允许 Null作为其中一个选项。
SlugField, 小标签, 只包含字母,数字,下划线和连字符,通常用于urls
XMLField,校验值是否为合法xml的TextField,必须提供参数schema_path,用来校验文本的RelaxNG schema的文件系统路径
FilePathField,可选项目为某个目录下的文件名,有三个参数,path 必须,一个目录的绝对文件路径,FilePathField据此得到可靠项目,math可选,正则表达式,
FilePathField使用它过滤文件名,recursive可靠参数,可设置为True,或False,
IPAddressField,字符串形式的IP地址
CommaSeparatedIntegerField,用于存放逗号分隔的整数值,类似CharField,必须指定max_length

参数
null, 如果为True, 将在数据库中存储空值,默认为False
blank,如果为True,该字段允许不填
default,字段的默认值,可以是一个值或者可调用对象
primary_key,如果为True,那么这个字段就是模型的主键
unique,如果该值设置为True,这个数据字段的值在整张表中必须是唯一的
choices, 由二元元组组成的一个可迭代对象,用来给字段提供选选择项
db_index, 如果db_index为True,则代表为该字段设置数据库索引

django字段与sql字段的对应关系

'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)', 

创建表(建立模型)
实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
模型建立如下:

from django.db import models
from django.utils import timezone

# Create your models here.


class Author(models.Model):
    name = models.CharField(verbose_name='姓名', max_length=32)
    age = models.IntegerField(verbose_name='年龄')
    author_detail = models.OneToOneField(to="AuthorDetail")

    class Meta:
        verbose_name_plural = verbose_name = '作者'

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    birthday = models.DateField(verbose_name='生日')
    telephone = models.CharField(verbose_name='电话', max_length=11)
    addr = models.CharField(verbose_name='地址', max_length=64)


class Press(models.Model):
    name = models.CharField(verbose_name='社名', max_length=32)
    city = models.CharField(verbose_name='所在城市', max_length=32)

    class Meta:
        verbose_name_plural = verbose_name = '出版社'

    def __str__(self):
        return self.name


class Book(models.Model):
    name = models.CharField(verbose_name='书名', max_length=20, )
    price = models.DecimalField(verbose_name='价格', max_digits=5, decimal_places=2)
    publish_date = models.DateField(verbose_name='出版日期', default=timezone.now)
    press = models.ForeignKey(to='Press', related_name='press_book')
    author = models.ManyToManyField(to='Author', related_name='author_book')

    class Meta:
        verbose_name_plural = verbose_name = '书籍'

    def __str__(self):
        return self.name 

    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author')

通过logging可以查看翻译成的sql语句

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
} 

注意事项:
1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称
2、id 字段是自动添加的
3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
4、这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。


增删改查

方式1:
   

 new_obj = models.UserInfo(
        name='子文',
        bday='2019-09-27',
        checked=1,
    )
    new_obj.save() 


方式2:
        # 有返回值,ret 是创建的新的记录的model对象(重点)
 

      ret = models.UserInfo.objects.create(
        name='卫贺',
        bday='2019-08-07',
        checked=0
    )

删:

#简单查询:filter()  -- 结果是queryset类型的数据里面是一个个的model对象,类似于列表

        models.UserInfo.objects.filter(id=7).delete()  #queryset对象调用
        models.UserInfo.objects.filter(id=7)[0].delete()  #model对象调用

改:
方式一:
# 注意不能对单个object用update,没有该方法。而只有queryset有该方法
    models.UserInfo.objects.filter(id=2)[0].update(
        name='新名+2',
    )
下面这样是不可以的。
 models.UserInfo.objects.filter(id=2).update(
        name='新名+2',
    )
但可以这样更新:
models.UserInfo.objects.filter(id=2)[0].save(update_fields='name')
方式二:
    
 ret = models.UserInfo.objects.filter(id=2)[0]
    ret.name = '新名+2'
    ret.checked = 1
    ret.save() 

更新时的auto_now参数
    # 更新记录时,自动更新时间,创建新纪录时也会帮你自动添加创建时的时间,但是在更新时只有使用save方法的方式2的形式更新才能自动更新时间。
因为update直接作用在数据库,但auto_now是通过Python来获取的。
    now2 = models.DateTimeField(auto_now=True,null=True)批量插入

book_list = []
    for i in range(10):
        bk_obj = models.Book(
            name=f'book{i}',
            addr='北京%s'%i
        )
        book_list.append(bk_obj)

    models.Book.objects.bulk_create(book_list) #批量插入,速度快 

update_or_create(defaults=None, **kwargs)
kwargs:用来更新对象或创建一个新的对象
defaults;由field, value组成的字典,用来更新对象
返回值;object, 创建或者被更新的对象,created,标示是否创建新对象的boolean值

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in updated_values.iteritems():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    updated_values.update({'first_name': 'John', 'last_name': 'Lennon'})
    obj = Person(**updated_values)
    obj.save()
# 如果模型的字段数量较大的话,这种模式就变的非常不易用。上面的示例可以用 update_or_create() 重写:
obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values) 


 

查询表记录
 all():     查询所有结果
 filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
 values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列,
values内部字段涉及反向查询时不需要_set
 values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 order_by(*field):      对查询结果排序 
 reverse():             对查询结果反向排序
 distinct():            从返回结果中剔除重复纪录
 count():              返回数据库中匹配查询(QuerySet)的对象数量。
 first():              返回第一条记录
 last():               返回最后一条记录
 exists():             如果QuerySet包含数据,就返回True,否则返回False 

注意:一定区分object与querySet的区别 !!!

双下划线之单表查询
models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and
models.Tb1.objects.filter(pub_date__year=2019), 过滤指定年份,同样有month, day
startswith,istartswith, endswith, iendswith


创建一对一关系时的一些参数:

to, 设置关联的表
to_field 关联的字段
on_delete,

创建一对多关系时的一些参数
to, 设置要关联的表
to_field, 设置要关联的字段
related_name, 反向操作时,使用的字段名,用于代替原反向查询时的‘表名_set'
related_query_name,反向查询操作时,使用的连接前缀,用于替换表名
on_delete,当删除关联表中的数据时,当前表与有关联的行的行为

创建多对多字段时的参数:
to,要关联的表
related_name, 反向操作时,使用的字段名,用于代替原反向查询的‘表名_set'
related_query_name,反向查询 操作时,使用的连接前缀,用于替换表名
through,使用ManyToManyField字段时,Django将自动生成一张表来管理多对多关关系,也可以通过
手动创建第三张表,用throug指定第三张表名
through_fields设置关联的字段
db_table,创建第三张表时,在数据库中的名称

创建表时的元信息设置

db_table, ORM数据库中的表名默认是app_类名,可以通过db_table重写表名。
index_together, 联合索引
unique_together,联合唯一索引
ordering, 指定按什么字段排序(只有排序过的结果才能反转)

获取元信息
如:
book = Book.objects.get(id=1)
book._meta.verbose_name,获取通过verbose_name指定的表名
book._meta.model_name获取小写的表名
book._meta.app_label,获取对象app的应用名

ondelete选项:
models.CASCADE 删除关联数据时,与之关联的数据也删除
models.DO_NOTHING, 
models.PROTECT
models.SET_NULL, 删除关联数据,与之关联的值设置为Null
models.SET_DEFAULT, 删除关联数据,与之关联的值设置为默认值
models.SET 删除关联数据,与之关联的值设置为指定值 ,models.SET(value), 也可以是可执行对象的返回值,models.SET(obj)

ForeignKey中的db_constraint参数
不回外键也能表示 两个表之间的关系,但是这样就不能使用ORM外键相关的方法了。当db_constrain=False只加了两会的关系,但没有
强制约束效果,但ORM相关的接口还能使用。

添加表记录
一对多
方式一
press_obj = Press.objects.get(id=1)                                                                                   
book_obj = Book.objects.create(name='python', price=100, publish_date='2019-01-1',press=press_obj) 
在数据库中press保存为press_id,其实上将press_obj.id取出来 赋值给press_id.
方式二
book_obj = Book.objects.create(name='python', price=100, publish_date='2019-01-1', press_id=1)

多对多
方式一

book_obj = Book.objects.create(name='go',price=120,publish_date='2019-01-20', publish_id=1)
author_obj1= Author.objects.get(id=1)
author_obj2 = Author.objects.get(id=2)
book_obj.author.add(author_obj1, author_obj2)


方式二

book_obj.author.add(1,2) # 1,2为两作者的id
book_obj.author.add(*[1,2])

多对多关系的其它常用api
book_obj.author.remove(), 将某个特定的对象从被关联对象集合中去除
book_obj.author.clear(), 将关联对象的集合清空
book_obj.author.set(),先清空再设置新的关联关系

直接赋值:
通过赋值一个新的可迭代的对象,关联对象集可以被整体替换掉。
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list
如果外键关系满足null=True,关联管理器会在添加new_list中的内容之前,首先调用clear()方法来解除关
联集中一切已存在对象的关联。否则, new_list中的对象会在已存在的关联的基础上被添加。


基于对象的跨表查询 
一对多查询(Publish 与 Book)

classBook(models.Model):
    #书籍
    name=models.CharField(verbose_name='书名',max_length=20,)
    price=models.DecimalField(verbose_name='价格',max_digits=5,decimal_places=2)
    publish_date=models.DateField(verbose_name='出版日期',default=timezone.now)
    press=models.ForeignKey(to='Press',related_name='press_book')
    author=models.ManyToManyField(to='Author',related_name='author_book')
    
class Press(models.Model):
    # 出版社
    name = models.CharField(verbose_name='社名', max_length=32)
    city = models.CharField(verbose_name='所在城市', max_length=32)


关联属性字段所在的表  查询被关联表的记录  就是正向查询,反之就是反向查询
 正向查询按字段, 反向查询表名(小写)_set.all()

正向查询(按字段:press):
# 查询id=1的书籍的出版社所在的城市
book_obj=Book.objects.get(id=1)
print(book_obj.press.city) 

反向查询按表名:book_set.all()
# 查询 人民出版社出版过的所有书籍
 press=Press.objects.get(name="人民出版社")
 book_list=press.book_set.all()  # press.press_book.all()与人民出版社关联的所有书籍对象集合

一对一查询(Author 与 AuthorDetail)
正向查询(按字段:authorDetail):
# 查询Andy作者的手机号
class Author(models.Model):
    # 作者
    name = models.CharField(verbose_name='姓名', max_length=32)
    age = models.IntegerField(verbose_name='年龄')
    author_detail = models.OneToOneField(to="AuthorDetail")

class AuthorDetail(models.Model):
    # 作者详情
    birthday = models.DateField(verbose_name='生日')
    telephone = models.CharField(verbose_name='电话', max_length=11)
    addr = models.CharField(verbose_name='地址', max_length=64)

andy = Author.objects.get(name='Andy')
andy_detail = andy.author_detail.telephone # 正向查询按字段


反向查询(按表名:author):
# 查询所有住址在北京的作者的姓名
author_detail_list = AuthorDetail.objects.filter(addr='beijing")
name_list = [author_detail.author.name for author_detail in author_detail_list] # 因为是一对一,没有set.all()

多对多查询 (Author 与 Book)
注意:
你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。

正向查询(按字段:authors):
python所有作者的名字,电话号码(电话在authordetail表中)
book_obj = Book.objects.filter(name='python').first()
author_list = book_obj.author.all()
for author in author_list:
    print(author.name, author.authordetail.telephone)
反向查询(按表名:book_set):
查询andy出过的所有书的名字
author_obj = Author.objects.get(name='andy')
book_list = author_obj.book_set.all() # 因为定义related_name="author_book", 所以这里可以用author_obj.author_book.all()
for book in book_list:
    print(book.name)

基于双下划线的跨表查询 
Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

正向查询按字段,反向查询按表名小写

# 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
# 正向查询 按字段:press
res = Book.objects.filter(press__name='人民币出版社').values_list('name','price')
# 反向查询 按表名:book
# 因为我的model中定义了related_name为press_book, 所以下面为press_book__name, 如果没有定义为book__name
res2 = Press.objects.filter(name='人民币出版社').values('press_book__name', 'press_book__price')


# 练习2: 查询Jack出过的所有书籍的名字(多对多)
# 正向查询 按字段:authors:
jack_books = Book.objects.filter(author__name ='Jack').values('name')
 # 反向查询 按表名:book
 # related_name 为author_book
jack_books = Author.objects.filter(name='Jack').values("author_book__name")
 
# 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
# 正向查询
res = Book.objects.filter(press__name='人民币出版社').values('name', 'author__name')
 # 反向查询
res = Press.objects.filter(name='人民币出版社').values('press_book__name', 'press_book__author__name')

# 练习4: 手机号以180开头的作者出版过的所有书籍名称以及出版社名称
正向查询 
 res=Book.objects.filter(author__author_detail__telephone='180').values('name','press__name')
反向查询:
res = AuthorDetail.objects.filter(telephone='180').values('author__author_book__name', 'author__author_book__press__name')
 注意:
反向查询时,如果定义了related_name ,则用related_name替换表名

聚合查询与分组查询
聚合:aggregate(*args, **kwargs)
# 计算所有图书的平均价格
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的
名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,
如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

分组:annotate()
为QuerySet中每一个对象都生成一个独立的汇总值。
(1) 练习:统计每一本书的作者个数
bookList=Book.objects.annotate(authorsNum=Count('authors'))
for book_obj in bookList:
    print(book_obj.title,book_obj.authorsNum)

SELECT 
"app01_book"."nid", 
"app01_book"."title", 
"app01_book"."publishDate", 
"app01_book"."price", 
"app01_book"."pageNum", 
"app01_book"."publish_id", 
COUNT("app01_book_authors"."author_id") AS "authorsNum" 
FROM "app01_book" LEFT OUTER JOIN "app01_book_authors" 
ON ("app01_book"."nid" = "app01_book_authors"."book_id") 
GROUP BY 
"app01_book"."nid", 
"app01_book"."title", 
"app01_book"."publishDate", 
"app01_book"."price", 
"app01_book"."pageNum", 
"app01_book"."publish_id"

(2) 如果想对所查询对象的关联对象进行聚合:
练习:统计每一个出版社的最便宜的书
    publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
    
    for publish_obj in publishList:
        print(publish_obj.name,publish_obj.MinPrice)
annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:
queryResult= Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
print(queryResult)

方式2:
queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min('price'))

注意:values内的字段即group by的字段
(3) 统计每一本以py开头的书籍的作者个数:
 queryResult=Book.objects.filter(title__startswith="Py").annotate(num_authors=Count('authors'))

(4) 统计不止一个作者的图书:
queryResult=Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
(5) 根据一本图书作者数量的多少对查询集 QuerySet进行排序:
Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
(6) 查询各个作者出的书的总价格:

# 按author表的所有字段 group by
queryResult=Author.objects.annotate(SumPrice=Sum("book__price")).values_list("name","SumPrice")
     print(queryResult)
    
#按authors__name group by
    queryResult=Book.objects.values("authors__name").annotate(SumPrice=Sum("price")).values_list("authors__name","SumPrice")
print(queryResult2)

F查询与Q查询
F查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# 查询评论数大于收藏数的书籍
   from django.db.models import F
   Book.objects.filter(commnetNum__lt=F('keepNum'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
# 查询评论数大于收藏数2倍的书籍
    Book.objects.filter(commnetNum__lt=F('keepNum')*2)
修改操作也可以使用F函数,比如将每一本书的价格提高30元:
Book.objects.all().update(price=F("price")+30)

Q查询
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。
from django.db.models import Q
Q(title__startswith='Py')
Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
bookList=Book.objects.filter(Q(author__name="Jack")|Q(authors__name="小黑"))

等同于下面的SQL WHERE 子句:
    WHERE name ="Jack" OR name ="小黑"
你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,
这允许组合正常的查询和取反(NOT) 查询:
    bookList=Book.objects.filter(Q(authors__name="Jack") & ~Q(publishDate__year=2017)).values_list("title")
查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。
但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:
    bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                                  title__icontains="python"
                                 )
 

上一篇:django inclusion_tag

下一篇:Django redirect temporary or permanent