Day45 of learning python --Django的ORM操作(model操作)

 一、ORM简介

  ORM实现了数据模型和数据库的解耦,即数据模型的设计不需要依赖特定的数据库,通过简单的配置就可更换数据库。

  ORM是‘对象-关系-映射’的简称

 

二、单表操作

1.创建表

1)django项目下,在model.py中创建数据库表(一个类代表一个表,类的对象相当于一列数据)

from django.db import models
q
class UserGroup(models.Model):    # 类名就相当于表名,创建成功时,在数据上表名会显示成:app名字+类名,中间用下划线隔开:例如app01_UserGroup,当使用的是models的点数据库表时,直接使用类名,而当使用sql语句时,要使用:app名字+类名
    # 部门
    tittle = models.CharField(max_length=32)
    class Meta:                   # 这是把数据库中的表名直接设置成UserGroup
        db_table = 'UserGroup'

class UserInfo(models.Model):   # 创建一个表
    # 员工
    nid = models.BigAutoField(primary_key=True)       # nid字段名,BigAutoFieleField是自增长类型。当model中如果没有自增列,则自动会创建一个列名为id的列
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    # age = models.IntegerField(null=True)
    age = models.IntegerField(default=1)
    # ug_id
    ug = models.ForeignKey('UserGroup',on_delete=models.CASCADE,null=True)   # 一个对象代指一行数据  外键

 2)字段和参数

AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    自定义无符号整数字段

        class UnsignedIntegerField(models.IntegerField):
            def db_type(self, connection):
                return 'integer UNSIGNED'

        PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
            '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)',

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
各字段的内容
 null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    db_tablespace
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空。
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )
参数
(1)blank
 
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
 
(2)default
 
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
 
(3)primary_key
 
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。
 
(4)unique
 
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
 
(5)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
常用参数

 3)Django下修改setting默认配置,用来连接pymysql数据库

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'d70django',     #库名,这个要我们先在数据库里创建一个库
        'USER':'root',            #连接数据库的用户名
        'PASSWORD':'baicells',            #连接数据库的密码
        'HOST':'127.0.0.1',       #本机ip
        'PORT':3306               #端口默认3306
    }
先把settings里面的databases给删除了,再写上自己的数据库的信息。

 4)配置app01下的__init__.py文件

因为Django默认你导入的驱动的是MySqldb,但是我们用的是pymysql,所以,我们把pymysql伪装成MySQLdb,让django识别

import pymysql
pymysql.install_as_MySQLdb()

5)在pycharm下的terminal终端下输入指令来创建表结构

python manage.py makemigrations
等待跑完之后输入
python manage.py migrate

 2.添加表结构

在视图函数输入创建表数据的代码,如果通过路由调用,进行创建数据

1)方式一

在视图函数下输入下面代码
UserType_obj = UserType(title='超级用户') # 实例化一个对象
UserType_obj.save()    # 加上save()方法

 2)方式二

book_obj=models.book.objects.create(name='python',price=20) #每一个定义的字段都要给值,自增长的不用,该create的返回值是新建的数据行

 三、models的基本操作-增删改查

1)查

queryset对象就是有实例化对象组成的集合,这和JQuery对象与DOM对象关系差不多
<1> all():                  查询所有结果       得到queryset对象
  
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象    queryset对象
  
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,      实例化对象
                            如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象        queryset对象
 
<5> order_by(*field):       对查询结果排序                    queryset对象
  
<6> reverse():              对查询结果反向排序                 queryset对象       只能和order_by搭配使用
  
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。
  
<9> first():                返回第一条记录            得到模型类对象
  
<10> last():                返回最后一条记录          得到模型类对象
  
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False
 
<12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<14> distinct():            从返回结果中剔除重复纪录
Book.objects.filter(price__in=[100,200,300])    可以找出price=100,或price=200,或price=300
Book.objects.filter(price__gt=100)             可以找出price>100的
Book.objects.filter(price__lt=100)             可以找出price<100的
Book.objects.filter(price__range=[100,200])    可以找出price在100到200之间的
Book.objects.filter(title__contains="python")    可以找出title里包含‘python’的
Book.objects.filter(title__icontains="python")   和上面一样,只是不区分大小写
Book.objects.filter(title__startswith="py")      可以找出title里以‘py’开头的
Book.objects.filter(pub_date__year=2012)         可以找出pub_date是2012年的

 2)增

models.Tb1.objects.create(c1='xx', c2='oo')  增加一条数据,可以接受字典类型数据 **kwargs

 

# 一次性增加多条数据
models.UserAdmin.objects.bulk_create([models.UserAdmin(user='egon',password='egon1'), models.UserAdmin(user='egon1',password='egon2') ])

 

 3)删

models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
obj.delete()     #obj可以使queryset对象,也可以是实例化对象

 4)改

 models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
 obj = models.Tb1.objects.get(id=1)
 obj.c1 = '111'
 obj.save()                                                 # 修改单条数据

 5)练习

1,查询人民出版社的价格大于200的书籍
models.book.objects.all().filter(publish='人民出版社',price__gt=200)
2,查询2017年8月出版的所有以py开头的书籍名称
models.book.objects.all().filter(pub_date__year=2017,pub_date__month=8,name__startswith='py').values('name')
3,查询价格为50,100或150的所有书籍名称和出版社名称
models.book.objects.all().filter(price__in=[50,100,150]).values('name','publish')
4,查询价格在100到200之间的所有书籍名称及其价格
models.book.objects.all().filter(price__range=[100,200]).values('name','price')
5,查询所有人民出版社出版的书籍的价格(从高到低排序,去重)
models.book.objects.all().filter(publish="人民出版社").values("price").order_by('-price').distinct()

 四、一对多关系的跨表查询

一本书只有一个出版社,一个出版社可以出版多本书,从而书与出版社之间就构成一对多关系,书是‘多’的一方,出版社是‘一’的一方,我们在建立模型的时候,把外键写在‘多’的一方,即我们要把外键写在book类。

from django.db import models

# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=16)
    price = models.IntegerField()
    publish = models.ForeignKey('Publish',on_delete=models.CASCADE)

class Publish(models.Model):
    name = models.CharField(max_length=16)
    addr = models.CharField(max_length=16)
    phone = models.IntegerField()

# 在创建模型时不用创建id字段,在makemigrations命令输入之后,它会在migrations文件夹下生产一个py文件记录models.py里面所有的改动,在记录的时候就会自动给你加上自增长的主键字段id。
 # 基于对象跨表查询
    # 一对多查询,正向查询(按外键字段:publish)
    book_obj = models.Book.objects.all().first()   # 查询第一个book对象
    # book_obj.publish 是book对象关联的出版社对象
    print(book_obj.publish.name,book_obj.publish.addr,type(book_obj))

    # 反向查询(按表名小写_set:book_set)
    publish_obj = models.Publish.objects.get(name='电子出版社')
    # publish_obj.book_set.all()   与电子出版社关联的所有书籍对象的集合
    book_list = publish_obj.book_set.all()
    print(type(book_list))
    for row in book_list:
        print(row.name)

    # 利用双下划线跨表--正向查询 按外键字段:publish
    # 查询书对应的出版社的名字
    ret = models.Book.objects.filter(id=1).values('publish__name')
    print(ret)
    ret = models.Book.objects.filter(id=1).values_list('publish__name')
    print(ret)
    # 查询人民出版社出版过的所有书籍的名字和价格
    ret = models.Book.objects.filter(publish__name='人民出版社').values('name','price')
    print(ret)

    # 利用双下划线跨表--反向查询  按表名:book
    ret = models.Publish.objects.filter(name='华南理工出版社').values('book__name','book__price')
    print(ret)

五、一对一关系的跨表查询

一个作者只能对应一个作者详细信息表,他们之间就是一对一关系,这和多对多一样的,关系写在哪张表都是可以的

class Author(models.Model):
    name = models.CharField(max_length=16)
    age = models.IntegerField()
    author_info = models.OneToOneField('Author_Info',on_delete=models.CASCADE)  # 第二个参数是,自动跟随删除,当作者不在了,随作者的信息也会删除
    class Meta:
        db_table = 'author'


class Author_Info(models.Model):
    gf_name = models.CharField(max_length=10)
    phone = models.IntegerField()
    card = models.IntegerField()
 # 一对一查询
    # 基于对象跨表查询--正向查询 按外键字段查询:author_info
    obj = models.Author.objects.filter(name='天青色等烟雨').first()
    print(obj.author_info.gf_name,obj.author_info.card)

    # 基于对象跨表查询--反向查询 按表名小写:author
    obj = models.Author_Info.objects.filter(id=1).first()
    print(obj.author.name)

    # 基于双下划线的跨表查询,正向按外键字段,方向按表名小写
    # 正向查询
    obj = models.Author.objects.filter(id=1).values('author_info__card')
    print(obj)

    # 反向查询
    obj = models.Author_Info.objects.filter(author__age=18).values('phone','card')
    print(obj)
    obj = models.Author_Info.objects.filter(id=1).values('author__age', 'author__name')
    print(obj)

六、多对多关系的跨表查询

一本书可以有多个作者,一个作者可以写多本书,从而书和作者就构成了多对多的关系,我们在创建模型的时候,把多对多关系写在其中的任何一张表都可以。

class Book1(models.Model):
    name = models.CharField(max_length=16)
    price = models.IntegerField()
    publish = models.CharField(max_length=16)
    author1 = models.ManyToManyField('Author1',db_table='book_author')   # 多对多关系时,有第三张表的形成,第二个参数为把关系表的名字改为‘book_author’,如果不写,名字会是应用名_本模型名的小写_另一张模型名的小写。如‘app_book_author’
    class Meta:
        db_table='book1'

class Author1(models.Model):
    name= models.CharField(max_length=16)
    age = models.IntegerField()
    class Meta:
        db_table = 'author1'
 # 多对多查询
    # 基于对象跨表查询--正向查询 按外键字段查询:author
    # 查询<python基础教程>所有作者以年龄
    obj = models.Book1.objects.filter(name='python基础教程').first()
    authors = obj.author1.all()
    for row in authors:
        print(row.name,row.age)

    # 基于对象跨表查询--反向查询 按表名小写_set:book1_set
    # 查询作者出过的所有书的名称
    obj = models.Author1.objects.filter(name='林玮任').first()
    books = obj.book1_set.all()
    for row in books:
        print(row.name)

    # 基于双下划线的跨表查询
    # 正向查询按外键字段 :author1__name
    # 查询作者出过的所有书的名称
    obj = models.Book1.objects.filter(author1__name='林玮任').values('name')
    print(obj)

    # 反向查询按表名:book
    obj = models.Author1.objects.filter(name='林玮任').values('book1__name')
    print(obj)

补充:related_name设置

可以通过Foreignkey和MangToMangField的定义中设置related_name的值来复写foo_set的名称。
publish=ForeignKey('Publish',related_name='booklist')    #这样之后,反向就不用表名_set,就用booklist
# 查询 人民出版社出版过的所有书籍
publish=Publish.objects.get(name="人民出版社")
book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合

七、聚合查询与分组查询

1)聚合,aggregate(*args,**kwargs)

aggregate(*args,**kwargs)是Queryset的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是按照字段和聚合函数的名称自动生成出来的
计算所有图书的平均价格
from django.db.models import Avg
Book.objects.all().aggregate(Avg('price'))
结果:{'price__avg': 34.35}
如果你想要为聚合值指定一个名称,可以向聚合函数前面用一个变量名来接收,此时,键的名称就变为接收的变量名
Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}
在终止子句里面可以放多个聚合函数,得到结果就是有多个键值对
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')}
aggregate()只能对一个分组有用,对于按某字段分完组后的n个组,此时aggregate()就不能循环对每个分组作用,它只会得到第一组的结果

2)分组

单表分组查询

查询每一个部门名称以及对应的员工数
emp:
id  name age   salary    dep
1   alex  12   2000     销售部
2   egon  22   3000     人事部
3   wen   22   5000     人事部
emp.objects.values('dep').annotate(c=Count('*'))
values(‘dep’)就是按‘dep’进行分组
annotate()对每个分组的进行操作

多表分组查询

每一个出版社的名称和出版过的书籍个数
Publish.objects.values('name').annotate(c=Count('book'))     #首先读整个语句,当读到‘book’时,就会把两个表连起来,然后在按Publish.name分组
跨表分组查询本质就是将关联表join成一张表,然后再按单表的思路进行分组查询

还有一种写法:
publishlist=Publish.objects.annotate(c=Count('book'))    这相当于给Publish表添加了一个‘c’字段。首先也是把两张表连起来,以Publish分组,计算每个Publish的书籍数量
publishlist是一个queryset对象集合,里面放的是publish模型类对象,只是现在的对象比之前多了一个‘c’字段
for publish in publishlist:
  print(publish.name,publish.c)   利用for循环就可以遍历出每个模型类对象,然后用句点符‘.’就可以取得任何字段的值
我们也可以不用for循环,直接用values_list()就可以实现,如上面的for循环可以写成:values_list('name','c')

统计每一本书的作者个数
Book.objects.annotate(c=Count('author')).values_list('name','c')

filter()放在annotate()前面就是相当于where
统计每一本以py开头的书籍的作者的个数:
Book.objects.filter(name__startswith='py').annotate(c=Count('author')).values_list('name','c')

filter()放在annotate()后面就相当于having
统计作者个数大于1的书籍:
Book.objects.annotate(c=Count('author')).filter(c__gt=1).value_list('name','c')

根据书籍的作者数来排序:
Book.objects.annotate(c=Count('author')).orderby('c')

八、F查询与Q查询

F,更新时用于获取原来的值。Q,用于构造复杂的查询条件

1)F查询

from django.db.models import F
在之前,对象的字段只能放在比较符的前面,比如filter(id__gt=2),但现在,有一个表,有生物成绩ss字段和物理成绩ws字段,统计物理成绩高于生物成绩的学生:
student.objects.filter(ws__gt=ss)    这样写肯定是报错的,因为字段写在了比较符后面,但此时我们借助F查询就可以不报错了,正确写法如下:
student.objcts.filter(ws__gt=F('ss'))   F('ss')此时就是把ss字段的值取出来,就相当于一个纯数字了,可以进行加减乘除操作

查询物理成绩大于生物成绩两倍的学生
student.objects.filter(ws__gt=F('ss')*2)

把每个学生的物理成绩加上10分:
student.objects.all().update(ws=F('ws')+10)

2)Q查询

 # q使用有两种方式:对象方式,方法方式
    # 对象方式
    from django.db.models import Q
    models.UserInfo.objects.filter(Q(id=1))
    models.UserInfo.objects.filter(Q(id=1) | Q(id=2))    #
    models.UserInfo.objects.filter(Q(id=1) & Q(id=2))    #
    '''
    # 方法方式,运维系统的多个条件的集合
    condition_dict = {
        'k1':[1,2,3,4],
        'k2':[1,],
    }
    con = Q()
    for k,v in condition_dict.items():
        q = Q()
        q.connector = 'OR'
        for i in v:
            q.children.append(('id',i))
        con.add(q,'AND')
    h = models.UserInfo.objects.filter(con)
    print(h.query) #SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."addr", "app01_publish"."phone" FROM "app01_publish" WHERE (("app01_publish"."id" = 1 OR "app01_publish"."id" = 2 OR "app01_publish"."id" = 3 OR "app01_publish"."id" = 4) AND "app01_publish"."id" = 1)
    for row in h:
    print(row.id,row.name,row.addr,row.phone)
    '''

九、Extra

额外查询条件及相关表,排序

extra(self, select=None, where=None, params=None, tables=None,
              order_by=None, select_params=None)
            a.映射
                #select 
                #select_params=None
                #select 此处 from 表 
                
            b.条件 
                #where = None
                #params=None,
                #select * from 表 where 此处 

            c.表 
                #tables 
                #select * from 表,此处 (笛卡尔积)
            
            d.排序 
                #order_by=None 
                #select * from 表 order by 此处 
                

运用:

models.UserInfo.objects.extra(
            select={'newid':'select count(1) from app01_usertype where id>%s'},
            select_params=[1,],
            where=['age'>%s'],
            params=[18,],
            order_by=['-age'],
            tables=['app01_usertype']
        )
        """
        select 
            app01_userinfo.id,
            (select count(1) from app01_usertype where id>1) as newid
        from app01_userinfo,app01_usertype
        where app01_userinfo.age>18 
        order_by app01_userinfo.age desc
        """
    v = models.UserInfo.objects.all().extra(
        select={
            'n':"select count(1) from app01_usertype where id=%s or id=%s",
            'm': "select count(1) from app01_usertype where id=%s or id=%s",
        },
        select_params=[1,2,3,4]
    )
    for obj in v:
        print(obj.name,obj.id,obj.n)

    models.UserInfo.objects.extra(
        where=["id=1 or id=%s","name=%s"],
        params=[1,"alex"]
    )
    models.UserInfo.objects.extra(
        tables=['app01_usertype'],
    )
当普通的ORM操作不了时,选择extra

十、原生SQL和raw

直接使用SQL语句进行查询

-原生SQL语句 
            from django.db import connection,connections
            cursor = connection.cursor()   # connection=default数据
            cursor = connections['db2'].cursor()
            
            cursor.execute("""select * from app01_userinfo where id = %s""",[1])
            
            row = cursor.fetchone()
            row = cursor.fetchall()
raw:
result = models.UserInfo.objects.raw('select * from userinfo')
[obj(UserInfo),obj,]

十一、添加表的纪录

1.一对多关系

 之前我们创建了Book表和Publish表,两者就是一对多的关系,Book表是‘多’的一方,所以外键字段在Book表,Book表添加和之前的不一样,而‘一’的Publish表就是一张单表,和之前的一样,所以我们只要学习‘多’的一张Book表的添加就行了。添加表记录有两种方式。

1.1 按models.py里面Book类的属性来添加

pub=Publish.objects.all().filter(id=1).first()      #首先找到id为1的Publish对象
book=Book.objects.create(name=name,price=price,publish=pub,pub_date=pub_date)   #然后把这一对象赋值给Book类的publish属性

1.2 按数据库里面Book表的字段来添加

book=Book.objects.create(name=name,price=price,publish_id=1,pub_date=pub_date)    #直接把Publish的id赋值给book表的publish_id就行了

2.多对多关系

之前我们创建了Book表和Author表,两者就是多对多关系,我是把多对多关系写在book表中的,所以从book去添加关联关系是正向的。

# 当前生成的书籍对象
book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
# 为书籍绑定的作者对象
a1=Author.objects.filter(id=2).first() # 在Author表中主键为2的纪录
a2=Author.objects.filter(id=1).first() # 在Author表中主键为1的纪录


# 绑定多对多关系,即向关系表book_authors中添加纪录,正向用属性,反向用表名_set

第一种,以Book为基表,因为多对多关系是写在Book中的,所以现在属于正向关联,用属性
book_obj.author.add(author1,author2)    #这是给book_obj对象绑定上author1和author2两个对象。这里的author不是Author小写,而是Book类的一个属性
第二种,以Author为基表,因为多对多关系不是写在Author表,所以属于反向关联,用表名小写_set
author_obj.book_set.add(book1,book2)    #这是给author_obj对象绑定上book1和book2两个对象,但是这里book可不是Author类的属性,而且也没有这个属性,它是Book表小写后得到的
关系表的方法:
1,add()方法
参数可以是可以是n个模型类对象,如上面的写法
也可以是一个queryset集合,如author_list=Author.objects.filter(id__gt=2),这是找出id大于2的作者集合
book_obj.author.add(*author_list)
还可以是一个主键列表,如下面的写法
book_obj.author.add(*[1,3,4])

2,remove()方法,移出关系方法
现在book1关联着author1和author2两个作者
book1.author.remove(author1)   #此时book1就关联author2一个作者
反向也行author2.book_set.remove(book2)    #把author2的关联书籍book2给移出

3,clear()方法,清空关系方法
book1.author.clear()     #把book1的所有关联关系给删除,现在book1就没有关联作者了
author1.book_set.clear() 一样的,把author1的所有关联书籍的关联关系删除

4,set()方法,先把关联关系清空,再添加关联关系
假如book1关联着author1
book1.author.set(author2)  先把与author1的关联关系删除,然后再建立与author2的关联关系
假如author3关联着book1
author3.book_set.set(book2)    先把关联关系清空,再建立与book2的关联关系

5,=方法,赋值一个可迭代对象,关联关系会被整体替换
假如book1关联author1
new_list=[author2,author3]
book1.author=new

3.一对一关系

给Author1类的属性赋值
info=Author_Info.objects.create(gf_name=gf_name,telephone=telephone,ShenFenZheng=ShenFenZheng)   #这是创建了一条Author_Info记录,info就是一个Author_info对象
Author1.objects.create(name=name,age=age,author_info=info)       把创建的info对象赋值给author_info属性

和一对多一样,也可以使用Author表的字段赋值
Author1.objects.create(name=name,age=age,author_info_id=2)

 神奇的双下划线

# 获取个数
        #
        # models.Tb1.objects.filter(name='seven').count()

        # 大于,小于
        #
        # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
        # models.Tb1.objects.filter(id__gte=1)              # 获取id大于等于1的值
        # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lte=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull
        # Entry.objects.filter(pub_date__isnull=True)

        # contains
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and

        # 其他类似
        #
        # startswith,istartswith, endswith, iendswith,

        # order by
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

        # group by
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset
        #
        # models.Tb1.objects.all()[10:20]

        # regex正则匹配,iregex 不区分大小写
        #
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')

        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)
进阶操作
posted on 2019-02-19 20:49  smile大豆芽  阅读(281)  评论(0)    收藏  举报