zoukankan      html  css  js  c++  java
  • Django 03

    django建立表关系

    • 以图书表, 作者表, 出版社表为例
    1. 一对多

      给图书表增加出版社外键 publish = models.ForeignKey(to="Publish")

    2. 一对一

      给作者表增加作者详情外键 author_detail = models.OneToOneField(to="AuthorDetail")

    3. 多对多

      图书和作者之间, 在图书表上添加 author = models.ManyToManyField(to="Author")

    4. 注意

      1. django会给外键字段自动加上"_id"后缀, 不需要我们手动增加, 否则会导致重复
      2. 建立多对多表关系时的字段只是一个虚拟字段, 并不会出现在表中. 会生成一个新的表

    请求生命周期图

    路由匹配

    我们在 urls.py 添加如下路由与视图函数的匹配关系, 注意路由结尾没有 "/"

    # urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^test', views.test),
        url(r'^test_add', views.test_add),
    ]
    
    # views.py
    def test(request):
        return HttpResponse("test view")
    
    
    def test_add(request):
        return HttpResponse("test_add view")
    
    

    现在我们启动项目并访问 127.0.0.1:8000/test 页面显示为 test view

    然后我们访问 127.0.0.1:8000/test_add 页面显示依旧为 test view

    **造成这种现象的原因是 url(r'^test', views.test) 中的第一个参数是一个正则表达式, 只要你输入的域名后缀, 比如 test_add 符合条件, 就会执行其对应的视图函数, 并结束匹配 **

    我们可以修改路由为 url(r'^test_add/', views.test) 来解决这个问题 (结尾增加一个 "/" )

    • ^test/ 必须以test/开头
    • test/$ 必须以test/结尾

    现在我们通过在结尾加"/"的方式解决了上述问题, 我们现在访问 127.0.0.1:8000/test_add 页面显示为 test_add view

    心细的你肯定又发现了另一个问题, 我们设置的路由匹配明明结尾是带有 "/" url(r'^test_add/', views.test)

    为什么我们访问时不加"/" 127.0.0.1:8000/test_add 也能成功进行访问呢?

    这是因为django自动给我们做了处理:

    • 当我们结尾不加 "/" 时进行访问时 127.0.0.1:8000/test_add, 先以 test_add 在url.py中进行寻找, 如果没有找到, 就会重定向到 127.0.0.1:8000/test_add/ 再次进行访问, 这时候就可以匹配到了

    如果我们不想让django帮我们添加 "/" 进行重定向访问, 可以在 setting.py 中加上如下一行代码

    • APPEND_SLASH = Flase

    还有一点需要我们注意的是:

    • 路由匹配不会匹配url中 "?" 及其后面的内容

    无名分组

    • 当路由中有无名分组的正则表达式时, 会把分组内匹配到的内容当做位置参数传递给视图函数

    现在我们设置了如下路由和视图函数的匹配关系

    # urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # ([0-9]{4}) 这是一个无名分组, 表示从0-9的4位数字
        url(r'^test/([0-9]{4})/', views.test),  
    ]
    
    # views.py
    def test(request, *args):
        return HttpResponse(f"test view received a positional argument: {args}")
    
    

    然后我们来访问一下 127.0.0.1:8000/test/1234 页面显示如下

    有名分组

    • 当路由中有有名分组的正则表达式时, 会把有名分组匹配到的内容当做关键字参数传递给视图函数

    现在我们设置了如下路由和视图函数的匹配关系

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^test_add/(?P<year>[0-9]{4})/', views.test_add),
    ]
    
    def test_add(request, **kwargs):
        return HttpResponse(f"test_add view received a key-word argument: {kwargs}")
    

    然后我们来访问一下 127.0.0.1:8000/test_add/2019/ 页面显示如下:

    • 利用无名分组和有名分组就可以给视图函数传递额外的参数
    • 可以有多个有名或者无名分组, 就是不能混合使用 url(r'^index/(?P<year1>[0-9]{4})/(?P<year2>[0-9]{4})/', views.test)

    反向解析

    • 根据一个别名, 动态解析出一个结果, 这个结果可以直接访问对应的url

    模板中的超链接

    这是我们的路由和视图函数

    # urls.py
    urlpatterns = [
        url(r'^index/', views.index),
        url(r'^home/', views.home)
    ]
    
    
    # views.py
    def index(request):
        return render(request, "index.html")
    
    
    def home(request):
        return HttpResponse("this is home view")
    

    这是我们的 index.html 文件, 很明显, 我们访问 index/ 点击 跳转到home 就可以跳转到home页面了

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>反向解析</title>
    </head>
    <body>
    普通连接: <a href="home/">跳转到home</a>
    </body>
    </html>
    

    假设现在产品经理要求把 url(r'^home/', views.home) 改成 url(r'^homework/', views.home)

    那我们也要把 index.html 的当中的 <a href="home/">跳转到home</a> 改成 <a href="homework/">跳转到home</a> 否则就跳转不到相应的页面啦

    像上面这样, 一个a标签很好改, 万一有几百上千个a标签呢? 还不得改出人命么

    为了挽救程序员的生命, 我们可以利用django提供的反向解析方法

    1. 在url中添加一个一个别名
    # urls.py
    urlpatterns = [
        url(r'^index/', views.index),
        # 添加一个name参数
        url(r'^home/', views.home, name='to_home')
    ]
    
    1. index.html 中修改跳转连接
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>反向解析</title>
    </head>
    <body>
    普通连接: <a href="home/">跳转到home</a>
    <hr>
    反向解析: <a href="{% url 'to_home' %}">跳转到home</a>
    </body>
    </html>
    

    这样django就可以通过这个 to_home 别名来找到相应的路由啦 (比如: /homework/)

    现在不管我们如何修改 url(r'^home/', views.home, name='to_home') 中的路由, 都可以跳转成功了

    视图中的重定向

    显然我们在视图层也有可能用到超链接, 比如 redirect 重定向

    同样的, 这是我们的路由和视图函数

    # urls.py
    urlpatterns = [
        url(r'^home/', views.home),
        url(r'^homepage/', views.homepage)
    ]
    
    # views.py
    def home(request):
        return HttpResponse("this is home view")
    
    
    def homepage(request):
        return redirect("/home/")
    

    和上面一样, 如果我们把 url(r'^home/', views.home) 改成 url(r'^homework/', views.home)

    那我们也要把 views.py 中的 homepage()方法 下面的 /home/ 改为 /homework/

    有什么办法可以让 django帮我们操作呢? 这里我们需要借助 reverse() 方法

    from django.shortcuts import render, HttpResponse, redirect, reverse
    
    def home(request):
        return HttpResponse("this is home view")
    
    
    def homepage(request):
        return redirect(reverse("to_home"))
    
    

    以为反向解析就这么结束了吗? 再看看下面两种情况:

    1. 当需要跳转的连接中包含无名分组时
    # urls.py
    urlpatterns = [
        url(r'^index/', views.index),
        url(r'^home/([0-9]{4})', views.home)
        url(r'^homepage/', views.homepage)
    ]
    
    # views.py
    def index(request):
        return render(request, "index.html")
    
    # 分组匹配到的内容会传入视图函数, 因此我们用*args/**kwargs来接收一下, 否则会报错
    def home(request, *args, **kwargs):
        return HttpResponse("this is home view")
    
    def homepage(request):
        return redirect(reverse("to_home"))
    

    index.html 中修改跳转连接, 需要传入一个参数, 只要这个参数满足无名分组的筛选条件即可

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>反向解析</title>
    </head>
    <body>
    普通连接: <a href="home/">跳转到home</a>
    <hr>
    反向解析: <a href="{% url 'to_home' 1999 %}">跳转到home</a>
    </body>
    </html>
    

    当然, 视图层里面的reverse内也需要传入一个参数, 只要这个参数满足无名分组的筛选条件即可

    def homepage(request):
        # 以元祖的形式传参
        return redirect(reverse("to_home", args=(1998, )))
    
    1. 当需要跳转的连接中包含有名分组时
    # urls.py
    urlpatterns = [
        url(r'^index/', views.index),
        url(r'^home/(?P<year>[0-9]{4})', views.home)
        url(r'^homepage/', views.homepage)
    ]
    
    # views.py
    def index(request):
        return render(request, "index.html")
    
    # 分组匹配到的内容会传入视图函数, 因此我们用*args/**kwargs来接收一下, 否则会报错
    def home(request, *args, **kwargs):
        return HttpResponse("this is home view")
    
    def homepage(request):
        return redirect(reverse("to_home"))
    

    index.html 中修改跳转连接, 需要传入一个参数, 只要这个参数满足有名分组的筛选条件即可

    <!--下面这两种都可以, 第二种更规范-->
    反向解析: <a href="{% url 'to_home' 1999 %}">跳转到home</a>
        
    反向解析: <a href="{% url 'to_home' year=1999 %}">跳转到home</a>
    
    

    当然, 视图层里面的reverse内也需要传入一个参数, 只要这个参数满足有名分组的筛选条件即可

    def homepage(request):
        # 以字典的形式传参
        return redirect(reverse("to_home", kwargs={year:1998}))
    

    路由分发

    在django中所有的app都可以有自己的独立的urls.py, templates文件夹, static文件夹

    这样一来, django项目就能够完全做到多人分组开发, 互相不干扰

    路由分发解决的是项目的总路由匹配关系过多的情况

    使用路由分发, 总路由匹配的是不再是视图函数, 而是对应的app

    # project/urls.py
    # 需要先导入 include
    from django.conf.urls import url, include
    from django.contrib import admin
    
    from app01 import urls as app01_urls
    from app02 import urls as app02_urls
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 总路由这里匹配的是相应的app
        url(r'^app01/', include(app01_urls)),
        url(r'^app02/', include(app02_urls)),
    
    ]
    
    
    # app01/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^reg/', views.reg),
    
    ]
    
    
    # app02/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^reg/', views.reg),
    
    ]
    
    
    # app01/views.py
    from django.shortcuts import render, HttpResponse
    
    
    def reg(request):
        return HttpResponse("app01 reg")
    
    
    # app02/views.py
    from django.shortcuts import render, HttpResponse
    
    
    def reg(request):
        return HttpResponse("app02 reg")
    
    

    现在我们来访问 127.0.0.1:8000/app01/reg 页面显示为 app01 reg

    访问 127.0.0.1:8000/app02/reg 页面显示为 app02 reg

    别着急还没完, 我们还可以写成如下格式, 这样就不用将各个app的 urls.py 一个个导入啦

    # project/urls.py
    # 需要先导入 include
    from django.conf.urls import url, include
    from django.contrib import admin
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 总路由这里匹配的是相应的app 
        url(r'^app01/', include(app01.urls)),  # 直接用 app名.urls 就可以, 不用导入了
        url(r'^app02/', include(app02.urls)),
    
    ]
    
    

    名称空间

    当多个app中 urls.pyurl() 方法中都传入相同的name参数, 那反向解析时可能会出错

    # app01/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^reg/', views.reg, name='reg'),
    
    ]
    
    
    # app02/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^reg/', views.reg, name='reg'),
    
    ]
    

    怎样解决这个问题呢?

    我们可以在项目 urls.py 中给各个app添加名称空间

    # project/urls.py
    from django.conf.urls import url, include
    from django.contrib import admin
    
    from app01 import urls as app01_urls
    from app02 import urls as app02_urls
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 添加名称空间spacename
        url(r'^app01/', include(app01_urls), spacename='app01'),
        url(r'^app02/', include(app02_urls), spacename='app02'),
    
    ]
    

    在前后端进行反向解析时也应该进行相应的修改

    ​ 模板层: <a href="{% url 'app01:reg' %}">跳转到reg</a>

    ​ 模型层: reverse("app01:reg")

    现在我们再来想一下这个问题, 导致这个问题的根本原因就是不同的app中起别名起重复了

    那只要不重复不就行了???

    很简单, 其别名的时候用app名作为前缀就行了

    # app01/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 用app名作为别名前缀, 避免重复
        url(r'^reg/', views.reg, name='app01_reg'),
    
    ]
    
    
    # app02/urls.py
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 用app名作为别名前缀, 避免重复
        url(r'^reg/', views.reg, name='app02_reg'),
    
    ]
    

    伪静态

    将一个动态网页伪装一个静态网页, 以此来提升搜索引擎SEO查询频率和收藏力度

    如何伪装呢?

    很简单, 修改路由以 .html 结尾即可

    urlpatterns = [
        url(r'^reg.html/', views.reg),
    
    ]
    

    虚拟环境

    给每一个项目 装备该项目所需要的模块 不需要的模块一概不装

    每创建一个虚拟环境就类似于你重新下载了一个纯净python解释器
    之后该项目用到什么 你就装什么 (虚拟环境一台机器上可以有N多个)

    注意, 不要在你的机器上无限制创建虚拟环境

    django版本区别

    我们知道现在django有两个大版本: django1.x 和 django2.x

    这两个版本 urls.py 中路由匹配的方法有区别的:

    # 1.x 用的还是url
    urlpatterns = [
         url(r'^admin/', admin.site.urls)
    ]
    
    # 2.x 用的是path
    urlpatterns = [
    		path('admin/', admin.site.urls),
    	]
    
    

    path第一个参数不是正则也不支持正则 写什么就匹配什么

    1. 虽然path不支持正则 感觉也bu好用 django2.x还有一个 re_path 的方法 该方法就是你django1.x里面url

    2. path提供了五种转换器 能够将匹配到的数据自动转化成对应的类型

    urlpatterns = [
    		path('index/<int:age>', views.index),
    	]
    

  • 相关阅读:
    Java Applet实现五子棋游戏
    CrawlScript脚本语言实现网络爬虫
    Eclipse集成Git的实践
    以图表形式分析和统计数据
    爬虫抓取分页数据的简单实现
    爬虫的简单实现
    使用htmlparser爬虫技术爬取电影网页的全部下载链接
    使用webcollector爬虫技术获取网易云音乐全部歌曲
    百度地图API-覆盖物
    百度地图API-控件
  • 原文地址:https://www.cnblogs.com/bigb/p/11932963.html
Copyright © 2011-2022 走看看