• ORM相关操作(未完善)


    单表查询

    QuerySet的查询方法

    <1> all():                  查询所有结果
    <2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
    <3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
    <4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
    <5> order_by(*field):       对查询结果排序('-id')/('price')
                        
    <6> reverse():              对查询结果反向排序     >>>前面要先有排序才能反向
    <7> count():                返回数据库中匹配查询(QuerySet)的对象数量。
    <8> first():                返回第一条记录
    <9> last():                返回最后一条记录
    <10> exists():             如果QuerySet包含数据,就返回True,否则返回False
    QuerySet的查询方法

    values 与 values_list    Queryset的每个元素都变为字典或元组

    distinct(): id不相同 所以无法排除 需要搭配values 与 values_list  使用

    QuerySet的添加数据方法

    user_obj =models.User.objects.create(name='tank',age=73,register_time='2019-2-14')
    
    user_obj = models.User(name='kevin',age=30,register_time='2019-1-1')
    user_obj.save()
    View Code

    QuerySet的修改数据方法

    bookquery=models.Book.objects.all().first()
    
    方式一:取出对象后修改属性,再save()
    bookquery.name="hahahah"
    bookquery.save()
    
    方式二:把所有queryset对象.update(k=v)的形式统一修改
    
    bookquery=models.Book.objects.all().update(name="egon")
    View Code

    QuerySet的删除数据方法

    delete()对对象和清空queryset均适用
    
    queryset
    models.User.objects.filter(name='egon').delete()
    
    对象
    user_obj.delete()
    View Code

    QuerySet中神奇双下划线

    字段__gt 大于xx的  
    res = models.User.objects.filter(age__gt=44)  筛选
    
    字段__lt 小于xx的 
    res = models.User.objects.filter(age__gt=44)  筛选
    
    字段__gte大于等于XXX的
    
    字段__lte小于等于XXX的
    
    字段__in 字段值在某个列表里的     age__in=[44,22,73] 是442273的
    
    age__range=[22,44]  在22到44范围
    
    
    字段__(day或year或者mon) 
    比如
    date__year=2019 筛选出date字段中年为多少的
    
    字段__contains=“n” 字  符串里有n的 区分大小写
    字段__icontains="N"     符串里有n或N的 不区分大小写
    
    startswith='j'    以j开头的所有..
    __endswith='n' 以n结尾的所有...
    View Code

      

    多表查询

    Query对象与Queryset的跨表查询

    原则:正向查字段 反向差表名小写_set  一对一只需要表名小写

     正向查询

    反向查询

     

    基于Queryset双下划线查询

    Query对象的增加

     queryset与query的修改

    queryset修改
    models.Book.objects.all().update(publish_id=3) #所有图书图书馆都为3
    
    models.Book.objects.filter(pk=1).update(publish=publish_obj)#传对象 会自动绑定
    
    
    对象修改
    book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.publish_id = 3  # 点表中真实存在的字段名
    # book_obj.save()
    
    ublish_obj = models.Publish.objects.filter(pk=2).first()
    book_obj.publish = publish_obj  # 点orm中字段名 传该字段对应的表的数据对象
    book_obj.save()
    queryset与query的修改

    book_obj.authors.set((1,))     #属性必须是多的
    book_obj.authors.set((1,2,3)) #属性是一对多或多对多

    删除某个绑定关系

    Book_obj.author.remove( 1,2 )  一个个 不能使用元祖或者列表

    清空 clear() 全清

    清空的是你当前这个表记录对应的绑定关系
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.clear()

    queryset与query的删除

      级联删除
      关联的对象删除 自己也删除

       

    ManyToMany与ForeignKey的操

    ForeignKey

    增
    models.Book.objects.create(publish=publish_obj)
    models.Book.objects.create(publish_id=1)
    
    改
    models.Book.objects.filter(pk=1).update(publish_id=1)
    models.Book.objects.filter(pk=1).update(publish=publish_obj)
    
    book_obj.publish_id = 3  # 点表中真实存在的字段名
    book_obj.save()
    
    
    删
    删除外键对象,并删除自己
    外键

    ManyToMany

    增  add(*args)  #也可以是传 *obj_list
    改  set(tuble)  
    set必须接收一个可迭代对象 
    
    删remove(*args)# 上面三个方法都可以支持传多个数字或对象
    clear()清除所有绑定  
    外键中  删除对方对自己的绑定,对方允许null才行
    多对多 清除所有的字段 第三张表少了这个记录
    View Code

      


    聚合查询  aggregate  分组查询 annotate

    跨表查询不需要 表名_set

    使用之前先导入:

    rom django.db.models import Avg, Sum, Max, Min, Count


    aggregate聚合

    from django.db.models import Avg, Sum, Max, Min, Count
    
    res=models.Book.objects.all().aggregate(Avg("price")) 
    print(res) #不指定别名返回字典{'price__avg': 13.233333}
    
    res=models.Book.objects.all().aggregate(price_avg=Avg("price")) 
    print(res) #指定返回值13.233333
    聚合方法

    annotate分组

    u_qset=Author.objects.all().annotate(age_avg=Avg("age"))
    print(u_qset) #QuerySet 分组之后没影响
    
    u_obj=Author.objects.all().annotate(age_avg=Avg("book__price"))
    print(u_obj.values("age_avg")) #可以转为age_avg

    Django ORM 常用字段和参数

    1.AutoField
    
    手动指定递增列  自动递增的int,primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列,有了这个就不会创建
    
    2.IntegerField
    
     整型-2147483648 to 2147483647
    
    3.CharField
    
    参数中必须有max_length  
    
    4.DateField
    
    日期格式  YYYY-MM-DD
    
    5.DateTimeField
    
     YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    ORM常用字段

    字段的参数

    1.null 
    
    是否为空,values bool类型
    
    2.unique
    
    是否唯一,设置后,不能再重复
    
    3.db_index
    
    设置该字段为索引
    
    4.default
    
    默认值
    
     
    
    以下是事件字段独有
    
    5.auto_now_add 
    
    设置True后,插入数据会自动添加当前时间
    
    6.auto_now
    
    更新的事件
    
     
    常用参数

    讲一下choise,用户只能多选一

    models.py

    class User(models.Model):

      choices = ((1,'重点大学'),(2,'普通本科'),(3,'专科'),(4,'其他'))
      education = models.IntegerField(choices=choices)

    在对象查找属性中

    对象.字段拿到的是值

      

    print(u_obj.sex)  #1

    如果希望是实际意义上的内容

    u_obj.get_字段_display()
    print(u_obj.get_sex_display()) #
    
    

    Django框架中的logging使用

    BASE_LOG_DIR = os.path.join(BASE_DIR, "log")
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
                          '[%(levelname)s][%(message)s]'
            },
            'simple': {
                'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
            },
            'collect': {
                'format': '%(message)s'
            }
        },
        'filters': {
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            },
        },
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'filters': ['require_debug_true'],  # 只有在Django debug为True时才在屏幕打印日志
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'SF': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,根据文件大小自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 50,  # 日志大小 50M
                'backupCount': 3,  # 备份数为3  xx.log --> xx.log.1 --> xx.log.2 --> xx.log.3
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            'TF': {
                'level': 'INFO',
                'class': 'logging.handlers.TimedRotatingFileHandler',  # 保存到文件,根据时间自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日志文件
                'backupCount': 3,  # 备份数为3  xx.log --> xx.log.2018-08-23_00-00-00 --> xx.log.2018-08-24_00-00-00 --> ...
                'when': 'D',  # 每天一切, 可选值有S/秒 M/分 H/小时 D/天 W0-W6/周(0=周一) midnight/如果没指定时间就默认在午夜
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            'error': {
                'level': 'ERROR',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 5,  # 日志大小 50M
                'backupCount': 5,
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            'collect': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
                'maxBytes': 1024 * 1024 * 50,  # 日志大小 50M
                'backupCount': 5,
                'formatter': 'collect',
                'encoding': "utf-8"
            }
        },
        'loggers': {
            '': {  # 默认的logger应用如下配置
                'handlers': ['SF', 'console', 'error'],  # 上线之后可以把'console'移除
                'level': 'DEBUG',
                'propagate': True,
            },
            'collect': {  # 名为 'collect'的logger还单独处理
                'handlers': ['console', 'collect'],
                'level': 'INFO',
            }
        },
    }
    LOGING

    解决字段参数无法筛选-F与Q查询

    F

    适用之前from django.db.models import F

    我们的过滤器只能筛选某个值,现在想字段值进行比较

    筛选出卖出大于库存的字段
    res=models.SP.object.filter(maichu__get=F("kucun"))
    
    把自己的价格+10
    res=models.SP.object.all().update(price=F("price")+50)
    
    所有的商品名称后面添加“NB”
    #不能直接拼接
    from django.db.models.functions import Concat
    from django.db.models import Value
    ret3=models.Product.objects.update(name=Concat(F('name'),Value('nb')))

    Q

    如果和普通的对比 Q必须放在前面

    from django.models import Q
    
    筛选出id大于3 或者年龄小于10
    models.Book.object.all().filter(Q(id__gt=3)|Q(age__lt=10))
    
    ~取反  
    名字不等于egon的
    models.Book.object.all().filter(Q(id__gt=3)|~Q(name="egon")

    如果和普通的对比 Q必须放在前面
    models.Book.object.all().filter(Q(id__gt=3),name="egon"


    如果字段名只有字符串怎么办?

    q=Q()

    q.connector="and"

    q.children.append("字段名","字段值")

    res=models.biao.object.filter(q)


      

    事物

    原子性操作和mysql一样

    from django.db import transaction
    with transaction.atomic():
        # 创建一条订单数据
        # 能执行成功
         #钱+100
        #钱-100
    
    可以防止执行到一半,后面代码无法执行造成的后果
    要么都成功,要都失败
    View Code

    QuerySet有哪些方法

    all  filter  exclude  annotate  distinct  order_by
    
    
    1.select_related方法
    OneToOneField 和外键均可以适用
    Django会获取相应外键对应的对象,使用该字段不会查找数据库
    
    citys = models.city.objects.select_related('province').all()
    citys.province  #不会走数据库
    
    2.select_related() 
    ManyToManyField和外键字段,可以使用prefetch_related()来进行优化。
    View Code

    牺牲效率优化内存-defer 和 only

    我们查询出来的Queryset里的对象拥有全部属性,而有些属性我们不会经常使用

    此时就可以用defer和only优化我们的“坦克”变身小刺客。等我们需要用到偏门的字段 再去数据库查询

    节约了我们内存的使用,但是牺牲了效率

    value  #查出来的元素是一个字典
    
    only  #规定只有某个属性
    only('id','name')#取的对象,只有id和name属性
    
    defer('id','name')#相反,字段除了id和name都有
    
    上述两个拿到了不需要的字段 才会去数据库查
    

    自定义字段

    用途不多说,直接干

    class MyCharField(models.Field):
        # 数据库中Char类型需要指定长度,所以要传max_length
        def __init__(self,max_length,*args,**kwargs):
            self.max_length = max_length
            # 调用父类init,一定要写关键字传参,因为Field的init参数很多,可以看一下它的源码
            super().__init__(max_length=max_length,*args,**kwargs)
        
        # 该方法也不能少
        def db_type(self, connection):
            return 'char(%s)'%self.max_length
    自定义字段

    其他边边角角

    建立第三张表的三种方式  

    1.ManyTOMany 全自动

    1.好处 不需要自己关心第三张表

    2.坏处 创表时无法自己手动关联其他字段

    class Book(models.Model):
        name = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author')
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    多对多创建表

    2.手动创建第三张表关联两个外键 纯手动

    1.好处 可以添加其他字段

    2.坏处 跨表查询不够方便

    class Book(models.Model):
        name = models.CharField(max_length=32)
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
    class Book2Author(models.Model):
        book = models.ForeignKey(to='Book')
        author = models.ForeignKey(to='Author')
            info = models.CharField(max_length=32)    
    手动创建第三张表的方式

    3.手动创建第三张表,仍使用ManyToMany

    1.好处 可以添加其他字段 够方便

    2.就是在使用的时候,不能用set、add、remove的方法,需要自己使用第三张表进行操作

    伪代码
    class 作者表(model.Modes):
        ...字段
        modes.ManyToMany(to="书籍",through="第三张表",through_fields=("表3字段1",“表3字段2”))
        
    class 书籍(models.Model):
    	....字段
    
    
    class 第三张表
        book = models.ForeignKey(to='Book')  #id 
        author = models.ForeignKey(to='Author') #id 
        ....其他字段信息





      

    在使用的时候,不能用set、add、remove的方法,需要自己跨到第三张表进行操作

    models.User2Bumen.objects.create(user_id=1,bumen_id=2)

    ContentType编码

    网页是别人写的,django也是别人写的,我们在前后端数据交互的时候

    要告诉服务器,我们的数据是哪些需要哪些编码格式,服务器才好区分 常见的有以下三种

    urlencoded

    对应数据格式键值对 name=123,后端会根据数据格式放在request.POST

    formdate

    表单编码格式

    比如普通键值对仍然在request.POST中,但是文件的话会丢到reque.Files

     

    application/json

    ajax发送json格式数据

    jason的内容在request.body里 是二进制

    Ajax

    可以发起一个异步请求,服务器会给我们一个返回结果

    我们可以拿到数据进行替换

    我们来做一个在线上传头像,并替换Img的例子

    需要实例化一个Datefrom 对象

    processData 和 contentType 都变为False,不处理Date和使用默认编码 

    $("#hread").on("click",function () {
            let touxiang_obj=$("img");
            let  touxiang_img=$("#touxiang");
             let formdata =new FormData();  /* 实例化一个form表单  */
             {#formdata.datamyfile=touxiang_img[0].files[0];  /* 为表单添加 file和文件内容,并且jquery不能使用files所有取索引0 添加获取files,取第一个 */#}
            formdata.append("myfile",touxiang_img[0].files[0]);
            {#console.log(formdata);#}
            {#console.log(touxiang_img[0].files[0]);#}
    
            $.ajax(
                {# ajax事件 #}
                {
                    url:"/test/",
                    type:"post",
                    data:formdata,
                    processData: false,
                    contentType:false,
                    success:function (data) {
                        leturl="/".concat(data);
                        touxiang_obj[1].src=leturl;
                        console.log(touxiang_obj[1]);
                        {#var res=encodeURI(data);#}
    
                    }
    
                })
        })
    发送表单提交

    ajax发送json

    需要指定改为contentType:pplication/json

    数据需要转为JSON.stringify

    $('#d1').click(function () {
           $.ajax({
               url:'',  // url参数可以不写,默认就是当前页面打开的地址
               type:'post',
               contentType:'application/json',
               data:JSON.stringify({'name':'jason','hobby':'study'}),
               success:function (data) {
                   {#alert(data)#}
                   {#$('#i3').val(data)#}
               }
           })
        });
    提交jason

     

     

    form表单与ajax异同点

    1.form表单不支持异步提交局部刷新
    2.form表单不支持传输json格式数据
    3.form表单与ajax默认传输数据的编码格式都是urlencoded

    批量提交

    服务器每次需要操作大量数据,操作完才能渲染页面,过程太久

    我们先让把实例化对象存在容器里,通过bulk_create(容器)创建

    l=[]
    for i in range(10000):
        l.append(models.Book(name="书{}".format(i)))
        models.Book.objects.bulk_create(l)
    View Code

    分页

    class Pagination(object):
        def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param pager_count:  最多显示的页码个数
    
            用法:
            queryset = model.objects.all()
            page_obj = Pagination(current_page,all_count)
            page_data = queryset[page_obj.start:page_obj.end]
            获取数据用page_data而不再使用原始的queryset
            获取前端分页样式用page_obj.page_html
            """
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
    
            if current_page < 1:
                current_page = 1
    
            self.current_page = current_page
    
            self.all_count = all_count
            self.per_page_num = per_page_num
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            # 添加前面的nav和ul标签
            page_html_list.append('''
                        <nav aria-label='Page navigation>'
                        <ul class='pagination'>
                    ''')
            first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                if i == self.current_page:
                    temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
                else:
                    temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
            page_html_list.append(next_page)
    
            last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
            page_html_list.append(last_page)
            # 尾部添加标签
            page_html_list.append('''
                                               </nav>
                                               </ul>
                                           ''')
            return ''.join(page_html_list)
    分页器代码

    使用

    page_obj = my_page.Pagination(current_page=current_page,all_count=all_count) # 对总数据进行切片
    page_queryset = book_list[page_obj.start:page_obj.end]

    前端

    {{ page_obj.page_html|safe }}

     聚合合并

    from django.db.models import Aggregate, CharField
    
    class Concat(Aggregate):
        """ORM用来分组显示其他字段 相当于group_concat"""
        function = 'GROUP_CONCAT'
        template = '%(function)s(%(distinct)s%(expressions)s)'
    
        def __init__(self, expression, distinct=False, **extra):
            super(Concat, self).__init__(
                expression,
                distinct='DISTINCT ' if distinct else '',
                output_field=CharField(),
                **extra)
    
    #使用
    WhiteList.objects.values('ip').annotate(id=Concat('id'))

      

    from django.db.models import Aggregate, CharField
    
    class Concat(Aggregate):
        """ORM用来分组显示其他字段 相当于group_concat"""
        function = 'GROUP_CONCAT'
        template = '%(function)s(%(distinct)s%(expressions)s)'
    
        def __init__(self, expression, distinct=False, **extra):
            super(Concat, self).__init__(
                expression,
                distinct='DISTINCT ' if distinct else '',
                output_field=CharField(),
                **extra)
    
  • 相关阅读:
    生成8位随机字符串
    Python字符串反转
    dd备份文件系统
    多线程mtr-代码
    Sysctl命令及linux内核参数调整
    解决系统存在大量TIME_WAIT状态的连接
    tcpkill清除异常tcp连接
    graphite
    sed 中带变量的情况
    JAVA的Random类
  • 原文地址:https://www.cnblogs.com/xzqpy/p/10993753.html
Copyright © 2020-2023  润新知