zoukankan      html  css  js  c++  java
  • 1127 模型层orm表操作

    昨日回顾

    视图层
    		小白必会三板斧
    		
    		1.JsonResponse
    			默认只能序列化字典类型
    			如果你想序列化其他json能够支持的格式
    			你需要加一个参数safe=False
    			
    			当你的数据有中文的时候 如果你不想自动转码
    			你需要制定一个参数 来告诉 你需要动内部任何数据
    			借助于原生的json模块作为参考依据
    			json.dumps(obj,ensure_ascii=False)
    			阅读源码 发现 json_dumps_params = {}
    			json.dumps(obj,cls,**json_dumps_params)
    		
    		2.FBV与CBV
    			FBV
    				路由
    					路由与视图函数内存地址
    				视图
    					函数
    			
    			CBV
    				路由
    					看似 路由与类点方法
    					实在还是路由与函数的内存地址
    				视图
    					类
    						# 只要是处理前端请求的业务逻辑的视图函数 都需要加上request形参
    						from django.views import View
    						class MyLogin(View):
    							def get(self,request):
    								return render(request,'login.html')
    							
    							def post(self,request):
    								return HttpResponse('post请求')
    					
    					urs.py
    						url(r'^login/',views.MyLogin.as_view())
    						# 1.函数名加括号执行优先级最高
    						# 2.该方法要么是普通函数 要么是绑定给类的方法
    						自动变形
    						url(r'^login/',views.view)
    						
    						# 内部源码 
    						def as_view(cls,**kwargs):
    							def view(...):
    								self = cls(...)  # 生成自己写的类的对象
    								return self.dispatch(...)  # 一定要确认self到底是谁
    								# 然后一定要问你一句 对象查找属性和方法的顺序(慢)
    							return view
    						
    						# 一旦用户敲了login 会自动加括号调用view函数
    						def dispatch(...)
    							# 先判断当前请求方式在不在默认的八个请求方法内
    							if request.method.lower() in self.http_method_allowed:
    								# 利用发射 获取到方法名对应的属性或者是方法
    								handler = getattr(self,request.method.lower(),error)
    							else:
    								# 提示报错
    							return handler(...)  # 调用请求方法所对应的函数
    			如何给CBV加装饰器
    				django推荐你使用内置的模块来给CBV加装饰器
    				from django.utils.decorators import method_decorator
    				# 1.直接在类上面装
    					method_decorator(wrapper,name='给类内部哪个方法装')
    				# 2.直接在类的内部方法上装
    					method_decorator(wrapper)
    				# 3.给类内部所有的方法都装  重写dispacth方法
    					method_decorator(wrapper)
    					
    	模板层
    		1.模板语法的传值
    			python所有的基本数据类型全部支持
    			
    			函数
    				会自动加括号调用 并且函数如果需要参数 那么模板语法不支持
    			
    			类
    				会自动加括号实例化  产生对象
    			# 只要对象能够加括号调用 那么模板语法都会自动加括号
    			对象
    				直接传对象 显示的是对象的内容地址    你可以定义__str__来控制对象的展示
    				
    				对象在html页面上可以调用绑定方法 
    			
    			
    		2.过滤器的使用
    			语法结构   |
    			语法特点   会将|左边的数据当做第一个参数传入 :右边的数据当做第二个参数传入
    			
    			|length
    			|add
    			|default:'默认值'  # 类似于get方法和getattr方法
    			|slice:'2:9:2'
    			|filesizeformat  # 将数字格式化成表示容量大小的单位 
    			|truncatechars  # 截取字符 包含三个点
    			|truncatewords  # 截取单词 按空格算单词数  不包含三个点
    			|safe  # 告诉浏览器文本内容是安全的 如果有html标签 正常识别渲染即可
    			
    			前后端取消转义的方法
    				前端
    					|safe
    				
    				后端
    					from django.utils.safestring import mark_safe
    					res = mark_safe('<a href='https://www.baidu.com'>点我</a>')
    			# 也就意味着 html代码可以不再html文件内写
    			# 可以在后端写html代码 然后传递给前端
    			
    		
    		3.标签
    			一对逻辑
    			if判断
    			
    			for循环
    				for循环内部有一个forloop对象
    				该对象可以判断for循环的开始和结束  first  last
    				也可以帮你获取索引或者数据计数  counter0  counter
    				
    				for循环和if判断嵌套使用
    				{% for i in l %}
    					{% if forloop.first %}
    						第一次操作
    					{% elif forloop.last %}
    						最后一次操作
    					{% else %}
    						中间操作
    					{% endif %}
    					{% empty %}
    						如果for循环对象是空 执行empty内的逻辑
    				{% endfor %}
    				
    			
    			with起别名
    			
    		自定义过滤器 标签  inclusion_tag
    			1.先在应用下创建一个名字必须交templatetags文件夹
    			2.文件夹内部创建一个任意名称的py文件(mytag)
    			3.py文件内必须先写两句代码
    				from django.template impory Library
    				
    				register = Library()
    				
    				@regiser.filters(name='过滤器的名字')
    				def index():
    					pass
    				
    				@register.simple_tag(name='标签名字')
    				def index1():
    					...
    				
    				@regisrer.inclusion_tag('html文件名',name='名字')
    				def index2():
    					...
    	
    			如何使用自定义的
    				{% load 任意名称的py文件名mytag %}
    				
    		
    		模板的继承
    			当一个页面需要被频繁使用的时候 你可以考虑使用模板的继承
    			
    			先通过block块划定后期可能需要修的区域
    			
    			一个模板上通常一个有三块区域
    				css
    					一个
    				html内容
    					可以有多个
    				js  一个
    
    			如何使用模板
    				{% extends '模板的名字' %}
    				
    				{% block css %}
    					修改模板中css区域内容
    				{% endblock %}
    				
    
    			
    		模板的导入
    			{% include '你要想导入的html文件名' %}
    

    模型层

    1.配置测试脚本

    1.1 应用下tests文件

    直接在某一应用下的tests文件中书写代码(去manage.py拷贝前四行代码),然后手动写两行代码

    import os
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
        
        import django
        django.setup()
    -----------------------以上是配置代码------------------------
        # 一定要等待测试脚本搭建完毕之后 才能导入django文件进行测试
        from app01 import models
        '''测试代码'''
    

    1.2 新建任意名称文件

    一样书写以上代码,也可以

    2. 数据的增删改查

    2.1 创建数据

    1.create方法

    直接插入数据进行保存

    book_obj = models.Books.objects.create(title='挪威的森林',price=123.23,pulish_date='2019-09-09')
    
    book_obj = models.Books.objects.create(title='人间失格',price=222.23,pulish_date=ctime)
    
    print(book_obj)
    

    2.对象的save()方法

    利用对象的绑定方法(实例化对象传值,利用对象的save方法创建保存)

    book_obj = models.Books(title='我是猫',price=467.78,pulish_date='2019-02-22')
    book_obj.save()
    

    queryset对象

    filter查询出来的结果是一个Queryset对象

    • 只要是Queryset对象就可以无限制的调用Queryset方法

      res = models.Books.objects.filter(pk=1).filter().filter().filter().filter()
      
    • 只要是Queryset对象就可以通过.query查看当前结果对应的sql语句

      res.query
      SELECT `app01_books`.`id`, `app01_books`.`title`, `app01_books`.`price`, `app01_books`.`publish_date` FROM `app01_books` WHERE `app01_books`.`id` = 1  
      

    2.2 修改数据

    pk会自动查找到当前表的主键字段,后期都是使用pk指代主键字段

    res = models.Books.objects.filter(pk=1)
    print(res)  # <QuerySet [<Books: Books object>]>
    

    1.利用Queryset方法update

    models.Books.objects.filter(pk=2).update(price=333.33)
    

    2.利用对象 get与filter

    使用get与save,该方法不推荐使用

    利用对象的修改 内部其实是重头到位将数据的所有字段都重新写一遍
    
    book_obj = models.Books.objects.get(pk=3)
    book_obj.price = 888.88
    book_obj.save()	   # 对象的保存
    

    get与filter的区别

    • filter获取到的是一个Queryset对象,类似一个列表
    • get获取到的直接就是数据本身
    • 当条件不存在的情况下
      • filter不会报错直接返回一个空,推荐使用filter方法
      • get则会直接报错

    2.3 删除数据

    1.利用Queryset方法 delete

    models.Books.objects.filter(pk=3).delete()
    

    2.利用对象的delete方法

    book_obj = models.Books.objects.get(pk=3)
    book_obj.delete()
    

    2.4查询数据 十三门徒

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

        res0 = models.Books.objects.filter(pk=1)
        res1 = models.Books.objects
        res2 = models.Books
        res3 = models
    
    
        print(res0,type(res0))      
        # <QuerySet [<Books: Books object>]>     <class 'django.db.models.query.QuerySet'>
        
        print(res1,type(res1))  
        # app01.Books.objects          <class 'django.db.models.manager.Manager'>
        
        print(res2,type(res2))  
        # <class 'app01.models.Books'>          <class 'django.db.models.base.ModelBase'>
        
        print(res3,type(res3))  
        # <module 'app01.models' from 'D:\pycharm\项目\开课练习\day53\app01\models.py'>      <class 'module'>
    

    自动打印对应sql语句

    如果你想查看所有的orm语句内部对应的sql语句,你可以直接在配置文件setting中配置相应的代码即可

    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.查询所有 all()

    返回Queryset对象

    res = models.Books.objects.all()
    print(res)
    
    #  <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
    

    2.筛选 filter()

    返回Queryset对象

    相当于你原生sql语句里面的where,filter中多个参数之间是and关系

    res = models.Books.objects.filter(pk=1)
    res = models.Books.objects.filter(pk=1,title='挪威的森林')
    print(res)
    

    3.筛选 get()

    获取数据对象本身

    条件不存在会直接报错,并且查询条件必须唯一, 不推荐使用

        res = models.Books.objects.get(pk=2)
        print(res)  # Books object
    

    4.取第一个 first()

    获取数据对象

    取Queryset对象中的第一个数据对象

    res = models.Books.objects.filter(title='我是猫').first()
    print(res)      # Books object
    print(res.title)    # 我是猫
    

    5.取最后 last()

    获取数据对象

    取Queryset对象中的最后一个数据对象

    res = models.Books.objects.filter(title='我是猫').last()
    print(res)      # Books object
    print(res.id)    # 5
    

    6.计数 count()

    返回数字

    统计数据的个数

    res = models.Books.objects.count()
    print(res)      # 4
    

    7.获取指定字段值 values()

    返回Queryset对象,列表套字典形式

    获取数据对象中指定的字段的值,可以有多个

        res = models.Books.objects.values('title','price')
        print(res)
        # <QuerySet [{'title': '挪威的森林', 'price': Decimal('123.23')}, {'title': '人间失格', 'price': Decimal('333.33')}, {'title': '我是猫', 'price': Decimal('888.88')}, {'title': '我是猫', 'price': Decimal('333.77')}]>
    

    8.获取指定字段值 values_list()

    返回Queryset对象,列表套元组形式

        res = models.Books.objects.values_list('title')
        print(res)
        # <QuerySet [('挪威的森林',), ('人间失格',), ('我是猫',), ('我是猫',)]>
    
    

    9.排序 order_by()

    按照指定的字段进行排序,默认是升序,字段前添加-符号降序排列

    res = models.Books.objects.order_by('price')
    
    print(res)
    # <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>]>
    

    语义明确 使用all().order_by('')

    res = models.Books.objects.all().order_by('price')
    

    降序

    res = models.Books.objects.order_by('-price')
    

    10.颠倒顺序 reverse()

    颠倒的对象必须提前排序,与order_by联用,单独使用没有效果

    res = models.Books.objects.all().order_by('price').reverse()
    
    

    11.排除...之外 exclude()

    返回Queryset对象

    将拥有某一个字段排除出去

    res = models.Books.objects.all().exclude(title='我是猫')
    print(res)
    # <QuerySet [<Books: Books object>, <Books: Books object>]>
    

    12.判断查询结果是否有值 exists()

    返回布尔值

    res = models.Books.objects.filter(pk=100).exists()
    print(res)	# False
    

    13.对查询结果去重 distinct()

    去重的前提是,必须完全相同( id不同也不行 ),可以与.values('')配合使用

    res = models.Books.objects.values('title')
    print(res)  # <QuerySet [{'title': '挪威的森林'}, {'title': '人间失格'}, {'title': '我是猫'}, {'title': '我是猫'}]>
    
    res = models.Books.objects.values('title').distinct()
    print(res)  # <QuerySet [{'title': '挪威的森林'}, {'title': '人间失格'}, {'title': '我是猫'}]>
    
    

    2.5 神奇的双下划线方法

    • __gt 大于
    • __lt 大于
    • __gte 大于等于
    • __lte 小于等于
    • __lt 大于
    • __in=['',''] 取列表内固定参数
    • __range=(,) 取范围内(头尾兼顾)
    • date字段
      • 可以通过在其后加__year,__month,__day等来获取date的特点部分数据,指定获取年月日数据
    • 模糊查询
      • __startswith='' 查询以...开头
      • __endswith='' 查询以...结尾
      • __contains='' 查询中间有某一字符的(默认区分大小写)
        • __icontains=''前面加i不区分大小写

    mysql中的模糊查询

    关键字like
    	%:匹配任意个数的任意字符
    	_:匹配一位任意的字符
    
    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")  # 获取name字段包含"ven"的
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
     
    models.Tb1.objects.filter(id__range=[1, 3])      # id范围是1到3的,等价于SQL的bettwen and
     
    类似的还有:startswith,istartswith, endswith, iendswith 
    
    date字段还可以:
    models.Class.objects.filter(first_day__year=2017)
    date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据
    # 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)
    需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~
    

    3. 多表查询

    时间类型

    DateField(auto_now_add=True)		
    时间类型
    	auto_now:每次修改数据的时候会自动更新数据(只会展示最新的一次修改时间)
    	auto_now_add:当数据创建出来的时候,会自动将创建时间记录下来,适用于注册
    

    1.表的创建与表关系的建立

    from django.db import models
    
    # Create your models here.
    
    
    # 多表联查
    
    
    # 书
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8,decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
        # 与出版社表关联 一对一
        publish = models.ForeignKey(to='Publish')
        # 与作者多对多关系
        authors = models.ManyToManyField(to='Author')
    
        
    # 出版社
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=64)
    
        
    # 作者
    class Author(models.Model):
        name = models.CharField(max_length=32)
        email = models.EmailField()
        # 与作业详情页一对一
        author_detail = models.OneToOneField(to='AuthorDetail')
    
    
    # 作者详细
    class AuthorDetail(models.Model):
        name = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    

    2.一对多字段数据的增删改查

    2.1 增 create()

    1.直接传表字段

    传表里的实际字段,跟数据主键值

    models.Book.objects.create(title='京华烟云',price=222.22,publish_id=1)
    
    

    2.直接传对象

    传给虚拟字段(外键名的虚拟字段),跟数据对象,(查找想要关联的对象传入)

    publish_obj = models.Publish.objects.filter(pk=2).first()
    
    models.Book.objects.create(title='四世同堂',price=333.33,publish=publish_obj)
    

    2.2 改 update()

    1.直接传表字段

    传表里的实际字段,跟数据主键值

    models.Book.objects.filter(pk=1).update(publish_id=3)
    

    2.直接放对象

    传虚拟字段,跟数据对象

    publish_obj = models.Publish.objects.filter(pk=2).first()
        models.Book.objects.filter(pk=1).update(publish=publish_obj)
    

    2.3 删 delete()

    删除有外键关系的表字段,默认是级联删除.

    models.Publish.objects.filter(pk=1).delete()
    

    3.多对多字段的增删改查

    3.1 增 add()

    add()方法能够向第三张表添加数据,既支持传数字,也支持传对象,两种都可以是多个

    1.直接传数字

    # 获取主键为2的书籍对象
    book_obj = models.Book.objects.filter(pk=2).first()
    # 根据对象点第三张表的外键字段进行添加
    book_obj.authors.add(1) # 给第三张表里的书籍绑定一个主键为1的作者
    book_obj.authors.add(2,3) # 给第三张表里的书籍绑定主键为2和3的作者
    

    2.传对象

    # 获取主键为2的书籍对象
    book_obj = models.Book.objects.filter(pk=2).first()
    # 获得author中主键为1,2的对象
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    # 书籍对象.authors进入第三张表中添加
    book_obj.authors.add(author_obj,author_obj2 )
    

    3.2 改 set(可迭代对象)

    set()方法支持传多个,需要使用(可迭代对象)的方式,其原理是先删除再添加.

    1.直接传数字

    book_obj = models.Book.objects.filter(pk=2).first()
    
    book_obj.authors.set((1,))
    book_obj.authors.set((2,3))
    

    2.传对象

    # 获取主键为2的书籍对象
    book_obj = models.Book.objects.filter(pk=2).first()
    
    # 获得author中主键为1,2的对象
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    
    book_obj.authors.set((author_obj,author_obj2 ))
    

    3.3 删 remove()

    数字对象都可以,支持传多个,不需要迭代

    1.直接传数字

    book_obj = models.Book.objects.filter(pk=2).first()
    
    book_obj.authors.remove(1) 
    book_obj.authors.remove(2,3) 
    

    2.传对象

    book_obj = models.Book.objects.filter(pk=2).first()
    
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    
    book_obj.authors.remove(author_obj)
    book_obj.authors.remove(author_obj,author_obj2 )
    

    3.4 清空 clear()

    删除某个数据在第三张表中的所有记录

    将书籍主键为2的对象,在第三张表中清除掉
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.clear()
    

    4. 跨表查询

    正反向查询

    1.正向查询按 关系字段

    正向查询
    	具有外键关系字段的一方向无关系的一表的查询是正向
    

    2.反向查询按 表名小写+_set

    反向查询
    	没有外键关系字段的表向有的表查询是反向
    

    1.基于对象的跨表查询

    子查询
    

    正向查询

    当正向查询
    	点击外键字段数据有多个的情况下,需要.all()
    	app01.Author.None 即加.all()
    

    题目

        # 查询书籍主键为2的出版社名称
        
        book_obj = models.Book.objects.filter(pk=2).first()
        print(book_obj.publish) #出版社对象
        print(book_obj.publish.name) #出版社名称
    
        # 查询书籍主键为4的作者姓名
        book_obj = models.Book.objects.filter(pk=4).first()
        print(book_obj.authors)    # app01.Author.None
        print(book_obj.authors.all())   # 拿到主键为4的作者名列表
    

    反向查询

    反向查询时
    一对一查询需要			'表名小写'
    一对多,多对多查询需要		'表名小写_set.all()`
    

    题目

        # 查询出版社是东方出版社出的书籍
        publish_obj = models.Publish.objects.filter(name='东方出版社').first()
        print(publish_obj.book_set.all())
    
        # 查询作者是jason写的书
        author_obj = models.Author.objects.filter(name='Jason').first()
        print(author_obj.book_set) # app01.Author.None
        print(author_obj.book_set.all())    # 写过的书籍
    

    2.基于双下划线的跨表查询

    联表操作
    

    正向查询

    写外键字段就相当于已经跨到了字段所关系的表中,你想要改表的哪个字段信息,只需要加__获取即可
    

    题目

    # 查询书籍主键为2的出版社名称
    res = models.Book.objects.filter(pk=2).values('publish__name')
    print(res)
    
    # 查询书籍pk为2的作者姓名和邮箱
    res = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
    print(res)
    

    反向查询

    反向查询  表名小写__字段
    	filter(表名小写__字段=值)
    

    题目

    # 获取书籍主键为2的出版社名称
    res = models.Publish.objects.filter(book__pk=2).values('name')
    print(res)
    
    # 获取书籍pk为2的作者姓名与邮箱
    res = models.Author.objects.filter(book__pk=2).values('name','email')
    print(res)
    

    连续跨表

    # 获取书籍pk为2的作者的手机号
    res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
    
  • 相关阅读:
    [BZOJ]2589: Spoj 10707 Count on a tree II
    [BZOJ]2434: [Noi2011]阿狸的打字机
    Codeforces Round #408 (Div. 2)
    [BZOJ]2653: middle
    洛谷4月月赛R1
    2017省夏令营Day8
    2017省夏令营Day7
    2017省夏令营Day6
    【20170604校内模拟赛】香蕉
    【20170602模拟赛】秋之国的夏日祭
  • 原文地址:https://www.cnblogs.com/fwzzz/p/11946389.html
Copyright © 2011-2022 走看看