zoukankan      html  css  js  c++  java
  • django2

    八 Models

    数据库的配置

    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)
    •    mysqlclient
    •    MySQL
    •    PyMySQL(纯python的mysql驱动程序)

    3     在django的项目中会默认使用sqlite数据库,在settings里有如下设置:

    如果我们想要更改数据库,需要修改如下:

     

    DATABASES = {
    
        'default': {
    
            'ENGINE': 'django.db.backends.mysql', 
    
            'NAME': 'books',    #你的数据库名称
    
            'USER': 'root',   #你的数据库用户名
    
            'PASSWORD': '', #你的数据库密码
    
            'HOST': '', #你的数据库主机,留空默认为localhost
    
            'PORT': '3306', #你的数据库端口
    
        }
    
    }
    View Code

    注意:

    NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建
    
    USER和PASSWORD分别是数据库的用户名和密码。
    
    设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。
    
    然后,启动项目,会报错:no module named MySQLdb
    
    这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
    
    所以,我们只需要找到项目名文件下的__init__,在里面写入:
    
    import pymysql
    pymysql.install_as_MySQLdb()
    
    问题解决!
    View Code

    ORM(对象关系映射)

    用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作。

    优点: 1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句。快速开发,由此而来。

              2 可以避免一些新手程序猿写sql语句带来的性能问题。

                比如 我们查询User表中的所有字段:

                新手可能会用select * from  auth_user,这样会因为多了一个匹配动作而影响效率的。

     缺点:1  性能有所牺牲,不过现在的各种ORM框架都在尝试各种方法,比如缓存,延迟加载登来减轻这个问题。效果很显著。

              2  对于个别复杂查询,ORM仍然力不从心,为了解决这个问题,ORM一般也支持写raw sql。

              3  通过QuerySet的query属性查询对应操作的sql语句

    author_obj=models.Author.objects.filter(id=2)
    print(author_obj.query)

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

    表(模型)的创建:

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

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

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

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

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

    from django.db import models<br>
    class Publisher(models.Model):
        name = models.CharField(max_length=30, verbose_name="名称")
        address = models.CharField("地址", max_length=50)
        city = models.CharField('城市',max_length=60)
        state_province = models.CharField(max_length=30)
        country = models.CharField(max_length=50)
        website = models.URLField()
     
        class Meta:
            verbose_name = '出版商'
            verbose_name_plural = verbose_name
     
        def __str__(self):
            return self.name
     
    class Author(models.Model):
        name = models.CharField(max_length=30)
        def __str__(self):
            return self.name
     
    class AuthorDetail(models.Model):
        sex = models.BooleanField(max_length=1, choices=((0, ''),(1, ''),))
        email = models.EmailField()
        address = models.CharField(max_length=50)
        birthday = models.DateField()
        author = models.OneToOneField(Author)
     
    class Book(models.Model):
        title = models.CharField(max_length=100)
        authors = models.ManyToManyField(Author)
        publisher = models.ForeignKey(Publisher)
        publication_date = models.DateField()
        price=models.DecimalField(max_digits=5,decimal_places=2,default=10)
        def __str__(self):
            return self.title
    View Code

    注意1:记得在settings里的INSTALLED_APPS中加入'app01',然后再同步数据库。

    注意2: models.ForeignKey("Publish") & models.ForeignKey(Publish)

    分析代码:

           <1>  每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。

           <2>  每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。

           <3>  模型之间的三种关系:一对一,一对多,多对多。

                 一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

                 一对多:就是主外键关系;(foreign key)

                 多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)

           <4>  模型常用的字段类型参数

    <1> CharField
            #字符串字段, 用于较短的字符串.
            #CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.
    
    <2> IntegerField
           #用于保存一个整数.
    
    <3> FloatField
            # 一个浮点数. 必须 提供两个参数:
            #
            # 参数    描述
            # max_digits    总位数(不包括小数点和符号)
            # decimal_places    小数位数
                    # 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
                    #
                    # models.FloatField(..., max_digits=5, decimal_places=2)
                    # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
                    #
                    # models.FloatField(..., max_digits=19, decimal_places=10)
                    # admin 用一个文本框(<input type="text">)表示该字段保存的数据.
    
    <4> AutoField
            # 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 
            # 自定义一个主键:my_id=models.AutoField(primary_key=True)
            # 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.
    
    <5> BooleanField
            # A true/false field. admin 用 checkbox 来表示此类字段.
    
    <6> TextField
            # 一个容量很大的文本字段.
            # admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).
    
    <7> EmailField
            # 一个带有检查Email合法性的 CharField,不接受 maxlength 参数.
    
    <8> DateField
            # 一个日期字段. 共有下列额外的可选参数:
            # Argument    描述
            # auto_now    当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
            # auto_now_add    当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
            #(仅仅在admin中有意义...)
    
    <9> DateTimeField
            #  一个日期时间字段. 类似 DateField 支持同样的附加选项.
    
    <10> ImageField
            # 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field,
            # 如果提供这两个参数,则图片将按提供的高度和宽度规格保存.     
    <11> FileField
         # 一个文件上传字段.
         #要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, 
         #该格式将被上载文件的 date/time 
         #替换(so that uploaded files don't fill up the given directory).
         # admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .
    
         #注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
                #(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. 
                # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 
                #  WEB服务器用户帐号是可写的.
                #(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
                # 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 
                # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField 
                # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.
    
    <12> URLField
          # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且
          # 没有返回404响应).
          # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)
    
    <13> NullBooleanField
           # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项
           # admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.
    
    <14> SlugField
           # "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs
           # 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50.  #在
           # 以前的 Django 版本,没有任何办法改变50 这个长度.
           # 这暗示了 db_index=True.
           # 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate 
           # the slug, via JavaScript,in the object's admin form: models.SlugField
           # (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.
    
    <13> XMLField
            #一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.
    
    <14> FilePathField
            # 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
            # 参数    描述
            # path    必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. 
            # Example: "/home/images".
            # match    可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名.  
            # 注意这个正则表达式只会应用到 base filename 而不是
            # 路径全名. Example: "foo.*.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.
            # recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
            # 这三个参数可以同时使用.
            # match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
            # FilePathField(path="/home/images", match="foo.*", recursive=True)
            # ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
    
    <15> IPAddressField
            # 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
    <16># CommaSeparatedIntegerField
            # 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
    View Code

    <5>  Field重要参数

    <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)
    View Code

    表的操作(增删改查):

    -------------------------------------增(create  ,  save) -------------------------------

    from app01.models import *
    
        #create方式一:   Author.objects.create(name='Alvin')
    
        #create方式二:   Author.objects.create(**{"name":"alex"})
    
        #save方式一:     author=Author(name="alvin")
                        author.save()
    
        #save方式二:     author=Author()
                        author.name="alvin"
                        author.save()

    重点来了------->那么如何创建存在一对多或多对多关系的一本书的信息呢?(如何处理外键关系的字段如一对多的publisher和多对多的authors)

    #一对多(ForeignKey):
    
        #方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个
        #       字段设定对应值:
               Book.objects.create(title='php',
                                   publisher_id=2,   #这里的2是指为该book对象绑定了Publisher表中id=2的行对象
                                   publication_date='2017-7-7',
                                   price=99)
    
    
        #方式二:
        #       <1> 先获取要绑定的Publisher对象:
            pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
                    state_province='河北',country='China',website='http://www.hbu.com')
        OR  pub_obj=Publisher.objects.get(id=1)
    
        #       <2>将 publisher_id=2 改为  publisher=pub_obj
    
    #多对多(ManyToManyField()):
    
        author1=Author.objects.get(id=1)
        author2=Author.objects.filter(name='alvin')[0]
        book=Book.objects.get(id=1)
        book.authors.add(author1,author2)
        #等同于:
        book.authors.add(*[author1,author2])
        book.authors.remove(*[author1,author2])
        #-------------------
        book=models.Book.objects.filter(id__gt=1)
        authors=models.Author.objects.filter(id=1)[0]
        authors.book_set.add(*book)
        authors.book_set.remove(*book)
        #-------------------
        book.authors.add(1)
        book.authors.remove(1)
        authors.book_set.add(1)
        authors.book_set.remove(1)
    
    #注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
    #     如果第三张表是自己创建的:
         class Book2Author(models.Model):
                author=models.ForeignKey("Author")
                Book=  models.ForeignKey("Book")
    #     那么就还有一种方式:
                author_obj=models.Author.objects.filter(id=2)[0]
                book_obj  =models.Book.objects.filter(id=3)[0]
    
                s=models.Book2Author.objects.create(author_id=1,Book_id=2)
                s.save()
                s=models.Book2Author(author=author_obj,Book_id=1)
                s.save()
    View Code

    -----------------------------------------删(delete) ---------------------------------------------

    >>> Book.objects.filter(id=1).delete()
    (3, {'app01.Book_authors': 2, 'app01.Book': 1})

    我们表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

    如果是多对多的关系: remove()和clear()方法:

    #正向
    book = models.Book.objects.filter(id=1)
    
    #删除第三张表中和女孩1关联的所有关联信息
    book.author.clear()        #清空与book中id=1 关联的所有数据
    book.author.remove(2)  #可以为id
    book.author.remove(*[1,2,3,4])     #可以为列表,前面加*
    
    #反向
    author = models.Author.objects.filter(id=1)
    author.book_set.clear() #清空与boy中id=1 关联的所有数据

    ----------------------------------------改(update和save) ----------------------------------------

    实例:

    注意:

    <1> 第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。

    <2>在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。

    #---------------- update方法直接设定对应属性----------------
        models.Book.objects.filter(id=3).update(title="PHP")
        ##sql:
        ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)
    
    
    #--------------- save方法会将所有属性重新设定一遍,效率低-----------
        obj=models.Book.objects.filter(id=3)[0]
        obj.title="Python"
        obj.save()
    # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", 
    # "app01_book"."color", "app01_book"."page_num", 
    # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; 
    # 
    # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
    # "publisher_id" = 1 WHERE "app01_book"."id" = 3;
    View Code

          在这个例子里我们可以看到Django的save()方法更新了不仅仅是title列的值,还有更新了所有的列。 若title以外的列有可能会被其他的进程所改动的情况下,只更改title列显然是更加明智的。更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法,与之等同的SQL语句变得更高效,并且不会引起竞态条件。

    此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

    注意,这里因为update返回的是一个整形,所以没法用query属性;对于每次创建一个对象,想显示对应的raw sql,需要在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',
            },
        }
    }
    
    LOGGING
    输出LOGGING

    注意:如果是多对多的改:

     obj=Book.objects.filter(id=1)[0]
        author=Author.objects.filter(id__gt=2)
    
        obj.author.clear()
        obj.author.add(*author)

    ---------------------------------------查(filter,value等) -------------------------------------

    ---------->查询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。
    View Code

    补充:

    #扩展查询,有时候DJANGO的查询API不能方便的设置查询条件,提供了另外的扩展查询方法extra:
    #extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None
    
    (1)  Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    (2)  Blog.objects.extra(
            select=SortedDict([('a', '%s'), ('b', '%s')]),
            select_params=('one', 'two'))
    
    (3)  q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
         q = q.extra(order_by = ['-is_recent'])
    
    (4)  Entry.objects.extra(where=['headline=%s'], params=['Lennon'])  
    
    extra
    View Code

    ---------->惰性机制:

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

    QuerySet特点:

           <1>  可迭代的

           <2>  可切片

    #objs=models.Book.objects.all()#[obj1,obj2,ob3...]
    
        #QuerySet:   可迭代
    
        # for obj in objs:#每一obj就是一个行对象
        #     print("obj:",obj)
        # QuerySet:  可切片
    
        # print(objs[1])
        # print(objs[1:4])
        # print(objs[::-1])
    View Code

    QuerySet的高效使用:

    <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,可能
    会造成额外的数据库查询。
    View Code

    ---------->对象查询,单表条件查询,多表条件关联查询

    #--------------------对象形式的查找--------------------------
        # 正向查找
        ret1=models.Book.objects.first()
        print(ret1.title)
        print(ret1.price)
        print(ret1.publisher)
        print(ret1.publisher.name)  #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合
    
        # 反向查找
        ret2=models.Publish.objects.last()
        print(ret2.name)
        print(ret2.city)
        #如何拿到与它绑定的Book对象呢?
        print(ret2.book_set.all()) #ret2.book_set是一个queryset集合
    
    #---------------了不起的双下划线(__)之单表条件查询----------------
    
    #    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,
    
    #----------------了不起的双下划线(__)之多表条件关联查询---------------
    
    # 正向查找(条件)
    
    #     ret3=models.Book.objects.filter(title='Python').values('id')
    #     print(ret3)#[{'id': 1}]
    
          #正向查找(条件)之一对多
    
          ret4=models.Book.objects.filter(title='Python').values('publisher__city')
          print(ret4)  #[{'publisher__city': '北京'}]
    
          #正向查找(条件)之多对多
          ret5=models.Book.objects.filter(title='Python').values('author__name')
          print(ret5)
          ret6=models.Book.objects.filter(author__name="alex").values('title')
          print(ret6)
    
          #注意
          #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段
          #一对多和多对多在这里用法没区别
    
    # 反向查找(条件)
    
        #反向查找之一对多:
        ret8=models.Publisher.objects.filter(book__title='Python').values('name')
        print(ret8)#[{'name': '人大出版社'}]  注意,book__title中的book就是Publisher的关联表名
    
        ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
        print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
    
        #反向查找之多对多:
        ret10=models.Author.objects.filter(book__title='Python').values('name')
        print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
    
        #注意
        #正向查找的book__title中的book是表名Book
        #一对多和多对多在这里用法没区别
    View Code

    注意:条件查询即与对象查询对应,是指在filter,values等方法中的通过__来明确查询条件。

    ---------->聚合查询和分组查询

    <1> aggregate(*args,**kwargs):

       通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。

    from django.db.models import Avg,Min,Sum,Max
    
    从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有
    图书的集合。
    
    >>> Book.objects.all().aggregate(Avg('price'))
    {'price__avg': 34.35}
    
    aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值
    
    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的
    标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定
    一个名称,可以向聚合子句提供它:
    >>> Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 34.35}
    
    
    如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
    >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
    {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
    View Code

    <2> annotate(*args,**kwargs):

       可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

           查询alex出的书总价格  

     查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name

         查询各个出版社最便宜的书价是多少

    ---------->F查询和Q查询

    仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:

    # F 使用查询条件的值,专门取对象中某列值的操作
    
        # from django.db.models import F
        # models.Tb1.objects.update(num=F('num')+1)
    
    
    # Q 构建搜索条件
        from django.db.models import Q
    
        #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
        q1=models.Book.objects.filter(Q(title__startswith='P')).all()
        print(q1)#[<Book: Python>, <Book: Perl>]
    
        # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
        Q(title__startswith='P') | Q(title__startswith='J')
    
        # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
        Q(title__startswith='P') | ~Q(pub_date__year=2005)
    
        # 4、应用范围:
    
        # Each lookup function that takes keyword-arguments (e.g. filter(),
        #  exclude(), get()) can also be passed one or more Q objects as
        # positional (not-named) arguments. If you provide multiple Q object
        # arguments to a lookup function, the arguments will be “AND”ed
        # together. For example:
    
        Book.objects.get(
            Q(title__startswith='P'),
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
        )
    
        #sql:
        # SELECT * from polls WHERE question LIKE 'P%'
        #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
    
        # import datetime
        # e=datetime.date(2005,5,6)  #2005-05-06
    
        # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
        # 正确:
        Book.objects.get(
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
            title__startswith='P')
        # 错误:
        Book.objects.get(
            question__startswith='P',
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
    View Code

    raw sql

    django中models的操作,也是调用了ORM框架来实现的,pymysql 或者mysqldb,所以我们也可以使用原生的SQL语句来操作数据库!

    九 admin的配置

    admin是django强大功能之一,它能共从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能,下面这一系列文章就逐步深入介绍如何定制适合自己的admin应用。

    如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项

    LANGUAGE_CODE = 'en-us'  #LANGUAGE_CODE = 'zh-hans'

    一  认识ModelAdmin

       管理界面的定制类,如需扩展特定的model界面需从该类继承。

    二 注册medel类到admin的两种方式:

         <1>   使用register的方法

    admin.site.register(Book,MyAdmin)

      <2>   使用register的装饰器

    @admin.register(Book)

    三 掌握一些常用的设置技巧

    •     list_display:     指定要显示的字段
    •     search_fields:  指定搜索的字段
    •     list_filter:        指定列表过滤器
    •     ordering:       指定排序字段
    from django.contrib import admin
    from app01.models import *
    # Register your models here.
    
    # @admin.register(Book)#----->单给某个表加一个定制
    class MyAdmin(admin.ModelAdmin):
        list_display = ("title","price","publisher")
        search_fields = ("title","publisher")
        list_filter = ("publisher",)
        ordering = ("price",)
        fieldsets =[
            (None,               {'fields': ['title']}),
            ('price information', {'fields': ['price',"publisher"], 'classes': ['collapse']}),
        ]
    
    admin.site.register(Book,MyAdmin)
    admin.site.register(Publish)
    admin.site.register(Author)
    View Code

    在models.py建表

    from django.db import models
    
    # Create your models here.
    
    
    
    class Book(models.Model):
        name=models.CharField(max_length=20)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        author=models.ManyToManyField("Author")
    
        def __str__(self):
            return self.name
    
    
    class Publish(models.Model):
        name=models.CharField(max_length=20)
        city=models.CharField(max_length=20)
    
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=20)
        age=models.IntegerField()
    
        def __str__(self):
            return self.name
    View Code

    在views.py

    from django.shortcuts import render,HttpResponse
    from django.db.models import Avg,Min,Sum,Max,Count
    from django.db.models import Q,F
    
    # Create your views here.
    
    from app01.models import *
    
    
    def addd(req):
        # 添加方法一
        # Book.objects.create(name="你的爸爸是谁",price=100,pub_date="2017-5-5",publish_id=1)
    
        # 添加方法二
        # p=Publish.objects.filter(name="重庆书店")[0]
        # Book.objects.create(name="我是你爸",price=10,pub_date="2027-1-5",publish=p)
        return HttpResponse("成功")
    
    
    def select(req):
        # b=Book.objects.get(id=3)
        # print(b.name)
        # print(b.price)
        # print(b.publish.name)
        # print(b.publish.city)
    
        # b=Book.objects.filter()
        # b1=b.values("name","price")
        # return render(req,"select.html",locals())
        # print("b1",b1)
        # for i in b1:
        #     print(i["name"])
    
        # p=Publish.objects.filter(name="人民书店")[0]
        # p1=p.book_set.all()
        # p2=p1.values("name")
        # print("p2",p2)
        # for i in p2:
        #     print(i["name"])
        # return HttpResponse("111")
    
    
        # ret=Book.objects.filter(publish__name="重庆书店").values("name")
        # print(ret)
    
        # ret1=Publish.objects.filter(book__name="python").values("name")
        # print(ret1)
        # ret2=Book.objects.filter(name="python").values("publish__name")
        # print(ret2)
    
        # b=Book.objects.filter(author__name="alex").values("name","price","pub_date")
        # print(b)
        # for i in b:
        #     print(i["name"])
        #     print(i["price"])
        #     print(i["pub_date"])
    
         # 书的总价格
        # ret=Book.objects.all().aggregate(Sum("price"))
        # print(ret)
    
        # tom写的书的总价格
        # ret=Book.objects.filter(author__name="tom").aggregate(Sum("price"))
        # print(ret)
    
    
        #算每个作者的书的总价格
        # ret=Book.objects.values("author__name").annotate(Sum("price"))
        # print(ret)
    
        #  |~非 要用Q
        # ret=Book.objects.filter(Q(name="go") | Q(price=54))
        # print(ret)
    
        #  F
        # Book.objects.filter(id=5).update(price=F("price")+100)
    
        return HttpResponse("111")
    View Code

    COOKIE和SESSION

    from django.shortcuts import render,redirect
    
    # Create your views here.
    
    
    def login(req):
        print("COOKIES",req.COOKIES)
        print("SESSION",req.session)
    
        if req.method=="POST":
            name=req.POST.get("user")
            pwd=req.POST.get("pwd")
            if name=="liao" and pwd=="123":
                # ret=redirect("/index/")
                # ret.set_cookie("username",name)
                # return ret
    
                #COOKIE SESSION
                req.session["is_login"]=True
                req.session["user"]=name
    
                return redirect("/index")
    
        return render(req,"login.html")
    
    
    def index(req):
        # if req.COOKIES.get("username",None):
        #     name=req.COOKIES.get("username",None)
        #     return render(req,"index.html",locals())
    
        if req.session.get("is_login",None):
            name=req.session.get("user",None)
            return render(req,"index.html",locals())
        else:
            return redirect("/login/")
    View Code
  • 相关阅读:
    GNU make manual 翻译(九十九)
    GNU make manual 翻译( 九十五)
    Shell的 for 循环小例子
    makefile中对目录遍历的小例子
    GNU make manual 翻译(九十三)
    GNU make manual 翻译( 一百)
    GNU make manual 翻译( 九十七)
    GNU make manual 翻译( 九十八)
    mapserver4.8.3 的readme.win32的中文翻译文件
    遥控器编程
  • 原文地址:https://www.cnblogs.com/liaoboshi/p/6498137.html
Copyright © 2011-2022 走看看