zoukankan      html  css  js  c++  java
  • Django框架基础

      web框架概念

    框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统。

    对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

     socket模拟服务端

          最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

      如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

          正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。

     web框架概念解析

    step1

     最最基本的wsgi实现
     python实现wsgi说明

    step2

     wsgi实现的http路由

    step3

     wsgi实现的简单登录1
     login.html

    step4

    进行模块化

     bin文件主运行文件
     views文件存放函数
     url文件存放路由
     templates文件夹存放html文件

     MVC和MTV模式

    web框架:MVC(model view controller)和MTV(model templates view controller)

    Django的MTV模式本质是各组件之间为了保持松耦合关系,Django的MTV分别代表:

           Model(模型):负责业务对象与数据库的对象(ORM)

           Template(模版):负责如何把页面展示给用户

           View(视图):负责业务逻辑,并在适当的时候调用Model和Template

    此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

     mvc补充

    注:用户的一次web请求,顺序:用户-服务器-web应用

      Django基本命令

     Django项目管理

     创建Django项目
    django-admin startproject mysite

    在当前目录生成mysite的项目,目录结构如下:

    • manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
    • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
    • urls.py ----- 负责把URL模式映射到应用程序。
    • wsgi.py----默认测试用的web服务器
     创建应用
    python manage.py startapp blog

    进入到mysite目录创建应用

    主要是models和views文件

     启动项目
    python manage.py runserver 8000

    默认启动的端口就是8000,访问:http://127.0.0.1:8000/

    项目与应用:
      一个项目有多个应用
      一个应用可以被多个项目拥有

     第一个Django项目

    step1:urls.py文件,增加路由信息

     新增路由

    step2:views.py修改视图函数

     新增视图函数

    step3:访问

    http://127.0.0.1:8080/

    http://127.0.0.1:8080/index/

    注:其他命令,用到时候补充

    Django框架: 大而全

    Flask框架: 小而精

     同步更改数据库表或字段
    python manage.py syncdb
         
    注意:Django 1.7.1 及以上的版本需要用以下命令
    python manage.py makemigrations
    python manage.py migrate

    这种方法可以创建表,当你在models.py中新增了类时,运行它就可以自动在数据库中创建表了,不用手动创建。

    清空数据库
    python manage.py flush
    #此命令会询问是 yes 还是 no, 选择 yes 会把数据全部清空掉,只留下空表。
     创建超级管理员
    python manage.py createsuperuser   
    # 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填  
    # 修改 用户密码可以用:
    python manage.py changepassword username
    终端环境
    python manage.py shell
    #这个命令和 直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据的测试非常方便。
    数据库环境终端
    python manage.py dbshell
    Django 会自动进入在settings.py中设置的数据库,如果是 MySQL 或 postgreSQL,会要求输入数据库用户密码。
    
    在这个终端可以执行数据库的SQL语句。如果您对SQL比较熟悉,可能喜欢这种方式。
     更多命令
    python manage.py

      路由分配系统

     路由介绍

    Django的路由分配系统,就是指的controller

    功能:客户端访问的url的路径(path)与视图函数一一映射关系,通过唯一的路径访问到唯一的函数

    语法:

    复制代码
    urlpatterns = [
        url(正则表达式, views视图函数,参数,别名),
    ]
    #参数说明:
        #一个正则表达式字符串,进行url路径匹配
        #一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
        #可选的要传递给视图函数的默认参数(字典形式)
        #一个可选的name参数
    复制代码

     URLconf的正则表达式参数

    参考python的正则表达式,该参数只会匹配路径,并不会匹配路径后的方法,而匹配到的参数或捕获到的值,永远为字符串

    示例:

    复制代码
    urlpatterns = [
        url(r'^admin/', admin.site.urls),   #admin/开头的
        url(r'^$', views.index),    #匹配不带路径的
        url(r'^index$', views.index),    #完全匹配index
        #url(r'index', views.index),    #只要带index的
        url(r'^(d{4})/$', views.show_year),    #无名分组
        url(r'^(?P<year>d{4})/(?P<month>d{2})/$', views.year_month),    #命名分组
    ]
    复制代码

    当匹配成功的时候,会调用视图函数中的一系列函数,即views.py文件中的一些列函数,这些函数默认会传入一个请求头消息,所以这些函数必须要有一个参数进行数据接收。

    正则匹配注意事项:

    1、一旦匹配成功则不再继续下一条路由的匹配
    2、若要从URL中捕获一个值,只需要在它周围放置一对圆括号,即分组的方式
    3、不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^path 而不是 ^/path
    4、每个正则表达式前面的'r'是可选的但是建议加上,因为匹配时候可能会出现元字符
     是否自动补全url中最后的/
     无名分组匹配/h5>

    当输入http://127.0.0.1:8000/2014/的时候,会匹配示例中的无名分组

    views.show_year视图函数

    def show_year(request,year):    #无名分组会将括号里面匹配到的值自动传入到对应的视图函数中,所以,视图函数必须要有一个参数接收值
        return HttpResponse(year)
     命名分组匹配

    当输入http://127.0.0.1:8000/2014/12/时候,会匹配到示例中的命名分组

    views.year_month视图函数

    def year_month(request,month,year):    #命名分组的名字必须和视图函数的参数名字对应,顺序无所谓
        return HttpResponse("year:"+year+"month:"+month)

    接收值的参数可以设置一个默认值,那么该函数可以给其他的匹配项使用,不会出现接收值的数量的错误

     Django应用的路由分发

    不同于在全局的urls.py文件中将所有涉及到的页面全部写在里面,因为一个项目中可以有多个应用,每个应用的页面和其他应用的页面应该是不相通的,在这种情况下,可以将全局的urls.py文件所涉及的页面改成应用路由,即只通过该文件进行应用的跳转,应用下面的页面通过应用的urls.py文件进行跳转

    示例:将mysite1项目下的全局urls.py文件作为应用路由文件,通过该文件跳转到blog应用下,而将blog应用下的urls.py文件作为blog应用下页面的路由文件

     应用路由示例

     URLconf的别名

    name参数,直接看示例:

    复制代码
    from django.conf.urls import url, include
    from django.contrib import admin
    from blog import  views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$', views.index),    #首页
        url(r'^index$', views.index),   #首页
        url(r'^regs/', views.reg,name="register"),  #别名
    ]
    复制代码

    视图函数

    def reg(request):
        if request.method=="POST":
            return HttpResponse("WO AI NI")
        return render(request,"register.html")

    然后在templates文件夹里创建register.html

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <!--action的写法-->
    <!--完整写法:<form action="http://127.0.0.1:8000/date" method="post">-->
    <!--简单写法:<form action="/date" method="post">,会自动加上协议、ip和端口-->
    
    <!--别名涉及到模版渲染,后续说明,现在这么写就可以-->
    <form action="{% url "register" %}" method="post">
        <p>用户:<input type="text"></p>
        <p>密码:<input type="password"></p>
        <input type="submit">
    </form>
    
    </body>
    </html>
    复制代码

    以上,当urls.py文件中的匹配的url路径有变化的时候,不会影响到html文件数据的提交

    注:如果提示“Forbidden (403)”页面,修改全局的setting.py文件

    复制代码
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',    #注释该行,这是Django的一个安全机制限制
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    复制代码

     传递额外参数到视图函数

     了解

      视图函数

    视图函数即视图,本质上就是python函数,能够接受web请求,然后做出响应,响应的内容可以是任何东西,图片文本html重定向等

    习惯上写到views.py文件中,但是其他文件也可以,只需要在urls.py文件中导入就可以

     最简单的完整视图示例

    from django.shortcuts import render,HttpResponse
    #HttpResponse是响应消息调用的方法
    def show_time(request):    #request接收的是请求头数据
        import  datetime
        t=datetime.datetime.now()
        return HttpResponse("<h1>time<?h1> %s" %t)    #响应的消息

    注意:视图函数的函数名字完全自定义,只不过要和urls.py文件中的路由信息匹配上

    http请求-响应过程中有两个核心对象

            http请求对象:HttpRequest

            http响应响应:HttpResponse

     快捷函数

     render函数

    render(request, template_name[, context])

    结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse对象。

    参数:
      request: 用于生成响应的请求对象。

      template_name:要使用的模板的完整名称,可选的参数

      context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。

      content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。

      status:响应的状态码。默认为200。

     redirect函数

    不同于render函数,redirect用于连接的跳转

     总结

    render和redirect的区别

      redirect走的是路径

      render返回的是模板

    示例:

     redirect和render

      Template模板系统

    为了将web页面的设计和Python的代码分离开,解决html代码和python代码的耦合性,使项目更干净简洁更容易维护,就是通过django提供的模板系统来解决该问题。

    模板系统的组成其实就是:html代码+逻辑控制语句

    只要带有模板语法的html文件都是模板

     模板系统语法

     变量引用

    语法格式

    {{  var_name  }}

    Template和Context对象

    C:DjangoProjectMysite>python manage.py shell
    >>> from django.template import Context, Template
    >>> t = Template('My name is {{ name }}.')
    >>> c = Context({'name': 'Stephane'})
    >>> t.render(c)
    'My name is Stephane.'

    同一模板,多个上下文,一旦有了模板对象,就可以通过它渲染多个context对象,无论何时我们都可以像这样使用同一模板源渲染多个Context,只进行一次模板创建然后多次调用render()方法渲染

    复制代码
    # Low版
    for name in ('John', 'Julie', 'Pat'):
        t = Template('Hello, {{ name }}')
        print t.render(Context({'name': name}))
    
    # Good版
    t = Template('Hello, {{ name }}')
    for name in ('John', 'Julie', 'Pat'):
        print t.render(Context({'name': name}))
    复制代码

    变量引用方式

     Django模板变量引用方式
     深度变量的引用

    除了上述的字符串变量的处理,类似于列表、字典等复杂数据的处理是通过句点字符 “ ” 来进行处理的。

     深度变量引用

    注,只能调用不传参数的方法

     变量过滤器

    语法格式

    {{ obj|filter:param }}

    示例

     过滤器

     标签tag的使用

    语法

    {% tags %}
     if标签
     View Code

    if标签接受and,or或者not来测试多个变量值或者否定一个给定的变量

    if标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:

    {% if obj1 and obj2 or obj3 %}

     for标签

    遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容

     View Code
     csrf_token标签

    用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。

     url标签

    引用路由配置的地址

     View Code
     with标签

    用更简单的变量名替代复杂的变量名

     View Code
     verbatim标签

    禁止render

     View Code
     load标签
     View Code 

     自定义过滤器和标签

    a、在app中创建templatetags模块(必须的),是一个py包

    b、创建任意 .py 文件,如:my_tags.py

     View Code

    c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}

    d、使用simple_tag和filter(如何调用)

     View Code

    e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

    filter可以用在if等语句后,simple_tag不可以

    {% if num|filter_multi:30 > 100 %}
        {{ num|filter_multi:30 }}
    {% endif %}

     extend模板继承

     一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django 解决此类问题的首选方法是使用模板继承 

    本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。

    创建基础模板

     基板

    子模板的作用就是重载、添加或保留基板里面块的内容。

    子模板继承

     子html文件

    继承的步骤

       <1> 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
       <2> 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对base.html 进行拓展,
           并包含区域特定的风格与设计。
       <3> 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。

    注意点

    复制代码
     <1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
    
     <2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此
        你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越
        多越好。
    
     <3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
        如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模
        板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
    
     <4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。
        也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个
        相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
    复制代码

      数据库与ORM

     配置数据库

    1、Django默认支持sqlite、mysql、oracle、postgresql数据库

    django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

    mysql的引擎名称:django.db.backends.mysql

    2、Mysql驱动程序

    •    MySQLdb(mysql python)
    •    mysqlclient
    •    MySQL
    •    PyMySQL(纯python的mysql驱动程序)

    3、更改项目数据库

    settings.py配置文件,更改DATABASES

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

     ORM表模型

     表模型的创建

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

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

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

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

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

     表创建代码

    代码分析 

    复制代码
    < 1 > 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
    
    < 2 > 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
    
    < 3 > 模型之间的三种关系:一对一,一对多,多对多。
    一对一:实质就是在主外键(author_id就是foreignkey)的关系基础上,给外键加了一个UNIQUE=True的属性;
    一对多:就是主外键关系;(foreignkey)
    多对多:(ManyToManyField)自动创建第三张表(当然我们也可以自己创建第三张表:两个foreignkey)
    复制代码
    增删查改之增

    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)

     一对多
     多对多
    增删查改之删
    Book.objects.filter(id=1).delete()
    #表面上删除了一条信息,实际却删除了三条,因为删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

    解除绑定关系

    # book_obj=Book.objects.get(id=2)
    # book_obj.authors.clear()    #解除所有的绑定
    
    # author=Author.objects.get(name="name")
    # book_obj.authors.remove(author) #只解除指定的
    增删查改之改
    author=Author.objects.get(id=5)
    author.name="tenglan"
    author.save()
    
    #Publisher.objects.filter(id=2).update(name="American publisher")

    注意:

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

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

     update更新
     save更新 

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

    注意,这里因为update返回的是一个整形,所以没法用query属性;对于每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:

     Mysql日志记录
    增删查改之查

    查询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
    复制代码
    复制代码
    ---------------了不起的双下划线(__)之单表条件查询----------------
    
    #    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,
    复制代码
    QuerySet与惰性机制

    所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用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])
    复制代码
     惰性机制的使用
    对象查询
    复制代码
    #--------------------对象形式的查找--------------------------
        # 正向查找
        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
        #一对多和多对多在这里用法没区别
    复制代码

     注意:条件查询即与对象查询对应,是指在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')}
    复制代码

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

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

    查询alex出的书总价格      

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

       

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

    聚合查询和分组查询

    仅仅靠单一的关键字参数查询已经很难满足查询要求。此时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)))
    复制代码

      补充: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)
     注册medel类到admin
    •     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)
  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/bsxq/p/8259129.html
Copyright © 2011-2022 走看看