模型层

模型层:

ORM查询

 ORM中常用字段和参数:
   1.int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列  (AutoField) 
   2.一个整数类型,范围在 -2147483648 to 2147483647(用字符串存储)(IntegerField)
   3.字符类型,必须提供max_length参数, max_length表示字符最大长度(CharField)
   4.日期字段,日期格式  YYYY-MM-DD (DateField)\
   5.日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] (DateTimeField)
    
    6.表示某个字段可以为空。 (null)
    7.设置为unique=True 则该字段在此表中必须是唯一的 。(unique)
    8.db_index=True 则代表着为此字段设置索引。
    9.为该字段设置默认值。 (default)
    
    10.配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库 (auto_now_add)
    11.配置上auto_now=True,每次更新数据记录的时候会更新该字段 (auto_now : 仅仅记载最新的记录)

	12.EmailField() : 数据类型是 varchar(254)
    

表之间的关系:

表之间的关联 : 外键 (ForeignKey)
    1.外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

    2.ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

    参数:to ; 设置要关联的表
    	 to_file: 设置要关联表的字段
         on_delete:删除关联表中的数据时,当前表与其关联的行的行为。
            
            
models.CASCADE : 删除关联数据,与之关联也删除!
db_constraint : 是否在数据库中创建外键约束,默认为True。


定义新字段:

自定义新的字段: 
	1.必须要有max_length
    2.返回值必须为字符串
class xxCharField(models.Fiels):
    '''自定义char类型的字段类'''
	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 Class(models.Model):
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)

配置测试脚本

配置orm操作数据库(mysql)的测式文件:

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")

    import django
    django.setup()
    from app01 import models
    models.Books.objects.all()
注意:
1.from app01 import models放置在建立测试脚本搭建完毕后
2.新建一个.py文件,要导入以上代码
3.在orm测式文件内部对数据进行操作

日志记录:

记录数据库操作:
--》放置在settings

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

orm对表内数据的操作:

查找数据:
--》 res = models.Books.objects.filter(pk=1)
# pk :会自动帮你查找到当前表的主键字段(指代主键字段)

# filter 查询出来的结果是一个Queryset对象:
	1.只要是queryset对象就可以无限制的调用queryset的方法
res = models.Books.objects.filter(pk=1).filter().....
	
	2.只要是queryset对象就可以点query查看当前结果内部对应的sql语句
	res = queryset_obj.query  ====  >  sql 语句

创建数据:
  1.create() :
        book_obj = models.Books.objects.create(title='三国演义',publish_date='2019-11-11')  #输入时间格式 :可以输入字符串
	  # ctime = date.today() 
    	book_obj = models.Books.objects.create(title='三国演义',publish_date=ctime)

  2.利用对象的绑定方法:
	book_obj = models.Books(title='西游记',publish_date='ctime)
	book_obj.save()

修改数据:
     1.利用queryset方法:                      
	models.Books.objects.filter(pk=1).update(price=444)

	2,利用对象:	
    book_obj = models.Books.objects.get(pk=1)
    book_obj.price = 222
    book_obj.save()

注意 : 利用对象的修改 内部其实是重头到位将数据的所有字段都重新写一遍(先删再创一个新的)
                            
 删除数据:
                            
	1.利用queryset方法 delete()
    models.Books.objects.filter(pk=3).delete()
    2,对象方法
    book_obj = models.Books.objects.get(pk=3)
    book_obj.delete()
                            
                            

get 与 filter 的区别:

区别:
 1.filter获取到的是一个queryset对象 类似于一个列表
 2.get获取到的直接就是数据对象本身

当条件不存在的情况下:
    filter不报错直接返回一个空  
    get直接报错 所以不推荐使用get方法

单表查询13条方法

orm语句的查询 :
	惰性查询,只有当你真正要使用数据的时候才会执行orm语句

1.all() : 查询匹配的所有数据  --》 返回 QuerySet对象
eg: res = models.Books.objects.all()

2.filter() : 筛选 (类似于 where 条件) -返回 QuerySet对象
eg: res = models.Books.object.filter(pk=1)

3.get() : 筛选 返回数据对象本身  查询条件必须是唯一的
eg: res = models.Books.objects.get(title='西游记')

4.first() : 取queryset中第一个数据对象  返回数据对象
eg: res = models.Books.objects.filter(pk=1).first()

5.last()  取queryset中最后一个数据对象    数据对象
eg: res = models.Books.objects.filter(pk=1).last()

6. count()  统计数据的个数(表记录的个数)   数字
eg: num = models.Books.objects.count() 

7.values()  获取数据对象中指定的字段的值  多个 queryset 列表套字典
eg: res = models.Books.objects.values('title','price')
<QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}

8.values_list()  获取数据对象中指定的字段的值 多个 queryset 列表套元祖
eg: res = models.Books.objects.values_list('title','price')
<QuerySet [('三国演义', Decimal('222.66'))

9.order_by()      按照指定的字段排序  # 默认是升序
eg: res = models.Books.objects.all().order_by('price') 

# 降序  字段前面加负号
res1 = models.Books.objects.all().order_by('-price')

10.reverse() 颠倒顺序   前提是跌倒的对象必须有顺序(排序之前才能颠倒)
   res1 = models.Books.objects.all().reverse()    

11.exclude()   排除什么什么之外   queryset对象    
res = models.Books.objects.all().exclude(title='三国演义')

12.exists()      判断查询结果是否有值 返回结果是一个布尔值
res = models.Books.objects.filter(pk=1).exists()

13..distinct()   去重操作 去重的前提:表记录数据必须是完全相同的情况下
res = models.Books.objects.values('title','price').distinct()
           
注意 :
	1.去重必须是一条表记录内所有的数据都一样(包括主键)
	2.能对帅选过后的数据进行去重

双下划线查询方法:

-->范围查询
    大于 :xx_gt   / 小于 : xx_lt
    大于等于: xx__gte   缺陷 :python 对小数不敏感(识别有误)
    小于等于: xx__lte 
eg: res = models.Books.objects.filter(price__lte=500)
                                      
    或者..或者是 :xx__in=[]
eg: res = models.Books.objects.filter(price__in=[222,444,500])
                                      
    在...到...之间  : xx__range = (,)   顾头顾尾
eg: res = models.Books.objects.filter(price__range=(200,800))
                                      
    查询日期: publish_date__year'
eg: res = models.Books.objects.filter(publish_date__year='2019')

模糊查询

MySQL中的模糊查询
  -->关键字 like
     模糊匹配的符号:
          %:匹配任何个数的任意字符
          _:匹配一位任意的字符

以....开头: __startswith
res = models.Books.objects.filter(title__startswith='三')

以....结尾: __endswith
res = models.Books.objects.filter(title__endswith='1')

包含...在其中:__contains
res = models.Books.objects.filter(title__contains='p')  # 默认区分大小写
res = models.Books.objects.filter(title__icontains='p')  # 忽略大小写 加i

一对多数据的增删改查:

增:
    第一种 :models.Book.objects.create(title='三国演义',ublish_id=1)
    #直接传表里面的实际字段 跟数据主键值  publish_id

	第二种 :publish_obj = models.Publish.objects.filter(pk=2).first()
	models.Book.objects.create(title='红楼梦',publish=publish_obj)  	# 传虚拟字段  跟数据对象即可

改:
	第一种 :models.Book.objects.filter(pk=1).update(publish_id=2)
	第二种 :publish_obj = models.Publish.objects.filter(pk=1).first()
	models.Book.objects.filter(pk=1).update(publish=publish_obj)

删:
	models.Publish.objects.filter(pk=1).delete()  
    # 默认就是级联删除 级联更新 (关联表一起变化)

多对多数据的增删改查:

--》创建第三张表进行操作。

增:  add()
	把指定的model对象添加到第三张关联表中。
    
添加对象:
>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)

添加id:
>>> models.Book.objects.first().authors.add(*[1, 2])


改 : set() 

更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置
-->括号内的数据必须要是可迭代对象!!!
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])


删 : remove()  / clear()

从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)

 清空  删除某个数据在第三张表中的所有记录:  clear()
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.clear()

跨表设计

正反向查询 ;
正 向查询 :有外键查的一边,查询另一边   --》查询按字段
反 向查询 :没有外键的一边, 查询拥有外键一边 ---》按表明小写

反向:对象_set ---> 查询数据有多个 / 一个就不加


基于对象的跨表查询:
	--》 子查询  分步操作

# 基于对象的跨表查询         子查询  分步操作
# 1.查询书籍主键为2的出版社名称
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish)  # 出版社对象
print(book_obj.publish.name)

# 2.查询书籍主键为4的作者姓名
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())

# 3.查询作者是jason的手机号码
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail)
print(author_obj.author_detail.phone)
  
# 4.查询出版社是东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())

# 5.查询作者是jason写过的书籍
author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.book_set)  # app01.Book.None
print(author_obj.book_set.all())  # app01.Book.None

# 6.查询手机号是120的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
print(author_detail_obj.author)
print(author_detail_obj.author.email)


基于双下滑先的跨表查询

基于双下滑先的跨表查询:
	--》联表操作
# 1.查询书籍pk为2的出版社名称
# 正向
res = models.Book.objects.filter(pk=2).values('publish__name')  # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
print(res)
# 反向
res = models.Publish.objects.filter(book__pk=2).values('name')
print(res)

# 2.查询书籍pk为2的作者姓名和邮箱
res = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
print(res)
res = models.Author.objects.filter(book__pk=2).values('name','email')
print(res)

# 3.查询作者是egon的家庭地址
res = models.Author.objects.filter(name='egon').values('author_detail__addr')
print(res)
res = models.AuthorDetail.objects.filter(author__name='egon').values('addr')
print(res)


# 4.查询出版社是东方出版社出版过的书的名字
res = models.Publish.objects.filter(name='东方出版社').values('book__title')
print(res)
res = models.Book.objects.filter(publish__name='东方出版社').values('title')
print(res)

# 查询书籍pk是2的作者的手机号
res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)
res = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
print(res)


小技巧

models + 表名 --》 查询以表名为基表 !!

什么时候需要加all ???
    1.当正向查询点击外键字段数据有多个的情况下 需要.all()
    2.app01.Author.None  一旦看到该结果 只需要加.all()即可

mysql : 链表操作(
        inner join
        left join
        right join
        union   #两边表都没有
    )
 什么时候反向查询的时候表名小写需要加_set??
        一对多表关系
        多对多表关系
    
   一对一表关系不需要加_set

技巧:在写orm语句的时候跟你写sql语句一样 不要想着一次性写完,查一点再写一点
posted @ 2019-11-27 20:14  black__star  阅读(144)  评论(0编辑  收藏  举报