Django ORM 操作

ORM

  • ORM (object Relational Mapping)

对象和关系型数据库的一个映射 同过操作对象的方式操作数据库的内容

  1. 对应关系

    ​ 类 ___> 表

    ​ 对象 ___> 记录 数据行

    ​ 属性 ___> 字段

  2. ORM的操作:

    1. 查询

      1. models.Publisher.objects.all()      # 查询所有的数据   ——》 QuerySet   对象列表
      2. models.Publisher.objects.get()    # 获取满足条件的一个对象    ——》 单独的对象
      3. models.Publisher.objects.filter()   # 获取满足条件的所有对象  ——》对象列表
      4. models.Publisher.objects.all().order_by('id')   # 排序  —— 》 对象列表
      5. pub_obj.pk    ——》 主键
      6. pub_obj.name  
      7. 外键
         1. book_obj.publisher    ——》 关联的对象
         2. book_obj.publisher_id  ——》从book表中获取关联对象的ID
         3. book_obj.publisher.name    ——》 关联的对象的属性
      8. 多对多
         1. author_obj.books   ——》 管理对象
         2. author_obj.books.all()   ——》 关联的所有的对象  对象列表
         3. book_obj.author_set   ——》管理对象、
      
      
    2. 增加

      1. models.Publisher.objects.create(name='xxx')    ——》 对象
      2. 外键
         1. models.Book.objects.create(title='xxx',publisher=pub_obj)
         2. models.Book.objects.create(title='xxx',publisher_id=pub_obj.id)
      3. 多对多
         1. models.Author.objects.create(name='xxxx')  ——》 author_obj
         2. author_obj.books.set([多个要关联对象的id,])
         3. author_obj.books.set([多个要关联对象,])
      
      
    3. 删除

      1. models.Author.objects.get(id=1).delete() 
      2. models.Author.objects.filter(id=1).delete() 
      
      
    4. 修改

      1. 1. pub_obj.name = 'new_xxxx'
         2. pub_obj.save() 
         3. 外键
            1. book_obj.title = 'xxxx'
            2. book_obj.publisher = pub_obj  或者  book_obj.publisher_id = pub_obj .id
            3. book_obj.save()
         4. 多对多
            1. author_obj.name = 'new_name'   
            2. author_obj.save()
            3. author_obj.books.set([多个要关联对象,])   author_obj.books.set([多个要关联对象的id,])
      

具体的操作

from app01 import models 
# 获取所有数据
models.User.objects.all()   # __>  QuerySet 对象列表 
# 获取单个对象   获取不到数据或者拿到多条数据就报错
models.User.objects.get(name='alex',pwd='111')   # __> 对象
# 获取满足条件的所有对象  
models.User.objects.filter(name='alex',pwd='111')  # __>  QuerySet 对象列表 

字段和字段的参数

1.字段和字段的参数

	常用的:                       		

	AutoField    #  自增字段       
    	参数:
    		primary_key=True   #  主键

	IntegerField  #  整数类型 	
    	参数:				
            blank=True   #  admin中显示 

	BooleanField   #  bool类型 
    	参数:
            choices((1,'男'),(0,'女')) 只能有两个值 
			0 为存储的值  男女为显示的内容
        
	CharField     #   varchar 类型	
    	参数:		  
            max_length=32  #  必填  最大长度

	TextField   #   文本类型 

	DateTimeField   #  时间类型 	
    	参数:
             auto_new_add=True  #  新增时自动保存当前时间
			auto_new=True      #  修改时自动保存当前时间
 
	DecimalField  #   小数类型   	
    	参数:
             max_digits=5   #  小数总长速度
    		decimal_places=2  #  小数位长度 
    ForeignKey('表名',)   #  	外键
   
    OneTuoOneField('表名',)  #   等同于外键关联自己
    	参数:
            related_name='books',     #  用于反向查询 
            related_query_name='book'
    
    ManyToManyField('表名',)   		#   多对多  
    	参数:
            related_name='books',      #  用于反向查询 
            related_query_name='book'      #  用于反向查询 
    
    其他参数:
		db_column='usrname'    		#  修改数据库中的列名 显示
		verbose_name="用户名"		 #  admin中文提示
		black=True  	#  校验时可以为空
         null=True       #  存储时可以为空
         unique=true 	 #  字段唯一
         default='默认值'   #  为空时提供默认值
        
        

自定义 Char 类型

class MyCharField(models.Field):
    """
    自定义的char类型的字段类
    """

    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)

    def db_type(self, connection):
        """
        限定生成数据库表的字段类型为char,长度为max_length指定的值
        """
        return 'char(%s)' % self.max_length
    
使用:
    phone = MyCharField(max_length=11, )

class Meta:

# 写在model 类中

class Meta:
        # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
        db_table = "person"
        # admin中显示的表名称
        verbose_name = '个人信息'

        # verbose_name加s
        verbose_name_plural = '所有用户信息'
        # 排序 升序排列,先按照index排序 如果相等按照id排序  倒序排列 加 -
        ordering = ('index', 'id')

        # # 联合索引
        # index_together = [
        #     ("pub_date", "deadline"),  # 应为两个存在的字段
        # ]
        #
        # # 联合唯一索引
        # unique_together = (("driver", "restaurant"),)  # 应为两个存在的字段

查询的方法(13个)

1. models.Book.objects.all()  # 获取到所有的书籍对象,结果是对象列表

2. models.Book.objects.get(条件)  # 获取符合条件的对象

3. models.Book.objects.filter(条件)  # 筛选所有符合条件的,结果是对象列表

4. models.Book.objects.exclude(条件)  # 筛选出所有不符合条件的,结果是对象列表

5. models.Book.objects.all().values( )  # 字典列表,[ {id:1,name:20} , {id:2,name:18} ]

values(‘id’)括号内不指定时显示全部,如指定则只显示指定的,[ {id:1} , {id:2,} ]

6. models.Book.objects.all().values_list( )  # 元组列表,[ (1,20) , (2,18) ]同上,指定时显示指定内容

7. models.Book.objects.all().order_by(‘id’)  # 按照id升序就行排列

models.Book.objects.all().order_by(‘-id’)  # 按照id降序就行排列

models.Book.objects.all().order_by(‘age’ , ‘-id’)  # 先按age升序,age相同的按id进行降序排列

8. models.Book.objects.all().order_by(‘id’).reverse()  # 对结果反转; 注意reverse前必须排序,

否则reverse无效; 或在model.py文件中Book类中的Meta中指定ordering=(‘id’ , )注意逗号必须有



9. distinct():  # 去重,当获取到的结果Queryset列表中同一对象出现多次时去重,只留一个

    10. models.Book.objects.all().count()  # 计数,可统计结果个数,如对Queryset内元素数进行统计.

    11. models.Book.objects.all().first()  # 获取结果中的第一条,即使前面结果列表为空,也不会报错

    12. models.Book.objects.filter().last()  # 获取结果中的最后一条

    13.models.Book.objects.filter().exists()  # 判断Queryset列表是否有东西,结果为True或False;

    小结:

        返回对象列表(Queryset)的方法有:

            all()   filter()   ordey_by()   exclude()   values()   values_list()   reverse()   distinct()

            返回单个对象的方法有:

                first()   last()   get()   create()创建一个对象,且返回刚创建的对象

                判断布尔值的有:

                    exists()

                    返回数字的有:

                        count()

建立 数据库查询 orm操作

  • modle 表结构
from django.db import models


class MyCharField(models.Field):
    """
    自定义的char类型的字段类
    """

    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)

    def db_type(self, connection):
        """
        限定生成数据库表的字段类型为char,长度为max_length指定的值
        """
        return 'char(%s)' % self.max_length


class Person(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, db_column='username', verbose_name='姓名')
    age = models.IntegerField(null=True, blank=True, verbose_name='年龄')
    # birth = models.DateTimeField(auto_now_add=True)    # 新增的时候保存当前的时间
    birth = models.DateTimeField(auto_now=True)  # 每次修改的时候保存当前的时间
    phone = MyCharField(max_length=11, )
    gender = models.BooleanField(choices=((0, '男'), (1, '女')))

    def __str__(self):
        return "<Person object: {}-{}>".format(self.pk, self.name)

    class Meta:
        # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
        db_table = "person"
        # admin中显示的表名称
        verbose_name = '个人信息'

        # verbose_name加s
        verbose_name_plural = '所有用户信息'

        ordering = ('id',)

class Publisher(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)  # 000.00    999.99
    sale = models.IntegerField()
    kucun = models.IntegerField()
    publisher = models.ForeignKey('Publisher', related_name='books', related_query_name='book', null=True)

    def __str__(self):
        return self.title + str(self.pk)


class Author(models.Model):
    name = models.CharField(max_length=32)
    books = models.ManyToManyField('Book',)

在setting 中配置 查看配置 显示查询语句
import django
django.setup()

from app01 import models

# all()   获取所有的数据  对象列表
ret = models.Person.objects.all()

# filter()   获取所有满足条件的所有对象    对象列表
ret = models.Person.objects.filter(id=1)

# get()     获取一个对象  没有或者是多个的时候报错
ret = models.Person.objects.get(id=1)

# exclude  获取不满足条件的所有对象  对象列表
ret = models.Person.objects.exclude(id=1)


# values  获取对象的字段名和值    [ {},{} ]
# 不指定字段名  获取所有字段的名和值
# 指定字段名    获取指定字段的名和值
ret = models.Person.objects.all().values('name','id')
# for i in ret:
#     print(i,type(i))

# values_list  获取对象的值    [ (),() ]
# 不指定字段名  获取所有字段的值
# 指定字段名    获取指定字段值
ret = models.Person.objects.all().values_list('id','name')
# for i in ret:
#     print(i,type(i))

# order_by 排序 默认升序  加- 降序  指定多个进行排序
ret = models.Person.objects.all().order_by('age','id')

# reverse() 给已经排好序的结果倒叙排序
ret = models.Person.objects.all().order_by('age','id').reverse()

ret = models.Person.objects.all().reverse()


# distinct()  去重

# count   计数
ret = models.Person.objects.all().count()

# first()  last   取第一个 最后一个对象
ret = models.Person.objects.filter(id=100).first()

# exists()  判断数据是否存在
ret = models.Person.objects.filter(id=1).exists()

单表的双下划线

import os

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

django.setup()

from app01 import models

ret = models.Person.objects.filter(id=1)
ret = models.Person.objects.filter(id__gt=1)  # greater than
ret = models.Person.objects.filter(id__gte=1)  # greater than equal
ret = models.Person.objects.filter(id__lt=3)  # less than
ret = models.Person.objects.filter(id__lte=3)  # less than equal

ret = models.Person.objects.filter(id__gt=1, id__lt=3)
ret = models.Person.objects.filter(id__range=[1, 3])  # 范围  左右都包含
ret = models.Person.objects.filter(id__in=[1, 3])  #

ret = models.Person.objects.filter(name__contains='alex')  # 包含   like
ret = models.Person.objects.filter(name__icontains='alex')  # 包含   like

ret = models.Person.objects.filter(name__startswith='a')  # 以什么开头
ret = models.Person.objects.filter(name__istartswith='a')  # 以什么开头  忽略大小写

ret = models.Person.objects.filter(name__endswith='x')  # 以什么结尾
ret = models.Person.objects.filter(name__iendswith='X')  # 以什么结尾  忽略大小写

ret = models.Person.objects.filter(birth__year=2018)
ret = models.Person.objects.filter(birth__contains='2018-12')

外键的操作

# 基于对象的查询
# 正向  有外键的一侧 查关联的对象
book_obj = models.Book.objects.get(id=1)

	book_obj.publisher    关联的对象
# print(book_obj.publisher)     # 关联的对象
# print(book_obj.publisher_id)  # 关联的对象的id
# print(book_obj.publisher.id)  # 关联的对象的id

# 反向查询   被关联的对象  查有外键的一侧
# pub_obj = models.Publisher.objects.get(id=1)
# print(pub_obj.name)

	不指定related_name

		pub_obj.book_set     管理对象  

		pub_obj.book_set.all()   

		指定related_name = ‘books’	

		pub_obj.books    管理对象
# 不指定 related_name='books'
# print(pub_obj.book_set,type(pub_obj.book_set))
# print(pub_obj.book_set.all())

# 指定related_name='books'
# print(pub_obj.books,type(pub_obj.books))
# print(pub_obj.books.all())
# 基于字段的查询

# ret = models.Book.objects.filter(publisher__name='老男孩出版社')

# 不指定related_name
# ret = models.Publisher.objects.filter(book__title='太亮教开车')

# 指定related_name
# ret = models.Publisher.objects.filter(books__title='太亮教开车')

# 指定related_query_name='book'
# ret = models.Publisher.objects.filter(book__title='太亮教开车')


# 外键字段可以为null 才有remove和clear  只能写对象
pub_obj = models.Publisher.objects.get(id=1)
# pub_obj.books.remove(models.Book.objects.get(id=1))
# pub_obj.books.clear()

pub_obj.books.create(title='太亮的产后护理')

多对多的操作

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models

# 基于对象的查询
# 正向
author_obj = models.Author.objects.get(id=2)
#
# print(author_obj.books,type(author_obj.books))
# print(author_obj.books.all())

# 反向
book_obj = models.Book.objects.get(id=1)

# 不指定related_name='authors'
# print(book_obj.author_set.all())

# 指定related_name='authors'
# print(book_obj.authors.all())


# set 设置多对多关系
# author_obj.books.set([])
# author_obj.books.set([1,2,3])   # 要关联对象的ID  [ 对象的id,对象的id]
# author_obj.books.set(models.Book.objects.all())   # 要关联对象  [ 对象,对象]


# add 添加多对多的关系
# author_obj.books.add(1)  # 要关联对象的ID
# author_obj.books.add(models.Book.objects.get(id=2))  # 要关联对象

# remove()  删除多对多的关系

# author_obj.books.remove(1)  # 要关联对象的id
# author_obj.books.remove(models.Book.objects.get(id=2))  # 要关联对象

# clear()  # 清空当前对象的多对多的关系
# author_obj.books.clear()

# create()
# author_obj.books.create(title='太亮教抛光',)

# update() 更新字段
# author_obj.books.update(title='太亮教抛光',)

book_obj.authors.create(name='alex')

聚合 和分组

​ Max, Min, Sum, Avg, Count

aggregate 聚合

annotate 分组

mport os

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

django.setup()

from app01 import models

from django.db.models import Max, Min, Sum, Avg, Count
#aggregate 聚合
ret = models.Book.objects.aggregate(max=Max('price'))  # { }


# annotate 分组
# 统计每一本书的作者个数
ret = models.Book.objects.all().annotate(count=Count('author')).values('count')

# 统计出每个出版社买的最便宜的书的价格
# 方法一
ret = models.Publisher.objects.all().annotate(Min('book__price')).values()
# for i in ret:
#     print(i)

# 方法二
ret = models.Book.objects.values('publisher__name').annotate(min=Min('price')).values('min')
# for i in ret:
#     print(i)


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

# 查询各个作者出的书的总价格
ret = models.Author.objects.annotate(Sum('books__price')).values()
for i in ret:
    print(i)

F 和 Q

import os

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

django.setup()

from app01 import models
from django.db.models import F

# ret= models.Book.objects.filter(kucun__gt=F('sale')).values()
# for i in ret:
#     print(i)
# models.Book.objects.all().update(sale=F('sale')*2)


# obj = models.Book.objects.filter(id=1).first()
#
# obj.sale = 60
# obj.save()

from django.db.models import Q

ret = models.Book.objects.filter(Q(~Q(id__lt=3) | Q(id__gt=5))&Q(id__lt=4))
print(ret)

事物

import os

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

django.setup()

from app01 import models

from django.db import transaction

try:
    with transaction.atomic():
        
        res = models.Publisher.objects.filter(name='新华出版社1').select_for_update() # 加锁
        res.update() # 释放锁
        models.Publisher.objects.create(name='新华出版社1')
        int('aaa')
        models.Publisher.objects.create(name='新华出版社2')
        models.Publisher.objects.create(name='新华出版社2')
except Exception as e:
        print(e)

性能

  • 性能相关

    1. 能用values,别用对象进行查询

    2. select_related 主动连表 一次查询

    3. prefetch_related 子查询 两次查询

    4. only (只拿某些字段) defer(排除某些字段)

      QuerySet

使用原生sql的 方法 :

  1. raw

    # row方法:(掺杂着原生sql和orm来执行的操作)
    res = CookBook.objects.raw('select id as nid  from  epos_cookbook  where  id>%s', params=[1, ])
    print(res.columns) # ['nid']
    print(type(res)) # <class 'django.db.models.query.RawQuerySet'>
    
    # 在select里面查询到的数据orm里面的要一一对应
    res = CookBook.objects.raw("select * from epos_cookbook")
    print(res)
    for i in res:
        print(i.create_date)
        print(i)
        
    res = CookBook.objects.raw('select * from epos_cookbook where id>%s', params=[1, ])
    # 后面可以加参数进来
    print(res)
    for i in res:
        # print(i.create_date)
        print(i)
    
  2. extra

    # (1,2) 必须两个以上
    # res = CookBook.objects.extra(select={"aaa": "cook_type = 1"}, where=['id in (1,2)', ]).values()
    res = CookBook.objects.extra(select={"aaa": "cook_type = 1"}, where=['id in (1,2)', ])
    print(res)  # <QuerySet [<CookBook: 鱼香肉丝>, <CookBook: 水煮鱼>]>
    for r in res:
        print(r)
    
  3. connections (最原生)

    from django.db import connection, connections
    # 需要配置数据库
    # cursor=connection['default'].cursor() 
    cursor = connection.cursor()  
    # 不传参数的情况
    cursor.execute("""select  * from epos_cookbook""")
    
    # 为原生sql语句设置参数的情况
    # cursor.execute("""select  * from  epos_cookbook   where   id=%s""",[2,]) # 2 是 id
    # cursor.execute("""select  * from  api_userinfo   where   id=%s"""%1)
    
    # 防止注入攻击
    cursor.execute("select  * from  epos_cookbook   where   id=%s", params=[1, ])
    # row=cursor.fetchone()
    # row=cursor.fetchmany()
    row = cursor.fetchall()  ##拿到全部的数据
    
    print(row)
    
    
    
    from django.db import connection
    
    cursor=connection.cursor()
    
    # 插入操作
    cursor.execute("insert into hello_author(name) values('钱钟书')")
    
    # 更新操作
    cursor.execute("update hello_author set name='abc' where name='bcd'")
    
    # 删除操作
    cursor.execute("delete from hello_author where name='abc'")
    
    # 查询操作
    cursor.execute("select * from hello_author")
    
    raw=cursor.fetchone()  # 返回结果行游标直读向前,读取一条
    cursor.fetchall()  # 读取所有
    
    

分页

from django.core.paginator import Paginator, Page  # 导入模块

current_pagnum = 2
user_list = CookBook.objects.all().values()
paginator = Paginator(user_list, 1)
print(paginator.per_page)
# 创建一个对象paginator,又有这是一个对象,所以可以通过点“.”来调用一些功能
# per_page: 每页显示条目数量
# count:    数据总个数
# num_pages:总页数
# page_range:总页数的索引范围,如: (1,10),(1,200)
# page:     page对象
posts = paginator.page(number=current_pagnum)  # 这个num就是现实当前第几页
# has_next              是否有下一页
# next_page_number      下一页页码
# has_previous          是否有上一页
# previous_page_number  上一页页码
# object_list           分页之后的数据列表
# number                当前页
# paginator             paginator对象
print(posts.object_list)
posted @ 2018-12-26 20:36  拐弯  阅读(198)  评论(0编辑  收藏  举报