python:Django Models / ORM

1    django默认支持sqlite,mysql, oracle,postgresql数据库。

     <1> sqlite

            django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

     <2> mysql

            引擎名称:django.db.backends.mysql

2    mysql驱动程序

  •    MySQLdb(mysql python)# python2使用。
  •    mysqlclient
  •    MySQL
  •    PyMySQL(纯python的mysql驱动程序)# python3使用

3、Django的数据库设置【setings.py】

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql', 

        'NAME': 'books',    #你的数据库名称

        'USER': 'root',   #你的数据库用户名

        'PASSWORD': '', #你的数据库密码

        'HOST': '', #你的数据库主机,留空默认为localhost

        'PORT': '3306', #你的数据库端口

    }

}
数据库设置

在此之前,需要在项目名下的__init__.py文件中 写入

import pymysql
pymysql.install_as_MySQLdb()

在setings设置完数据库模式为mysql之后,需要导入驱动,因为Django默认导入的驱动是mysqldb,所以我们需要更改驱动的设置。

下面要开始学习Django ORM语法了,为了更好的理解,我们来做一个基本的 书籍/作者/出版商 数据库结构。 我们这样做是因为 这是一个众所周知的例子,很多SQL有关的书籍也常用这个举例。

表(模型)的创建:

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名。

作者详细模型:把作者的详情放到详情表,包含性别,email地址和出生日期,作者详情模型和作者模型之间是一对一的关系(one-to-one)(类似于每个人和他的身份证之间的关系),在大多数情况下我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。

出版商模型:出版商有名称,地址,所在城市,省,国家和网站。

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

附:数据模型常见的字段类型

 

 

 参数:

<1> null : 数据库中字段是否可以为空

    <2> blank: django的 Admin 中添加数据时是否可允许空值

    <3> default:设定缺省值

    <4> editable:如果为假,admin模式下将不能改写。缺省为真

    <5> primary_key:设置主键,如果没有设置django创建表时会自动加上:
        id = meta.AutoField('ID', primary_key=True)
        primary_key=True implies blank=False, null=False and unique=True. Only one
        primary key is allowed on an object.

    <6> unique:数据唯一

    <7> verbose_name  Admin中字段的显示名称

    <8> validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误


    <9> db_column,db_index 如果为真将为此字段创建索引

    <10>choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。
                如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),)
                gender = models.CharField(max_length=2,choices = SEX_CHOICES)
Field常用参数

 

 再进行ORM查询数据时,会经常获得一个QuerySet集合对象。

所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。

QuerySet特点:

       <1>  可迭代的#可以用for循环

       <2>  可切片#【0,1,2,3,4】#取几个对象

常用的API方法

# 查询相关API:

#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象

#  <2>all():                 查询所有结果

#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------

#  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
                                     
#  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象

#  <6>order_by(*field):      对查询结果排序

#  <7>reverse():             对查询结果反向排序

#  <8>distinct():            从返回结果中剔除重复纪录

#  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

#  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。

# <11>first():               返回第一条记录

# <12>last():                返回最后一条记录

#  <13>exists():             如果QuerySet包含数据,就返回True,否则返回False。
方法
<1>Django的queryset是惰性的

     Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得
     到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
     上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
     这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。

<2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
   为了验证这些,需要在settings里加入 LOGGING(验证方式)
        obj=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)

        # if obj:
        #     print("ok")

<3>queryset是具有cache的
     当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行
    (evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,
     你不需要重复运行通用的查询。
        obj=models.Book.objects.filter(id=3)

        # for i in obj:
        #     print(i)
                          ## models.Book.objects.filter(id=3).update(title="GO")
                          ## obj_new=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)   #LOGGING只会打印一次

<4>
     简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些
     数据!为了避免这个,可以用exists()方法来检查是否有数据:

            obj = Book.objects.filter(id=4)
            #  exists()的检查可以避免数据放入queryset的cache。
            if obj.exists():
                print("hello world!")

<5>当queryset非常巨大时,cache会成为问题

     处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统
     进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法
     来获取数据,处理完数据就将其丢弃。
        objs = Book.objects.all().iterator()
        # iterator()可以一次只从数据库获取少量数据,这样可以节省内存
        for obj in objs:
            print(obj.name)
        #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
        for obj in objs:
            print(obj.name)

     #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使
     #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询

总结:
    queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
会造成额外的数据库查询。
QuerySet高效使用

 

一,单表操作

1、在models.py中,通过类来设置表头。

from django.db import models#导入模块
from django.utils import timezone
from django.contrib.auth.models import User
# Create your models here.
#
class Book_info(models.Model):#图书表#继承 父类
    book_name = models.CharField(max_length=300)#书名
    t_publication = models.DateField()#出版时间
    t_entering = models.IntegerField#录入时间
    book_type = models.IntegerField(max_length=300)#图书类型
    b_price = models.FloatField()#价格
    Write_info = models.FloatField()  # 作者
models.py

2、运行下面命令,来进行数据表的创建

创建表

python manage.py makemigrations

python manage.py migrate
创建表

3、添加数据

a:  创建记录     :通过views  class类实例化数据库添加数据

import Tbook.models# 引入刚才建立的那张表
def add_book(requset):#添加
    ad = models.Book_type(book_type="财经")#实例化这张表
    ad.save()#保存
    return HttpResponse("添加成功")

#我在路由中添加了 add_book,views.book.
#运行Django服务器,输入,127.0.0.1/add_book.
views添加数据

b:调用object.create方法进行添加记录

import Tbook.models# 引入刚才建立的那张表
def add_book(requset):#添加
    models.Book_type.objects.create(book_type="天文")
    return HttpResponse("添加成功")
object.create

4、删除记录

models.Book_type.objects.filter(book_type="水利").delete()
del

5、查询,并修改数据

def find_book(requset):#查找 及修改
    models.Book_type.objects.filter(book_type="言情").update(book_type = "建筑")
#filter查询,upadte,更新数据
    return HttpResponse("查询成功")
查询数据
def find_book(requset):#查找 及修改
    upd = models.Book_type.objects.get(id = 2)#取一个。
    print(upd)#QuerySet 对象合计
    upd.book_type = "水利"
    upd.save()
#利用update,少用save,因为,save这个方法会修改整条数据。而,objects只修改指定数据
View Code

6.怎么查看你用用的这些命令,原生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',
        },
    }
}
修改seting添加此文本

 常用的查询命令:

# 查询相关API:

#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象f

#  <2>all():                 查询所有结果  object.all()[0:2]    可以进行切片

#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。  

#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------

#  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列   #取出一个特定的值,filter(字段==)。values(字段,字段)
                                     
#  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象

#  <6>order_by(*field):      对查询结果排序

#  <7>reverse():             对查询结果反向排序

#  <8>distinct():            从返回结果中剔除重复纪录
 对象.object.all().values("name").distinct()

#  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

#  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。

# <11>first():               返回第一条记录

# <12>last():                返回最后一条记录

#  <13>exists():             如果QuerySet包含数据,就返回True,否则返回False。
ORM
#---------------了不起的双下划线(__)之单表条件查询----------------

#    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
#
#    startswith,istartswith, endswith, iendswith,
单表查询__双下线

二、一对多。

例如:有2张表,一张书籍表,一张出版社表,一个出版社可以出多本书,一本书一般情况下是一个出版社出的。所以是1对多的关系。在models中新建表关系时,要在多的那一方新建外键。具体如下:

class Book_info(models.Model):#图书表
    name = models.CharField(max_length=50)#书名
    Write = models.CharField(max_length=100)# 作者
    price = models.IntegerField()#价格
    publish = models.ForeignKey("Publish_h")#默认关键主键


class Publish_h(models.Model):#出版社表
    name = models.CharField(max_length=300)#书名
    city = models.CharField(max_length=32)

#新建完了之后,他会在BOOK表中 新建一列,列名是:Pulish_h_id
也就是出版社的表名+ID
1对多,外键新建

查询数据

外键查询————双下划线
 #查询python这本书籍的出版社
#filter#
obj = Publish_h.objects.filter(book_info__name="linux").values('name')
    print(obj)

#values#

obj = Book_info.objects.filter(name = "linux").values("publish__name")
filter__values__
#查询城市是上海的出版社出版的书

    obj = Publish_h.objects.filter(city = "上海").values("book_info__name")
    obj = Book_info.objects.filter(publish__city='上海').values("name")
再加一个例子

增加数据

 #方式1
    add_list = Book_info.objects.create(name="色即是空", t_entering="2019-08-09", t_publication="2008-08-06",
                                        type="历史", price=88, Write="王龙", publish_id=2)
    #方式2
    # pubobj = Publish_h.objects.filter(name="人民出版社")[0]
    # Book_info.objects.create(name="色即是空", t_entering="2019-08-09", t_publication="2008-08-06",
    #                          type="色情", price=88, Write="王龙", publish_id=pubobj)
View Code

二、多对多

创建多对多的表#   一个作者个出版多本书,一本书可以有多个作者。

创建了多对多关系之后,Django会新建一张新表来保存这个关系(book_info__Writer_b)这张表中存放了主键ID,book_info的外键id与Writer_b的外键id

人工用manytomany的方式创建了第三张表,就不能通过ORM直接添加数据。

Write = models.ManyToManyField("Writer_b")  # 作者#多对多

1、添加关系,删除关系

   #绑定多对多的关系
    #给ID等于4的书,绑定3个作者
    book_obj = Book_info.objects.get(id = 4)

    Writer_obj = Writer_b.objects.all()#所有的作者信息
    Writer_obj = Writer_b.objects.get(id = 2)  # id等于2的作者
    book_obj.Write.add(*Writer_obj)#添加关系
    book_obj.Write.remove(Writer_obj)#删除关系
    book_obj.Write.remove(1)  # 删除关系表中ID = 1 的
View Code

备注更新数据,

obj = models.book.objcts.filter(id=2).first()

obj.wirte.set([1,2])1   2    2  2     更新

2、如果想直接在第三张表里面添加数据,那就不能用manytomany,需要自己新建一张表。

  

class Book_write(models.Model):
    book = models.ForeignKey('Book_info',on_delete=models.CASCADE)
    write = models.ForeignKey('Writer_b',on_delete=models.CASCADE)


外键模式,必须创建on_delete字段

CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
SET(): 自定义一个值,该值当然只能是对应的实体了

3、自定义创建第三张表查询/manytomany

自定义
#manytomany
    print(Book_info.objects.filter(Write__Write='耳根').values('name'))
many to many

4、聚合函数查询

from django.db.models import Avg,Min,Sum,Max,Count
#单表聚合查询
#查询书籍表price的平均值
Book_info.objects.all().aggregate(Avg("price"))
Book_info.objects.all().aggregate(Sum("price"))


#多表聚合
print(Book_info.objects.filter(Write__Write="耳根").aggregate(Sum("price")))

# 默认是字段名是   sum_price        Sum("price").
#改名:   sjy_mone=Sum("price").
多表之聚合查询

5、分组查询

# 查询每个作者出的书,他们各一共有多少钱

Book_info.objects.values('write__name').annotate(Sum("price"))
    #按照作者来分组(BOOK表中的write字段双下划线连接至Write表下的name 字段_以作者分组),然后再求和
   


 # 每个出版出版社出版的书最便宜的价格是多少
1、    Book_info.objects.values("publish__name").annotate(Min("price"))
分组查询聚合查询

 6、模糊查询

F----Q查询

    #F 使用查询条件的值,专门取对象中某列值的操作
    #每本书 提高10元
    # Book_info.objects.all().update(price=F('price')+10)
    #update修改表 F找到 字段并取值

    a = Book_info.objects.filter(Q(price=53)).values('name')
    print(a)#查询价格等于53的书籍
    b = Book_info.objects.filter(~Q(price=53)).values('name')
    print(b)#查询价格不等于53的书籍
    c = Book_info.objects.filter(Q(price=53) | Q(type='历史')).values('name')
    print(c)#查询 等于 53或者 等于历史的书籍
    #如果要查询  并关系的话, filter(name = **,type =1111),就是并的关系
#Q查询和关键字查询组合使用
   ret =Book_info.objects.filter(Q(name='仙逆'),price=55)
Q /F

posted on 2019-12-24 10:13  超nmmmmm  阅读(145)  评论(0编辑  收藏  举报

导航