• day16-python项目Django框架之基础


    第1章 Django之MTV模型

    1.1 课堂总结记录

    Django
    
     
    
       1 流程:
    
           (1) 设计url: url(r'^timer/', timer), # timer(request)
    
           (2) 构建视图函数:
    
               在views.py:
    
                def timer(request):
    
                    import time
    
                    ctime=time.time()
    
                    return render(request,"timer.html",{"ctime":ctime})
    
                   
    
            (3) templates:timer.html
    
                    <p>当前时间:{{ ctime }}</p>
    
                   
    
                   
    
       
    
     
    
        2 URL控制器(路由层):
    
           
    
            简单配置
    
            分组
    
            有名分组
    
            分发
    
            反向解析
    
           
    
       
    
        3 MTV--View(视图层):
    
          
    
           请求对象
    
                request:
    
                   request.GET
    
                   request.POST
    
                   request.method
    
                   request.path
    
          
    
         
    
           响应对象:
    
                Httpresponse()
    
                render()
    
                redirect()
    
       
    
       
    
        4 MTV--Template(模板层)
    
       
    
              渲染变量 {{ }}
    
                   深度查询句点符
    
                   过滤器{{ var|filter:参数}}
    
                   add
    
                   date
    
                   safe
    
                   filesizeformat     
    
                  
    
              渲染标签 {% %}
    
                   for
    
                   if
    
                   url 反向解析
    
                   csrftoken
    
              自定义过滤器和标签
    
     
    
        4 MTV--Model(模型层)
    
       
    
            ORM---对象关系映射
    
           
    
                class Book(model.Model):
    
                    title=models.CharFiled(max_length=32)
    
     
    
                   
    
                create table book (
    
                     title varchar(32)         
    
                )
    
               
    
               
    
                类名        ------表名
    
                类属性      ------表字段
    
                类实例对象  ------表记录
    
               
    
           
    
               
    
       
    
            单表记录操作:
    
                Book
    
                    id    title
    
                    1     python
    
                    2     java
    
                添加记录:
    
                   # 方式1:
    
                   # obj新添加记录对象
    
                   obj=Book.objects.create(title="python")
    
                   # 方式2:
    
                   obj=Book(title="java")
    
                   obj.save()
    
     
    
                查询记录API(QuerySet):
    
               
    
                    <1> all():                 查询所有结果
    
     
    
                    <2> filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
    
                     
    
                    <3> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
    
                                               如果符合筛选条件的对象超过一个或者没有都会抛出错误。
    
                    <5> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
    
                     
    
                    <4> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
    
                                               model的实例化对象,而是一个可迭代的字典序列
    
                     
    
                    <9> values_list(*field):      它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    
                     
    
                    <6> order_by(*field):      对查询结果排序
    
                     
    
                    <7> reverse():             对查询结果反向排序
    
                     
    
                    <8> distinct():            从返回结果中剔除重复纪录
    
                     
    
                    <10> count():              返回数据库中匹配查询(QuerySet)的对象数量。
    
                     
    
                    <11> first():              返回第一条记录
    
                     
    
                    <12> last():               返回最后一条记录
    
                     
    
                    <13> exists():            如果QuerySet包含数据,就返回True,否则返回False
    
                   
    
                   
    
                    模糊查询: __
    
                   
    
                   
    
                   
    
                删除记录
    
                    Book.objects.filter(price=123,title="python").delete()
    
     
    
                更新记录:
    
                    Book.objects.filter(price=123,title="python").update(title="python123")
    
       
    
        mysql表关系
    
       
    
        一对多关系:关联字段
    
        多对多关系:创建关系表
    
       
    
        Book
    
           title=...
    
           publish=Foreignkey(to="Publish",to_field="")
    
           authors=
    
        Publish
    
           name=....
    
          
    
        Author
    
           name=....
    
       
    
        Book2Author
    
       
    
       
    
     
    课堂笔记

    1.2 MTV模型的含义

    Django的MTV分别代表:

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

      Template(模板):放所有的html文件,负责如何把页面展示给用户

               模板语法:目的是将白变量(数据库的内容)如何巧妙的嵌入到html页面中

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

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

     

    1.3 Django基本命令

    1.3.1 下载Django:

    pip3 install django

    1.4 创建一个django project

    创建一个Django项目分两种方式创建:

    1.4.1 第一种方法使用pycharm软件创建

    文件——新建项目——切到Django

     

    创建成功后会自动生成这样一个工程。目录结构如下:

     

    1.5 第二种命令行创建

    1.5.1 创建一个Django对象

    django-admin.py  startproject   项目名称
    
    django-admin startproject mysite

    创建成功后会生成这样一个工程。目录结构如下:

     

    • manage.py------启动文件 (Django项目里面的工具,通过它可以调用Django shell的数目和数据库等)
    • settings.py------包含了项目的一些设置,包括数据库信息、调试标志以及其他一些工作的变量。
    • urls.py-----------路径与视图函数的映射关系

    1.5.2 在mysite目录下创建应用

    python3 manage.py startapp blog(应用名称)

    创建成功后会生成这样一个工程。目录结构如下:

     

    1.5.3 启动django项目

    python3 manage.py runserver 8080

    这样我们的django就启动起来了!当我们访问:http://127.0.0.1:8080/时就可以看到:

     

    1.6 创建表命令

    1.6.1 同步更改数据库表或字段

    '''
    
        python3 manage.py syncdb
    
        
    
        注意:Django 1.7.1 及以上的版本需要用以下命令
    
        python3 manage.py makemigrations
    
        python3 manage.py migrate   
    
    '''

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

    1.6.2 清空数据库

    python3 manage.py flush

    此命令会询问是 yes 还是 no, 选择 yes 会把数据全部清空掉,只留下空表。

    1.6.3 创建超级管理员

    '''
    
        python3 manage.py createsuperuser
    
        
    
        # 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填
    
        
    
        # 修改 用户密码可以用:
    
        python3 manage.py changepassword username
    
       
    
    '''

    1.6.4 Django 项目环境终端

    python3 manage.py shell

    这个命令和 直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据的测试非常方便。

    1.6.5 Django 项目环境终端

    python3 manage.py dbshell

    Django 会自动进入在settings.py中设置的数据库,如果是 MySQL 或 postgreSQL,会要求输入数据库用户密码。

    在这个终端可以执行数据库的SQL语句。如果您对SQL比较熟悉,可能喜欢这种方式。

    1.6.6 更多命令

    python3 manage.py                  #########切换到项目目录下

    查看所有的命令,忘记子名称的时候特别有用。

    1.6.7 静态文件配置

    概述:
    
     
    
         静态文件交由Web服务器处理,Django本身不处理静态文件。简单的处理逻辑如下(以nginx为例):
    
     
    
                  URI请求-----> 按照Web服务器里面的配置规则先处理,以nginx为例,主要求配置在nginx.
    
                                 conf里的location
    
     
    
                             |---------->如果是静态文件,则由nginx直接处理
    
     
    
                             |---------->如果不是则交由Django处理,Django根据urls.py里面的规则进行匹配
    
     
    
        以上是部署到Web服务器后的处理方式,为了便于开发,Django提供了在开发环境的对静态文件的处理机制,方法是这样:
    
     
    概述

    static配置:

    STATIC主要指的是如css,js,images这样文件:

    STATIC_URL = '/static/'      # 别名
    
    STATICFILES_DIRS = (
    
                os.path.join(BASE_DIR,"static"),  #实际名 ,即实际文件夹的名字
    
            )
    
     
    
    '''
    
     
    
    注意点1:
    
     django对引用名和实际名进行映射,引用时,只能按照引用名来,不能按实际名去找
    
            <script src="/statics/jquery-3.1.1.js"></script>
    
            ------error-----不能直接用,必须用STATIC_URL = '/static/':
    
            <script src="/static/jquery-3.1.1.js"></script>
    
     
    
    注意点2:
    
     STATICFILES_DIRS = (
    
        ("app01",os.path.join(BASE_DIR, "app01/statics")),
    
            )
    
     
    
     <script src="/static/app01/jquery.js"></script>
    
     
    
    '''
    View Code

    have a try

    http://127.0.0.1:8000/static/jquery.js

    media配置:

    # in settings:
    
     
    
    MEDIA_URL="/media/"
    
    MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media","upload")
    
     
    
    # in urls:
    
    from django.views.static import serve
    
    url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
    View Code

    have a try:

    http://127.0.0.1:8000/media/1.png
    '''
    
            静态文件的处理又包括STATIC和MEDIA两类,这往往容易混淆,在Django里面是这样定义的:
    
           
    
            MEDIA:指用户上传的文件,比如在Model里面的FileFIeld,ImageField上传的文件。如果你定义
    
           
    
            MEDIA_ROOT=c:	empmedia,那么File=models.FileField(upload_to="abc/")#,上传的文件就会被保存到c:	empmediaabc
    
     
    
            eg:
    
                class blog(models.Model):
    
                       Title=models.charField(max_length=64)
    
                       Photo=models.ImageField(upload_to="photo")
    
              上传的图片就上传到c:	empmediaphoto,而在模板中要显示该文件,则在这样写
    
              在settings里面设置的MEDIA_ROOT必须是本地路径的绝对路径,一般是这样写:
    
                     BASE_DIR= os.path.abspath(os.path.dirname(__file__))
    
                     MEDIA_ROOT=os.path.join(BASE_DIR,'media/').replace('\','/')
    
     
    
            MEDIA_URL是指从浏览器访问时的地址前缀,举个例子:
    
                MEDIA_ROOT=c:	empmediaphoto
    
                MEDIA_URL="/data/"
    
            在开发阶段,media的处理由django处理:
    
     
    
               访问http://localhost/data/abc/a.png就是访问c:	empmediaphotoabca.png
    
     
    
               在模板里面这样写<img src="/media/abc/a.png">
    
     
    
               在部署阶段最大的不同在于你必须让web服务器来处理media文件,因此你必须在web服务器中配置,
    
               以便能让web服务器能访问media文件
    
               以nginx为例,可以在nginx.conf里面这样:
    
     
    
                     location ~/media/{
    
                           root/temp/
    
                           break;
    
                        }
    
     
    
               具体可以参考如何在nginx部署django的资料。
    
              
    
              
    
               '''
    
     
    View Code

    第2章 视图层之路由配置系统(views)

    URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

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

    2.1 URLconf的正则字符串参数

    2.1.1 简单配置

    ######项目cms中的urls.py中的内容
    
    from django.conf.urls import url
    
     
    
    from . import views
    
     
    
    urlpatterns = [
    
        url(r'^articles/2003/$', views.special_case_2003),
    
        url(r'^articles/([0-9]{4})/$', views.year_archive),
    
        url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
    
    ]
    
     
    项目cms中的urls.py中的内容
    #############说明
    
    '''
    
        NOTE:
    
        1 一旦匹配成功则不再继续
    
        2 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
    
        3 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
    
        4 每个正则表达式前面的'r' 是可选的但是建议加上。
    
     
    
    一些请求的例子:
    
     
    
        /articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。
    
        /articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。
    
        /articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数
    
                           views.month_archive(request, '2005', '03')。
    
        '''
    说明
    #设置项是否开启URL访问地址后面不为/跳转至带有/的路径
    
    APPEND_SLASH=True

    2.1.2 无名分组和有名分组(named group)

    上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。

    在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。

    下面是以上URLconf 使用命名组的重写:

    from app02 import views
    
    from django.conf.urls import url
    
     
    
    urlpatterns = [
    
      #无名分组
    
        url(r'^article/d{4}', views.year) ,
    
     
    
        url(r'^article/(d{4})$', views.year2),
    
        如果有多个匹配一样的时候,谁放在上面就匹配谁,上面的就会把下面的覆盖了
    
        正则加上括号,就是分组,会把分组的内容作为year2函数的参数传进去
    
        url(r'^article/(d{4})/(d{2})$', views.year_month),
    
     
    
        # 有名分组(就是给分组起个名字,这样定义的好处就是按照关键字参数去传参了,指名道姓的方式)
    
        url(r'^article/(?P<year>d{4})/(?P<month>d{2})$', views.year_month_hasname)
    
    ]
    
     
    View Code

    这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:

    /articles/2005/03/   
    
    请求将调用views.month_archive(request, year='2005', month='03')函数
    
    /articles/2003/03/03/
    
    请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

    在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;有些开发人员认为命名组语法丑陋而繁琐。

    2.1.3 URLconf 在什么上查找

    URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

    例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。

    在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。

    URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。

    2.1.4 捕获的参数永远是字符串

    每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

    views.year_archive() 的year 参数将是一个字符串

    2.1.5 指定视图参数的默认值

    有一个方便的小技巧是指定视图参数的默认值。 下面是一个URLconf 和视图的示例:

    # URLconf
    
    from django.conf.urls import url
    
     
    
    from . import views
    
     
    
    urlpatterns = [
    
        url(r'^blog/$', views.page),
    
        url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
    
    ]
    
     
    
    # View (in blog/views.py)
    
    def page(request, num="1"):
    
     
    
        ...
    View Code

    在上面的例子中,两个URL模式指向同一个视图views.page —— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,page() 函数将使用num参数的默认值"1"。如果第二个模式匹配,page() 将使用正则表达式捕获的num 值。

    2.1.6 Including other URLconfs

    #At any point, your urlpatterns can “include” other URLconf modules. This
    
    #essentially “roots” a set of URLs below other ones.
    
     
    
    #For example, here’s an excerpt of the URLconf for the Django website itself.
    
    #It includes a number of other URLconfs:
    
     
    
     
    
    from django.conf.urls import include, url
    
     
    
    urlpatterns = [
    
       url(r'^admin/', admin.site.urls),
    
       url(r'^blog/', include('blog.urls')),
    
    ]
    
     
    View Code

    2.2 传递额外的选项给视图函数(了解)

    URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

    django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

    例如:

    from django.conf.urls import url
    
    from . import views
    
     
    
    urlpatterns = [
    
        url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
    
    ]

    在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。

    这个技术在Syndication 框架中使用,来传递元数据和选项给视图。

    2.3 URL 的反向解析

    在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。

    人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

    换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。

    获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。

    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

    l  根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。

    l  根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

    第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。

    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

    l  在模板中:使用url 模板标签。

    l  在Python 代码中:使用django.core.urlresolvers.reverse() 函数。

    l  在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

    例子:

    考虑下面的URLconf:

    from django.conf.urls import url
    
     
    
    from . import views
    
     
    
    urlpatterns = [
    
        #...
    
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    
        #...
    
    ]
    
     
    View Code

    根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/。

    你可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    
     
    
    <ul>
    
    {% for yearvar in year_list %}
    
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    
    {% endfor %}
    
    </ul>

    在Python 代码中,这样使用:

    from django.core.urlresolvers import reverse
    
    from django.http import HttpResponseRedirect
    
     
    
    def redirect_to_year(request):
    
        # ...
    
        year = 2006
    
        # ...
    
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
    
     
    View Code

    如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

    在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

    2.4 名称空间(Namespace)

    命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

    由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回

    我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

    project.urls:

    urlpatterns = [
    
        url(r'^admin/', admin.site.urls),
    
        url(r'^app01/', include("app01.urls",namespace="app01")),
    
        url(r'^app02/', include("app02.urls",namespace="app02")),
    
    ]
    View Code

    app01.urls:

    urlpatterns = [
    
        url(r'^index/', index,name="index"),
    
    ]

    app02.urls:

    urlpatterns = [
    
        url(r'^index/', index,name="index"),
    
    ]

    app01.views 

    from django.core.urlresolvers import reverse
    
     
    
    def index(request):
    
     
    
        return  HttpResponse(reverse("app01:index"))
    
    app02.views
    
    from django.core.urlresolvers import reverse
    
     
    
    def index(request):
    
     
    
        return  HttpResponse(reverse("app02:index"))
    View Code

    2.5 CBV

    url(r'^login.html$', views.Login.as_view()),
    
     
    
    ============================
    
    from django.views import View
    
    class Login(View):
    
        
    
        def dispatch(self, request, *args, **kwargs):
    
            print('before')
    
            obj = super(Login,self).dispatch(request, *args, **kwargs)
    
            print('after')
    
            return obj
    
     
    
        def get(self,request):
    
           
    
            return render(request,'login.html')
    
     
    
        def post(self,request):
    
            print(request.POST.get('user'))
    
            return HttpResponse('Login.post')
    View Code

    第3章 视图层之视图函数(views)

    一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

    3.1 一个简单的视图

    3.1.1 实例一

    下面是一个返回当前日期和时间作为HTML文档的视图:

    from django.http import HttpResponse
    
    import datetime
    
     
    
    def current_datetime(request):
    
        now = datetime.datetime.now()
    
        html = "<html><body>It is now %s.</body></html>" % now
    
        return HttpResponse(html)
    
     
    View Code

    让我们逐行阅读上面的代码:

    l  首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。

    l  接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request。

    l  注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。

    l  这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

     

    3.1.2 实例二

    ######################views.py###############################
    
    from django.shortcuts import render,HttpResponse
    
     
    
    # Create your views here.
    
    def year(request):  # request参数请求所有的参数,这个参数一定要有
    
        return HttpResponse("ok")  #每一个视图函数必须有return
    
    def year2(request,year):
    
        print(year)
    
        return HttpResponse("hello")   #返回的一定是一个字符串,如果你想return纯字符串,就用HttpResponse方法
    
    def year_month(request,year,month):
    
        print(year,month)
    
        # 返回的是匹配的年和月拼接的结果
    
        return HttpResponse(year+month)   #
    
    def year_month_hasname(request,month,year):
    
        # return HttpResponse("ok")
    
        print(year,month)
    
        return HttpResponse("month是:%s,year是:%s"%(month,year))
    
     
    views.py

    注意:视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

    3.2 HttpRequest对象的属性和方法

    3.2.1 HttpRequest对象的属性

    属性:
    
      django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。
    
       除了特殊说明的之外,其他均为只读的。
    
     
    
    '''
    
     
    
    1.HttpRequest.body
    
     
    
      一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
    
     
    
      但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
    
     
    
      另外,我们还可以用 python 的类文件方法去操作它,详情参考 HttpRequest.read() 。
    
     
    
     
    
     
    
    2.HttpRequest.path
    
     
    
      一个字符串,表示请求的路径组件(不含域名)。
    
     
    
      例如:"/music/bands/the_beatles/"
    
     
    
     
    
     
    
    3.HttpRequest.method
    
     
    
      一个字符串,表示请求使用的HTTP 方法。必须使用大写。
    
     
    
      例如:"GET"、"POST"
    
     
    
     
    
     
    
    4.HttpRequest.encoding
    
     
    
      一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
    
       这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
    
       接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
    
       如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
    
     
    
     
    
     
    
    5.HttpRequest.GET
    
     
    
      一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
    
     
    
     
    
     
    
    6.HttpRequest.POST
    
     
    
      一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
    
     
    
      POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
    
       因此,不应该使用 if request.POST  来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
    
     
    
      另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
    
     
    
     
    
     
    
    7.HttpRequest.REQUEST
    
     
    
      一个类似于字典的对象,它首先搜索POST,然后搜索GET,主要是为了方便。灵感来自于PHP 的 $_REQUEST。
    
     
    
      例如,如果 GET = {"name": "john"}  而 POST = {"age": '34'} , REQUEST["name"]  将等于"john", REQUEST["age"]  将等于"34"。
    
     
    
      强烈建议使用 GET 和 POST 而不要用REQUEST,因为它们更加明确。
    
     
    
     
    
     
    
    8.HttpRequest.COOKIES
    
     
    
      一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
    
     
    
     
    
     
    
    9.HttpRequest.FILES
    
     
    
      一个类似于字典的对象,包含所有的上传文件信息。
    
       FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
    
     
    
      注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
    
       包含数据。否则,FILES 将为一个空的类似于字典的对象。
    
     
    
     
    
     
    
    10.HttpRequest.META
    
     
    
       一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
    
     
    
        CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
    
        CONTENT_TYPE —— 请求的正文的MIME 类型。
    
        HTTP_ACCEPT —— 响应可接收的Content-Type。
    
        HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
    
        HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
    
        HTTP_HOST —— 客服端发送的HTTP Host 头部。
    
        HTTP_REFERER —— Referring 页面。
    
        HTTP_USER_AGENT —— 客户端的user-agent 字符串。
    
        QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
    
        REMOTE_ADDR —— 客户端的IP 地址。
    
        REMOTE_HOST —— 客户端的主机名。
    
        REMOTE_USER —— 服务器认证后的用户。
    
        REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
    
        SERVER_NAME —— 服务器的主机名。
    
        SERVER_PORT —— 服务器的端口(是一个字符串)。
    
       从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
    
        都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_  前缀。
    
        所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
    
     
    
     
    
    11.HttpRequest.user
    
     
    
      一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
    
     
    
      如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
    
     
    
        例如:
    
     
    
        if request.user.is_authenticated():
    
            # Do something for logged-in users.
    
        else:
    
            # Do something for anonymous users.
    
        
    
     
    
           user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
    
     
    
         -------------------------------------------------------------------------------------
    
     
    
        匿名用户
    
        class models.AnonymousUser
    
     
    
        django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
    
     
    
        id 永远为None。
    
        username 永远为空字符串。
    
        get_username() 永远返回空字符串。
    
        is_staff 和 is_superuser 永远为False。
    
        is_active 永远为 False。
    
        groups 和 user_permissions 永远为空。
    
        is_anonymous() 返回True 而不是False。
    
        is_authenticated() 返回False 而不是True。
    
        set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
    
        New in Django 1.8:
    
        新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
    
     
    
     
    
     
    
    12.HttpRequest.session
    
     
    
       一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
    
        完整的细节参见会话的文档。
    
     
    
     
    
    13.HttpRequest.resolver_match
    
     
    
      一个 ResolverMatch 的实例,表示解析后的URL。这个属性只有在 URL 解析方法之后才设置,这意味着它在所有的视图中可以访问,
    
       但是在 URL 解析发生之前执行的中间件方法中不可以访问(比如process_request,但你可以使用 process_view 代替)。
    
    '''
    
     
    View Code

    3.2.2 HttpRequest对象的方法

    '''
    
    1.HttpRequest.get_host()
    
     
    
      根据从HTTP_X_FORWARDED_HOST(如果打开 USE_X_FORWARDED_HOST,默认为False)和 HTTP_HOST 头部信息返回请求的原始主机。   如果这两个头部没有提供相应的值,则使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有详细描述。
    
     
    
      USE_X_FORWARDED_HOST:一个布尔值,用于指定是否优先使用 X-Forwarded-Host 首部,仅在代理设置了该首部的情况下,才可以被使用。
    
     
    
      例如:"127.0.0.1:8000"
    
     
    
      注意:当主机位于多个代理后面时,get_host() 方法将会失败。除非使用中间件重写代理的首部。
    
     
    
     
    
     
    
    2.HttpRequest.get_full_path()
    
     
    
      返回 path,如果可以将加上查询字符串。
    
     
    
      例如:"/music/bands/the_beatles/?print=true"
    
     
    
     
    
     
    
    3.HttpRequest.build_absolute_uri(location)
    
     
    
      返回location 的绝对URI。如果location 没有提供,则使用request.get_full_path()的返回值。
    
     
    
      如果URI 已经是一个绝对的URI,将不会修改。否则,使用请求中的服务器相关的变量构建绝对URI。
    
     
    
      例如:"http://example.com/music/bands/the_beatles/?print=true"
    
     
    
     
    
     
    
    4.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    
     
    
      返回签名过的Cookie 对应的值,如果签名不再合法则返回django.core.signing.BadSignature。
    
     
    
      如果提供 default 参数,将不会引发异常并返回 default 的值。
    
     
    
      可选参数salt 可以用来对安全密钥强力攻击提供额外的保护。max_age 参数用于检查Cookie 对应的时间戳以确保Cookie 的时间不会超过max_age 秒。
    
     
    
            复制代码
    
            >>> request.get_signed_cookie('name')
    
            'Tony'
    
            >>> request.get_signed_cookie('name', salt='name-salt')
    
            'Tony' # 假设在设置cookie的时候使用的是相同的salt
    
            >>> request.get_signed_cookie('non-existing-cookie')
    
            ...
    
            KeyError: 'non-existing-cookie'    # 没有相应的键时触发异常
    
            >>> request.get_signed_cookie('non-existing-cookie', False)
    
            False
    
            >>> request.get_signed_cookie('cookie-that-was-tampered-with')
    
            ...
    
            BadSignature: ...   
    
            >>> request.get_signed_cookie('name', max_age=60)
    
            ...
    
            SignatureExpired: Signature age 1677.3839159 > 60 seconds
    
            >>> request.get_signed_cookie('name', False, max_age=60)
    
            False
    
            复制代码
    
            
    
     
    
     
    
     
    
    5.HttpRequest.is_secure()
    
     
    
      如果请求时是安全的,则返回True;即请求通是过 HTTPS 发起的。
    
     
    
     
    
     
    
    6.HttpRequest.is_ajax()
    
     
    
      如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
    
     
    
      大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
    
     
    
      如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,    你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
    
     
    
     
    
     
    
    7.HttpRequest.read(size=None)
    
     
    
      像文件一样读取请求报文的内容主体,同样的,还有以下方法可用。
    
     
    
      HttpRequest.readline()
    
     
    
      HttpRequest.readlines()
    
     
    
      HttpRequest.xreadlines()
    
     
    
      其行为和文件操作中的一样。
    
     
    
      HttpRequest.__iter__():说明可以使用 for 的方式迭代文件的每一行。'''
    
     
    View Code

    注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:

    request.POST.getlist("hobby")

    3.3 render 函数

    render(request, template_name[, context])

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

    参数:
    
         request: 用于生成响应的请求对象。
    
         template_name:要使用的模板的完整名称,可选的参数
    
         context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
    
         content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。
    
         status:响应的状态码。默认为200。

    3.4 redirect 函数

    参数可以是:

    l  一个模型:将调用模型的get_absolute_url() 函数

    l  一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称

    l  一个绝对的或相对的URL,将原封不动的作为重定向的位置。

    默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。

    示例:

    你可以用多种方式使用redirect() 函数。

    3.4.1 传递一个对象

    将调用get_absolute_url() 方法来获取重定向的URL:

    from django.shortcuts import redirect
    
     
    
    def my_view(request):
    
        ...
    
        object = MyModel.objects.get(...)
    
        return redirect(object)
    View Code

    3.4.2 传递一个视图的名称

    可以带有位置参数和关键字参数;将使用reverse() 方法反向解析URL: 

    def my_view(request):
    
        ...
    
        return redirect('some-view-name', foo='bar')

    3.4.3 传递要重定向的一个硬编码的URL

    def my_view(request):
    
        ...
    
        return redirect('/some/url/')

    也可以是一个完整的URL:

    def my_view(request):
    
        ...
    
        return redirect('http://example.com/')

    默认情况下,redirect() 返回一个临时重定向。以上所有的形式都接收一个permanent 参数;如果设置为True,将返回一个永久的重定向:

    def my_view(request):
    
        ...
    
        object = MyModel.objects.get(...)
    
        return redirect(object, permanent=True)  

    3.4.4 跳转(重定向)应用

    -----------------------------------url.py
    
     
    
     url(r"login",   views.login),
    
     url(r"yuan_back",   views.yuan_back),
    
     
    
    -----------------------------------views.py
    
    def login(req):
    
        if req.method=="POST":
    
            if 1:
    
                # return redirect("/yuan_back/")
    
                name="yuanhao"
    
     
    
                return render(req,"my backend.html",locals())
    
     
    
        return render(req,"login.html",locals())
    
     
    
     
    
    def yuan_back(req):
    
     
    
        name="苑昊"
    
     
    
        return render(req,"my backend.html",locals())
    
     
    
    -----------------------------------login.html
    
     
    
    <form action="/login/" method="post">
    
        <p>姓名<input type="text" name="username"></p>
    
        <p>性别<input type="text" name="sex"></p>
    
        <p>邮箱<input type="text" name="email"></p>
    
        <p><input type="submit" value="submit"></p>
    
    </form>
    
    -----------------------------------my backend.html
    
    <h1>用户{{ name }}你好</h1>
    
     
    View Code

    redirect关键点:两次请求过程,掌握流程。

    注意:render和redirect的区别:

    1、 if 页面需要模板语言渲染,需要的将数据库的数据加载到html,那么render方法则不会显示这一部分。

    2、 the most important: url没有跳转到/yuan_back/,而是还在/login/,所以当刷新后又得重新登录。

    第4章 模板层(template)

    python的模板:HTML代码+模板语法

    模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签

    def current_time(req):
    
        # ================================原始的视图函数
    
        # import datetime
    
        # now=datetime.datetime.now()
    
        # html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now
    
     
    
     
    
        # ================================django模板修改的视图函数
    
        # from django.template import Template,Context
    
        # now=datetime.datetime.now()
    
        # t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
    
        # #t=get_template('current_datetime.html')
    
        # c=Context({'current_date':str(now)})
    
        # html=t.render(c)
    
        #
    
        # return HttpResponse(html)
    
     
    
     
    
        #另一种写法(推荐)
    
        import datetime
    
        now=datetime.datetime.now()
    
        return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
    View Code

    模板语法:目的是将变量(数据库的内容)如何巧妙的嵌入到html页面中(就不用之前我们用的字符串拼接了)

    在 Django 模板中遍历复杂数据结构的关键是句点字符  .

    语法:

    {{var_name}} 

    4.1 示例

    #####################view.py##############################
    
    def index(request):
    
        import datetime
    
        s="hello"
    
        l=[111,222,333]    # 列表
    
        dic={"name":"yuan","age":18}  # 字典
    
        date = datetime.date(1993, 5, 2)   # 日期对象
    
     
    
        class Person(object):
    
            def __init__(self,name):
    
                self.name=name
    
     
    
        person_yuan=Person("yuan")  # 自定义类对象
    
        person_egon=Person("egon")
    
        person_alex=Person("alex")
    
     
    
        person_list=[person_yuan,person_egon,person_alex]
    
     
    
     
    
        return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list}) 
    view.py 

    template

    <h4>{{s}}</h4>
    
    <h4>列表:{{ l.0 }}</h4>
    
    <h4>列表:{{ l.2 }}</h4>
    
    <h4>字典:{{ dic.name }}</h4>
    
    <h4>日期:{{ date.year }}</h4>
    
    <h4>类对象列表:{{ person_list.0.name }}</h4>
    View Code

    注意:句点符也可以用来引用对象的方法(无参数方法)。

    <h4>字典:{{ dic.name.upper }}</h4>

    4.2 小练习

    需求:当用户输入一个URL:  http://127.0.0.1:8080/timer,就返回给用户一个当前的时间

    基本流程

    4.2.1 对urls进行一个设置

     

    4.2.2 views.py

     

    4.2.3 在template里创建一个timer.html页面

     

    第5章 Django框架之第二篇反向解析

    5.1 知识点回顾

    5.1.1 MTV模型

      model:模型,和数据库相关的

      template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中)。

      views:视图函数

    另加urls:url路径与视图函数的映射关系,,可以不是一一对应的。

    5.1.2 相关的一些命令

      创建一个Django项目:django-admin  startproject  projectname

      创建一个项目下的应用:python3  manage.py  startapp  appname

      运行:python3  manage.py  runserver  IP PORT

    5.1.3 url配置(URLconf)urls.py

      功能:建立起url与视图函数的映射关系

      url(正则表达式(规则),视图函数,[可选参数])

       url:http://127.0.0.1:8080/blog/articles/2003/05?a=1&b=2

        匹配字符串:用户输入的url对应的路径    /blog/articles/2003/05

    注意:

      (1)出现覆盖现象的情况,也就是匹配规则冲突的时候,匹配第一个url

      (2)无名分组:url(r'^articles/(d{4})/(d{2})$', views.year_month),  # year(requset,1990,12)   按位置传参数

      (3)有名分组:url(r'^articles/(?P<year>d{4})/(?P<month>d{2})$', views.year_month),  # year(requset,year=1990,month=12)   按位置传参数

      (4)url分发:url(r'^blog/',include('blog.urls'))

    5.2 视图函数的补充

    5.2.1 视图函数

    1、视图函数:一定是要包含两个对象的(render源码里面有HttpResponse对象)

           request对象:-----》所有的请求信息

           HttpResponse:-----》响应的内容(字符串)

    5.2.2 get请求发送数据

    2、get请求发送数据:http://127.0.0.1:8000/login.html?user=asd&pwd=asd

    重点:request里包含哪些数据
    1、request.GET: GET请求的数据,如果没有数据是一个空字典    {}
    2、request.POST:POST请求的数据 ,如果没有数据是一个空字典  {}
    3、request.method:请求方式:GET 或 POST
    4、请求某个键下多个值时:request.POST.getlist("hobby")
    5、 request.path : 请求路径(只会拿到路径,不拿数据)    
    
     请求url:http://127.0.0.1:8000/index.html/23?a=1
     path:request.path:/index.html/23
    6、request.get_full_path():请求路径(路径和数据都会拿到)
      请求url:http://127.0.0.1:8000/index.html/23?a=1
      request.get_full_path():/index.html/23?a=1

    5.3 render函数和redirect函数的区别

    render:只会返回页面内容,但是未发送第二次请求

    redirect:发挥了第二次请求,url更新

     

    具体实例说明如下:

    5.3.1 render:

     

    5.3.2 redirect:

     

    5.4 反向解析

    5.4.1 介绍

    在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。

    人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

    换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。

    获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。

    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

    l  根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。

    l  根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

    第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。

    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

    l  在模板中:使用url 模板标签。

    l  在Python 代码中:使用django.core.urlresolvers.reverse() 函数。

    l  在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

    5.4.2 例子:

    考虑下面的URLconf:

    from django.conf.urls import url
    
     
    
    from . import views
    
     
    
    urlpatterns = [
    
        #...
    
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    
        #...
    
    ]
    
     
    View Code

    根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/。

    你可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    
     
    
    <ul>
    
    {% for yearvar in year_list %}
    
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    
    {% endfor %}
    
    </ul>
    
     
    View Code

    在Python 代码中,这样使用:

    from django.core.urlresolvers import reverse
    
    from django.http import HttpResponseRedirect
    
     
    
    def redirect_to_year(request):
    
        # ...
    
        year = 2006
    
        # ...
    
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
    View Code

    如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

    在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

    5.4.3 例子分析

    例子中:

    分析:想我们一开始写的硬编码,也就是吧action要跳转的路径写死了。但是像淘宝,天猫等都会经常更新新东西,,那么你的页面上的url路径也会时不时的变化。但是如果有特别多的商品,那么你就得去服务端一个一个的改,这样显得很麻烦,那么有没有一种机制帮我们解决问题呢?那就按照我下面的办法解决。就把url路径写活了。

    1、首先给url起一个别名。

    2、然后在login.html中写上{%  url ‘别名’’  %}    ,如果在页面中点击查看元素,它会变成login.html,,,当然我的是分发了,,就会变成test/login.html

    3、这样你就可以修改你的正则了,,因为他是按照别名走的,不会影响。

     

    urls.py

     

    login.html

     

    查看元素的结果:

     

    这样的好处是:无论你怎么改你要匹配的url,只要你写上了别名。在html实现了模板语法,就会去找别名对应的那个url,以后不管你怎么改url都没事,就写活了,就不像一开始写的硬编码了。

    第6章 Django框架之第三篇模板语法

    6.1 什么是模板?

    只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板。

    6.2 模板语法分类

    6.2.1 模板语法之变量:语法为 {{ }}:

    在 Django 模板中遍历复杂数据结构的关键是句点字符  .(也就是点)

    views.py

    def index(request):
    
        name = "hello haiyan"
    
        i = 200
    
        l = [11,22,33,44,55]
    
        d = {"name":"haiyan","age":20}
    
     
    
        class People(object): #继承元类
    
            def __init__(self,name,age):
    
                self.name = name
    
                self.age = age
    
            def __str__(self):
    
                return self.name+str(self.age)
    
            def dream(self):
    
                return "你有梦想吗?"
    
        #实例化
    
        person_egon = People("egon",10)
    
        person_dada = People("dada",34)
    
        person_susan = People("susan",34)
    
        person_list = [person_dada,person_egon,person_susan]
    
     
    
        return render(request,"index.html",
    
                        {
    
                            "name":name,
    
                            "i":i,
    
                            "l":l,
    
                            "d":d,  #键对应的是模板里的名字。值对应的是上面定义的变量
    
                            "person_egon":person_egon,
    
                            "person_dada":person_dada,
    
                            "person_list":person_list,
    
                        }
    
                  )
    
        # return render(request,"index.html",locals())
    
        #用locals()可以不用写上面的render了。不过用locals(),views里面用什么名。模板里面就得用什么名
    
        # locals()局部的:用了locals就相当于都得按照上面的那样
    
     
    View Code

    template/index.html

    <h4>变量{{ z }}:深度查询</h4><hr>
    
    <h3>{{ name }}</h3>
    
    <p>{{ i }}</p>
    
    <p>{{ l }}</p>
    
    <p>{{ d }}</p>
    
    <p>{{ l.0 }}------》取单个值可通过句点符(也就是点)</p>
    
    <p>{{ l.4 }}</p>
    
    <p>{{ d.name }}</p>
    
    <p>{{ d.age }}-----》字典也可以根据句点符取值,一个点就搞定了。
    
    然而在前端页面中是看不到你的模板语法的,当你点击审查元素的
    
    时候,你就会发现,偷偷的换过来了</p>
    
    <p>{{ person_dada.name }}</p>
    
    <p>{{ person_egon.age }}</p>
    
    <p>{{ person_dada.dream }}</p>  <!-- .方法的时候,注意当前的dream方法是没有参数的-->
    
    <p>{{ person_list.2 }}</p>  <!--单个取值-->
    
    <p>{{ person_list.1.name }}</p>
    
    <!-- 那怎么让对象变成字符串呢?在index视图函数里里面再加上一个__str__内置方法-->
    
    <!--__str__是对象字符串的改变-->
    
     
    View Code

    注意:句点符也可以用来引用对象的方法(无参数方法)。

    <h4>字典:{{ dic.name.upper }}</h4>

    6.2.2 模板语法之标签:语法为 {% tag  %}:

    标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。

    一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。

    1for标签(注:循环序号可以通过{{forloop}}显示)

    <h3>循环取值1</h3><hr>
    
    {% for item in person_list %}
    
        <p>{{ item.name }},{{ item.age }}</p>
    
    {% endfor %}
    
     
    
    <h3>循环取值2:倒序</h3><hr>
    
    {% for item in person_list reversed %}
    
        <!--序号从1开始-->
    
        <p>{{ forloop.counter }}----->{{ item.name }},{{ item.age }}</p>
    
        <!--序号从0开始--><p>{{ forloop.counter0 }}----->{{ item.name }},{{ item.age }}</p><!-- 序号倒序 --><p>{{ forloop.revcounter }}----->{{ item.name }},{{ item.age }}</p>
    
    {% endfor %}
    
     
    
    <h3>循环取值3:字典</h3><hr>
    
    {% for k,v in d.items %}
    
        <p>{{ k }},{{ v}}</p>
    
    {% endfor %}
    
     
    View Code

    2、for....empty for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。

    {% for person in person_list %}
    
        <p>{{ person.name }}</p>
    
     
    
    {% empty %}
    
        <p>sorry,no person here</p>
    
    {% endfor %}
    View Code

    3、if标签 :{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

    {% if i > 300 %}
    
        <p>大于{{ i }}</p>
    
    {% elif i == 200  %}
    
        <p>等于{{ i }}</p>
    
    {% else %}
    
        <p>小于{{ i }}</p>
    
    {% endif %}
    View Code

    4、with:使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的

    {% with total=business.employees.count %}
    
        {{ total }} employee{{ total|pluralize }}
    
    {% endwith %}
    
     
    
    <p>{{ person_list.2.name }}</p>
    
    {% with name=person_list.2.name %}
    
        <p>{{ name }}</p>
    
    {% endwith %}
    View Code

    5、csrf_token:这个标签用于跨站请求伪造保护

    提交数据的时候就会做安全机制,当你点击提交的时候会出现一个forbbiddon的错误,就是用setting配置里的scrf做安全机制的,那么我们可以把它给注释了,或者在form表单下面添加一个{% csrf_token %}   ,这才是真正解决的办法,注释不是解决的办法

    <h3>scrf_token</h3><form action="/tag/" method="post">
    
        {% csrf_token %}
    
        <p><input type="text" name="haiyan"></p>
    
        <input type="submit">
    
    </form>
    View Code

    6.2.3 模板语法之过滤器:语法 {{obj|filter__name:param}}

    1、default:如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:

    <p>default过滤器:{{ li|default:"如果显示为空,设置的解释性的内容" }}</p>

    2、length:返回值的长度。它对字符串和列表都起作用。例如:

    {{ value|length }}

    如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。

     

    3、filesizeformat:将值格式化为一个人类可读的文件尺寸(例如 '13 KB''4.1 MB''102 bytes', 等等)。例如:

    {{ value|filesizeformat }}

    如果 value 是 123456789,输出将会是 117.7 MB。  

     

    4、date:如果 value=datetime.datetime.now()

    {{ value|date:"Y-m-d" }}  

    5、slice  :切片

    如果 value="hello world"

    {{ value|slice:"2:-1" }}

    6truncatechars  截断

    如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

    参数:要截断的字符数

    例如:

    <p>截断字符:{{ content|truncatechars:20 }}</p>
    
    <p>截断单词:{{ content|truncatewords:4 }}</p>

    如果content是“I am is haiyan,how are you asd df dfgfdgdg?

    输出结果: 截断字符:I am is haiyan,ho...

    输出结果 :截断单词:I am is haiyan,how ...

    7safe

    Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:

    value="<a href="">点击</a>"
    
     
    
    {{ value|safe}}
    
    <p>{{ label }}</p>  <!--为了安全系统会把标签变成字符串-->
    
    <p>{{ label|safe }}</p>    <!--加上safe,确定你的数据是安全的才能被当成是标签-->

    这里简单介绍一些常用的模板的过滤器,更多详见

    6.2.4 自定义标签和过滤器

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

    2、在app中创建templatetags模块(模块名只能是templatetags)

    3、在templatetags里面创建任意 .py 文件,

    如:my_tags.py

    from django import template
    
    from django.utils.safestring import mark_safe
    
     
    
    register = template.Library()   #register的名字是固定的,不可改变
    
    @register.filter   过滤器
    def multi(x,y):
        return x*y
    
    @register.simple_tag  标签
    def multitag(x,y,z):
        return x*y*z
    
    @register.simple_tag  标签
    def my_input(id,arg):
       result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
       return mark_safe(result)
    View Code

    4、在使用自定义simple_tagfilterhtml文件中导入之前创建的 my_tags.py

    {% load my_tags %} 

    5、使用simple_tagfilter(如何调用

    过滤器: {{ var|filter_name:参数 }} # 参数只能是两个,一个参数是变量var ,一个是参数是后面的那个参数

    标签: {% simple_tag 参数1 参数2 ... %}

    -------------------------------.html
    
    {% load xxx %} 
    
         
    
    # num=12
    
    {{ num|multi:2 }} #24
    
     
    
    {{ num|multi:"[22,333,4444]" }}   相当于复制了,吧[22,333,4444]乘了num遍
    
    {% multitag 2 5 6 %} 参数不限,但不能放在if for语句中 {% simple_tag_multi num 5 %}
    View Code
    自定义过滤器函数的参数只能两个,可以进行逻辑判断
    自定义标签无参数限制,不能进行逻辑判断
    {% if i|multi:5 > 1000 %}   <!-- 判断i*5>1000 -->
    
        <p>大于{{ i }}</p>
    
    {% else %}
    
        <p>大于等于{{ i }}</p>
    
    {% endif %}
    View Code

    第7章 Django框架之模板继承和静态文件配置

    7.1 模板继承

    目的是:减少代码的冗余

    语法:

    {% block classinfo %}
    
     
    
    {% endblock %}

    7.1.1 具体步骤

    1、创建一个base.html文件,
    2、把要显示的页面的内容写在这里面,也就是html要在浏览器显示的内容
    3、在right里面写个盒子
      {% block classinfo %}

      {% endblock %}
    在这里面写个空盒子,以后谁来扩展就在这个盒子里面添加相应的内容就行了

    4、然后再创建一个.html文件,让这个继承base.html文件,
      {% extends "base.html" %}    #必须是在文件的第一行
      在基板里面添加内容
      {% block classinfo %}
        <h2>首页</h2>
        <h2>学生信息</h2>
        <h3>{{ class_id }}班</h3>
      {% endblock%}

    5、也可以写好多盒子,
      在left中写个盒子
        {% block menu %}
          <p>I see you you</p>
        {% endblock %}

    注意:

    盒子里面可以有默认的内容,如果有默认的时候你不扩展就走默认的,如果你扩展了,就替换了,那么不替换直接追加可以嘛?可以的,那就用下面的方式。

    {% block.super %}

    例如:

    {% block menu %}
    
     
    
      {{ block.super }}
    
     
    
      <p>!!!</p>       #先继承父类的,后插入数据
    
     
    
    {% endblock %}
    View Code

    7.1.2 注意项

    1、模板继承围绕两点:继承和扩展
              你有什么继承什么,       
              扩展的是盒子,
    2、模板中设置的盒子越多越好,因为这样你想扩展的时候就容易了。我想扩展就扩展了。不扩展就不扩展了
    3、为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:

    {% block content %}
    
    ...
    
    {% endblock content %}  

    4、如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。

    最后,请注意你并不能在一个模版中定义多个相同名字的 block 标签。这个限制的存在是因为block标签的作用是“双向”的。这个意思是,block标签不仅提供了一个坑去填,它还在 _父模版_中定义了填坑的内容。如果在一个模版中有两个名字一样的 block 标签,模版的父模版将不知道使用哪个block的内容。

    7.2 具体例子说明

    7.2.1 urls.py

    urlpatterns = [
    
        url(r'^admin/', admin.site.urls),
    
        url(r'^text/(d+)', views.text),
    
    ]

    7.2.2 views.py

    from django.shortcuts import render,redirect
    
     
    
    # Create your views here.
    
     
    
    def text(request,class_id):
    
            # 班级变量
    
            print(class_id)  #拿到的是你在路径里输入的几就是几
    
            # 数据库查询
    
            return render(request, "text.html", {"class_id": class_id})
    View Code

    7.2.3 templaite / base.html

    <!DOCTYPE html>
    
    <html lang="en">
    
    <head>
    
        <meta charset="UTF-8">
    
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
        <meta name="viewport" content="width=device-width">
    
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    
        <title>Title</title>
    
        <style>
    
            .right {
    
                height: 400px;
    
                background-color: silver;
    
            }
    
        </style>
    
    </head>
    
    <body>
    
    {#导航条#}
    
    <nav class="navbar navbar-primary navbar-inverse">
    
        <div class="container-fluid">
    
            <!-- Brand and toggle get grouped for better mobile display -->
    
            <div class="navbar-header">
    
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
    
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
    
                    <span class="sr-only">Toggle navigation</span>
    
                    <span class="icon-bar"></span>
    
                    <span class="icon-bar"></span>
    
                    <span class="icon-bar"></span>
    
                </button>
    
                <a class="navbar-brand" href="#">Brand</a>
    
            </div>
    
     
    
            <!-- Collect the nav links, forms, and other content for toggling -->
    
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    
                <ul class="nav navbar-nav">
    
                    <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
    
                    <li><a href="#">Link</a></li>
    
                    <li class="dropdown">
    
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
    
                           aria-expanded="false">Dropdown <span class="caret"></span></a>
    
                        <ul class="dropdown-menu">
    
                            <li><a href="#">Action</a></li>
    
                            <li><a href="#">Another action</a></li>
    
                            <li><a href="#">Something else here</a></li>
    
                            <li role="separator" class="divider"></li>
    
                            <li><a href="#">Separated link</a></li>
    
                            <li role="separator" class="divider"></li>
    
                            <li><a href="#">One more separated link</a></li>
    
                        </ul>
    
                    </li>
    
                </ul>
    
            </div><!-- /.navbar-collapse -->
    
        </div><!-- /.container-fluid -->
    
    </nav>
    
    {#内容#}
    
    <div class="containers">
    
        <div class="row">
    
            <div class="col-md-11 col-lg-offset-1">
    
                {#            左侧#}
    
                <div class="left col-md-3">
    
                    {% block menu %}
    
                        <div class="list-group">
    
                            <a href="#" class="list-group-item active">
    
                                学生班级
    
                            </a>
    
                            <a href="/text/6" class="list-group-item">s6</a>
    
                            <a href="/text/7" class="list-group-item">s7</a>
    
                            <a href="/text/8" class="list-group-item">s8</a>
    
                            <a href="/text/9" class="list-group-item">s9</a>
    
                        </div>
    
                    {% endblock %}
    
                </div>
    
                {#            右侧#}
    
                <div class="right col-md-8">
    
                    {#                定义一个盒子#}
    
                    {% block classinfo %}
    
     
    
                    {% endblock %}
    
                </div>
    
            </div>
    
        </div>
    
    </div>
    
    {#底部#}
    
     
    
    </body>
    
    </html>
    View Code

    7.2.4 template /text.py   继承上面的文件

    {% extends "base.html" %}
    
    
    
    {% block classinfo %}
    
        <h1>学生信息</h1>
    
        <h3>{{ class_id }}班级</h3>
    
    {% endblock %}
    
    
    
    {#追加#}
    
    {% block menu %}
    
        {{ block.super }}
    
        <a href="">学生信息</a>
    
    {% endblock %}
    View Code

    7.3 静态文件配置

    我们自己导入的一些包就叫做静态文件

    1、在全局中先创建一个static的包,

    2、在static里面导入我们的bootstrap,还是jquery等

    3、然后在settings.py中加上一些配置

    STATIC_URL = '/static/'   #这个配置就相当于下面配置的别名,如果这里的名字修改了就按照这里的名字去导入
    
    STATICFILES_DIRS = [
    
        os.path.join(BASE_DIR,"static")  #E:day68static 找到static路径
    
    ]

    4、导入css,js,jquery

    <link rel = "stysheet",href= "/static/index.css/">
    
     
    
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">

    第8章 django之ORM数据库操作

    8.1 ORM介绍

    映射关系:

      表名 --------------------》类名

      字段--------------------》属性

      表记录-----------------》类实例化对象

    ORM的两大功能:

      操作表:

        - 创建表

        - 修改表

        - 删除表

      操作数据行:

        - 增删改查

    ORM利用pymysql第三方工具链接数据库

    Django没办法帮我们创建数据库,只能我们创建完之后告诉它,让django去链接

    8.2 创建表之前的准备工作

    一、自己创建数据库

    二、在settings里面配置mysql数据库链接

      sqlite3------改为mysql

    # 修改django默认的数据库的sqlite3为mysql
    
    DATABASES = {
    
        'default': {
    
                'ENGINE': 'django.db.backends.mysql', #通过这个去链接mysql
    
                'NAME': 'djangotsgl',
    
                'USER':'root',
    
                'PASSWORD':'123456',
    
                'HOST':'localhost',
    
                'PORT':'3306',
    
            }
    
        } 
    
     
    View Code

    这样写上以后django会默认的就去链接数据库,这时你会看到报错了,那么解决的办法就是下面的这样。

    三、app01中的--init--文件

    import pymysql
    
    pymysql.install_as_MySQLdb()

    四、创建数据库表

    models.py

    class Book(models.Model):  #必须要继承的
    
        nid = models.AutoField(primary_key=True)  #自增id(可以不写,默认会有自增id)
    
        title = models.CharField(max_length=32)
    
        publishDdata = models.DateField()  #出版日期
    
        author = models.CharField(max_length=32)
    
        price = models.DecimalField(max_digits=5,decimal_places=2)  #一共5位,保留两位小数
    
     
    View Code

    执行命令创建:(需要记住的!!!) 

    python3 manage.py makemigrations   创建脚本
    
    python3 manage.py migrate   迁移

    8.3 具体例子实现

    8.3.1 model.py

     

    8.3.2 urls.py

     

    8.3.3 views.py

     

    8.3.4 template /index.html

    #######################图片内容具体#######################
    
    <!DOCTYPE html>
    
    <html lang="en">
    
    <head>
    
        <meta charset="UTF-8">
    
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
        <meta name="viewport" content="width=device-width">
    
        <title>Title</title>
    
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    
        <style>
    
            table{
    
                margin-top: 50px;
    
            }
    
        </style>
    
    </head>
    
    <body>
    
    <div class="containers">
    
        <div class="row">
    
            <div class="col-md-9 col-md-offset-2">
    
                <table class="table table-hover">
    
                    <thead>
    
                        <tr>
    
                            <th>编号</th>
    
                            <th>书名</th>
    
                            <th>出版日期</th>
    
                            <th>作者</th>
    
                            <th>价钱</th>
    
                            <th>操作</th>
    
                        </tr>
    
                    </thead>
    
                    <tbody>
    
                    {% for book in book_list %}
    
                        <tr>
    
                                <td>{{ book.nid }}</td>
    
                                <td>{{ book.title }}</td>
    
                                <td>{{ book.publishDdata|date:'Y-m-d' }}</td>
    
                                <td>{{ book.author }}</td>
    
                                <td>{{ book.price }}</td>
    
                                <td>
    
                                    <a href="/del/{{ book.nid }}"><button class="btn btn-danger">删除</button></a>
    
                                    <a href="/edit/{{ book.nid }}"><button class="btn btn-success">编辑</button></a>
    
                                    <a href="/add/"><button class="btn btn-primary">添加</button></a>
    
                                </td>
    
                        </tr>
    
                    {% endfor %}
    
                    </tbody>
    
                </table>
    
            </div>
    
        </div>
    
    </div>
    
    </body>
    
    </html>
    
     
    图片内容具体

    8.4 查看数据库的sql语句

    五、查看数据库的sql语句(加在settings.py)

    查看数据库执行代码
    
    LOGGING = {
    
        'version': 1,
    
        'disable_existing_loggers': False,
    
        'handlers': {
    
            'console':{
    
                'level':'DEBUG',
    
                'class':'logging.StreamHandler',
    
            },
    
        },
    
        'loggers': {
    
            'django.db.backends': {
    
                'handlers': ['console'],
    
                'propagate': True,
    
                'level':'DEBUG',
    
            },
    
        }
    
    }
    View Code

    第9章 Django之ORM数据库操作注意细节

    9.1 多对多的正反向查询

    class Class(models.Model):
    
        name = models.CharField(max_length=32,verbose_name="班级名")
    
        course = models.CharField(verbose_name="课程",max_length=32)
    
        def __str__(self):
    
            return self.name
    
     
    
    class Teacher(models.Model):
    
        name = models.CharField(max_length=23,verbose_name="姓名")
    
        classes = models.ManyToManyField(verbose_name="所属班级",to="Class")
    
        def __str__(self):
    
            return self.name
    View Code

    9.1.1 题目1:查找娜娜老师所带的班级

    # 方式一:基于对象的查找
    
            obj = models.Teacher.objects.filter(name="娜娜").first()
    
            print(obj.classes.all())
    
            print("娜娜老师带的班级",obj.classes.values("name"))
    
            # 方式二:基于双下划线的查找
    
            obj_cls = models.Teacher.objects.filter(name="娜娜").values("classes__name")
    
            print("娜娜老师带的班级",obj_cls)
    View Code

    注意:要说明的是多对多的查询用.all,查单个的时候用.values或者values_list,不要用obj.classes.name,这样查到的会是None,反向查询也是如此。我就是犯了这样的错,引以为戒。。

    总结:不管是一对多,还是多对多,要是查询多得一方就得用all()

    运行结果截图:

     

    表结构:

    from django.db import models
    
     
    
    # Create your models here.
    
    # 一个学生有一个班级,一个班级可以有好多学生,所以是
    
    # 一对多的关系,关联字段放在多的一方
    
    class Student(models.Model):
    
        name = models.CharField(max_length=32,verbose_name="姓名")
    
        age = models.IntegerField(verbose_name="年龄")
    
        classes = models.ForeignKey(to="Class",verbose_name="所属班级")
    
        def __str__(self):
    
            return self.name
    
     
    
    class Class(models.Model):
    
        name = models.CharField(max_length=32,verbose_name="班级名")
    
        course = models.CharField(verbose_name="课程",max_length=32)
    
        def __str__(self):
    
            return self.name
    
     
    
    class Teacher(models.Model):
    
        name = models.CharField(max_length=23,verbose_name="姓名")
    
        classes = models.ManyToManyField(verbose_name="所属班级",to="Class")
    
        def __str__(self):
    
            return self.name
    
     
    View Code

    9.1.2 查询海燕在那个班级

    # 方式一:
    
        print("海燕所在的班级",models.Student.objects.filter(name="海燕").values("classes__name"))
    
        # 方式二:
    
        obj_cls = models.Student.objects.filter(name="海燕").first()
    
        print("海燕所在的班级",obj_cls.classes.name)
    
     
    View Code

    9.1.3 查询海燕所在班的老师的姓名

    print("海燕所在班的老师的姓名",models.Student.objects.filter(name="海燕").values("classes__teacher__name"))

    9.1.4 查询软件测试151班的所有学生的姓名

    print("软件测试151班的所有学生的姓名",models.Class.objects.filter(name="软件测试151").values("student__name"))
    
     obj = models.Class.objects.filter(name="软件测试151").first()
    
     # print("软件测试151班的所有学生的姓名",obj.student_set.name)  #这样打印的结果是None
    
     print("软件测试151班的所有学生的姓名",obj.student_set.all().values("name"))
    View Code

    9.2 需要掌握的一个很重要的知识点

    1、form表单中要用submit,如果用button切记要加上type,不然button默认的type是submit,会有影响

      <button class="login" type="button">注册</button>

    <button type="button" onclick="doValidation();">提交</button>
    
    <input type="button" onclick="doValidation();" value="提交"/>
    
    上面两种写法是对的,功能一样。
    
     
    
    <button onclick="doValidation();">提交</button>
    
    如果写成这种,默认为submit,本来doValidation方法里有提交功能了,
    
    再加上按钮也是提交功能,会提交两次。所以使用按钮时最好指定type类型。
    
     
    View Code

    第10章 django之数据库表的单表查询

    10.1 添加表记录

    对于单表有两种方式

     # 添加数据的两种方式
    
        # 方式一:实例化对象就是一条表记录
    
        Frank_obj = models.Student(name ="海东",course="python",birth="2000-9-9",fenshu=80)
    
        Frank_obj.save()
    
        # 方式二:
    
        models.Student.objects.create(name ="海燕",course="python",birth="1995-5-9",fenshu=88)
    View Code

    10.2 查询表记录

    10.2.1 查询相关API

    # 查询相关API
    
        # 1、all():查看所有
    
        student_obj = models.Student.objects.all()
    
        print(student_obj)  #打印的结果是QuerySet集合
    
        # 2、filter():可以实现且关系,但是或关系需要借助Q查询实现。。。
    
        #              查不到的时候不会报错
    
        print(models.Student.objects.filter(name="Frank"))  #查看名字是Frank的
    
        print(models.Student.objects.filter(name="Frank",fenshu=80))  #查看名字是Frank的并且分数是80的
    
        # 3、get():如果找不到就会报错,如果有多个值,也会报错,只能拿有一个值的
    
        print(models.Student.objects.get(name="Frank"))  #拿到的是model对象
    
        print(models.Student.objects.get(nid=2))  #拿到的是model对象
    
        # 4、exclude():排除条件
    
        print( models.Student.objects.exclude(name="海东")) #查看除了名字是海东的信息
    
        # 5、values():是QuerySet的一个方法 (吧对象转换成字典的形式了,)
    
        print(models.Student.objects.filter(name="海东").values("nid","course")) #查看名字为海东的编号和课程
    
        #打印结果:<QuerySet [{'nid': 2, 'course': 'python'}, {'nid': 24, 'course': 'python'}]>
    
        # 6、values_list():是queryset的一个方法 (吧对象转成元组的形式了)
    
        print(models.Student.objects.filter(name="海东").values_list("nid", "course"))
    
        #打印结果:< QuerySet[(2, 'python'), (24, 'python')] >
    
        # 7、order_by():排序
    
        print(models.Student.objects.all().order_by("fenshu"))
    
        # 8、reverse():倒序
    
        print(models.Student.objects.all().reverse())
    
        # 9、distinct():去重(只要结果里面有重复的)
    
        print(models.Student.objects.filter(course="python").values("fenshu").distinct())
    
        # 10、count():查看有几条记录
    
        print(models.Student.objects.filter(name="海东").count())
    
     
    
        # 11、first()
    
        # 12、last()
    
        return render(request,"test.html",{"student_obj":student_obj})
    
        # 13、esits:查看有没有记录,如果有返回True,没有返回False
    
            #         并不需要判断所有的数据,
    
            # if models.Book.objects.all().exists():
    View Code

    10.2.2 双下划线之单表查询

    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")  #包括ven的
    
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    
     
    
    models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and
    
     
    
    startswith,istartswith, endswith, iendswith 
    View Code
    对象可以调用自己的属性,用一个点就可以
    
    还可以通过双下划线。。。
    
        models.Book.objects.filter(price__gt=100)   价格大于100的书
    
        models.Book.objects.filter(author__startwith= "")    查看作者的名字是以张开头的
    
        主键大于5的且小于2
    
        price__gte=99大于等于
    
        publishDate__year =2017,publishDate__month = 10   查看2017年10月份的数据

    10.3 修改表记录

     

    注意:

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

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

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

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

    10.4 删除表记录

    删除方法就是 delete()。它运行时立即删除对象而不返回任何值。例如:e.delete()

    def delstudent(request,id):
    
        # 删除数据
    
        models.Student.objects.filter(nid=id).delete()
    
        return redirect("/test/")

    你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。

    例如,下面的代码将删除 pub_date 是2005年的 Entry 对象:

    Entry.objects.filter(pub_date__year=2005).delete()

    要牢记这一点:无论在什么情况下,QuerySet 中的 delete() 方法都只使用一条 SQL 语句一次性删除所有对象,而并不是分别删除每个对象。如果你想使用在 model 中自定义的 delete() 方法,就要自行调用每个对象的delete 方法。(例如,遍历 QuerySet,在每个对象上调用 delete()方法),而不是使用 QuerySet 中的 delete()方法。

    在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。例如:

    b = Blog.objects.get(pk=1)
    
    # This will delete the Blog and all of its Entry objects.
    
    b.delete()

    要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:

    Entry.objects.all().delete()

    10.5 编辑表格中的内容的涉及到的语法

    编辑操作涉及到的语法
    
     
    
    分析:
    
        1、点击编辑,让跳转到另一个页面,拿到我点击的那一行
    
        两种取id值的方式
    
        方式一:
    
            利用数据传参数(作为数据参数传过去了)
    
            <a href="/edit/?book_id = {{book_obj.nid}}"></a>  #相当于发了一个键值对
    
            url里面就不用写匹配的路径了,
    
            id = request.GET.get("book_id")  #取值
    
       
    
        方式二:
    
            利用路径传参,得在url里面加上(d+),就得给函数传个参数,无名分组从参数里面取值
    
            <a href="/{{book_obj.nid}}"></a>
    
       
    
        2、拿到id,然后在做筛选
    
            id = request.GET.get("book_id")
    
            book_obj = models.Book.objects.filter(nid=id)  #拿到的是一个列表对象
    
            注意:
    
                1.取[0]就拿到对象了,,然后对象.属性就可以取到值了
    
                2.用get,你取出来的数据必须只有一条的时候,,如果有多条用get就会报错,,,但是用get就不用加[0]了
    
            book_obj = models.Book.objects.filter(nid=id)[0]   
    
           
    
        3、当点击编辑的时候怎么让input框里显示文本内容
    
            value = "{{book_obj.title}}"
    
        4、改完数据后重新提交
    
            当提交的时候走action...../edit/}
    
            隐藏一个input,
    
            <input type="hidden" name = "book_id" value="{{book_obj.nid}}">
    
            判断post的时候:
    
                修改数据
    
                    方式一:save(这种方式效率是非常低的,不推荐使用,了解就行了)
    
                        修改的前提是先取(拿到要编辑的id值)
    
                        id = request.POST.get("book_id")
    
                        bk_obj = models.Book.objects.filter(nid=id)[0]
    
                        bk_obj.title = "hhhhhh"  #这是写死了,不能都像这样写死了
    
                        bk_obj.save()  只要是用对象的这种都要.save
    
                    方式二:update
    
                    title = request.POST.get("title")
    
                    models.Book.objects.filter(nid=id).update(title=title,......)
    
                跳转到index
    
               
    
               
    
               
    
               
    
    如果是post请求的时候怎么找到id呢,
    
    一、如果是数据传参:(也就是get请求的时候)
    
        可以通过一个隐藏的input框,给这个框给一个name属性,value属性。通过request.POST.get(""),,就可以得到id的值
    
    二、如果是路径传参
    
        可以通过传参的形式,当正则表达式写一个(d+)的时候,就给函数传一个id,可通过这个id知道id.
    View Code

    第11章 作业

    作业要求,在Django里面实现一个简单的表单数据查询、新增、修改、删除等。

  • 相关阅读:
    注解
    idea 快速生成返回值快捷方式
    异常处理
    finally 关键字
    博客园美化
    winform中webBrowser模拟网页操作中遇到的问题
    使用NPOI 2.1.1读取EXCEL2003/2007返回DataTable
    使用事务和SqlBulkCopy批量插入数据
    Java String比较
    Java 实例级别的锁和类级别的锁
  • 原文地址:https://www.cnblogs.com/maojiong/p/8947397.html
Copyright © 2020-2023  润新知