(day51)三、ORM、路由层、版本差异、流程图

一、ORM关系建立

(一)ForeignKey(一对多)

  1. 外键字段建在多的那一方(多次引用)
  2. 外键字段在同步时,会自动在字段加_id后缀,不需要手动加
from django.db import models

class Publish(models.Model):
    title = models.CharField(max_length=32)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=32)
    email = models.DecimalField(max_digits=8,decimal_places=2) # 数字总共8位,小数两位

    # 书和出版社是一对多,并且书是多的一方,所以外键字段在书表中
    publish = models.ForeignKey(to = 'Publish')  # to用来指代和哪张表有关系,默认关联主键字段

(二)ManyToManyField(多对多)

  1. 被当做外键的表必须先创建,因此多对多的外键关系需要建立第三张表来专门处理
  2. 多对多的外键字段建在任意一方都可以,推荐建在查询速率高的一方
  3. 多对多的外键字段只是一个虚拟字段,不会再表中展示出来,只是起到一个高速ORM创建第三张表的关系的作用
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    
    
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)


    # 书跟作者是多对多的关系 外键字段建在任意一方都可以  但是建议你建在查询频率较高的那一方
    author = models.ManyToManyField(to='Author')  # django orm会自动帮你创建书籍和作者的第三张关系表
    # author这个字段是一个虚拟字段 不能在表中展示出来 仅仅只是起到一个高速orm 建第三章表的关系的作用

(三)OneToOneField(一对一)

  1. 一对一的表关系,外键字段建在任意一方都可以,推荐建在查询频率较高的一方
  2. 外键字段也不用添加_id
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
# 一对一的表关系 外键字段建在任意一方都可以,推荐建在查询频率较高的一方

author_detail = models.OneToOneField(to='Author_detail')  # fk + unique

class Author_detail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)  

二、django请求生命周期流程图

三、urls.py 路由层

(一)路由匹配

路由即请求地址和视图函数的映射关系

(1)URLconf配置

  1. 正则表达式:一个正则表达式字符串
  2. views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  3. 参数:可选的要传递给视图函数的默认参数(字典形式)
  4. 别名:可选的name参数
from django.conf.urls import url

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]

(2)正则表达式详解

  1. 正则匹配一旦匹配成功则不再继续,因此可加^$进行精确配置
  2. ^:以···开头,控制路由后缀前面部分
  3. $:以···结尾,控制路由后缀后面部分
  4. /:用来控制防止路由后缀前缀相同,比如,r'test'r'testadd'
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'test/', views.test),  # 路由后缀为qqqtest/qqq仍可访问
    url(r'^test/', views.test),  # 路由后缀为test/qqq仍可访问
    url(r'test/$', views.test),  # 路由后缀为qqqtest/仍可访问
    url(r'^test/$', views.test),  # 路由后缀为test/才可访问
]

(3)APPEND_SLASH

  1. settings.py文件中,没有此参数,但是默认参数APPEND_SLASH=True
  2. 作用:在浏览器发送请求时,检测到没有后缀/时,自动加上/并重定向到该网址
  3. 可在settings.py文件中,最后一行,配置APPEND_SLASH=False来关掉此功能

(二)分组匹配

  1. 无名分组:将分组内正则表达式匹配到的内容以位置参数传给视图函数,(pattern)
  2. 有名分组:将分组内正则匹配式匹配到的内容以关键字参数传给视图函数,(?P<name>pattern)
  3. 无名和有名分组不能混用,但是同种分组可以使用多次
  4. 正则表达式匹配出的参数永远都是字符串
url(r'^test/([0-9]{4})/', views.test)  # 无名分组
url(r'^testadd/(?P<year>\d+)/', views.testadd)  # 有名分组

url(r'^index/(\d+)/(?P<year>\d+)/', views.index)  # 不能混合使用,会报错

url(r'^index/(\d+)/(\d+)/', views.index),  # 可以使用多次无名分组
url(r'^index/(?P<args>\d+)/(?P<year>\d+)/', views.index),  # 可以使用多次有名分组

(三)反向解析

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

(1)正常匹配

url(r'^home/', views.home,name='xxx'),  # 路由和函数起别名
  1. 前端反向解析(url)

    <p><a href="{% url 'xxx' %}">111</a></p>
  2. 后端反向解析(reverse)

    from django.shortcuts import render,HttpResponse,redirect,reverse
    url = reverse('xxx')

(2)无名分组匹配

url(r'^home/(\d+)/', views.home,name='xxx'),  # 给路由与视图函数对应关系起别名
  1. 前端反向解析

    <p><a href="{% url 'xxx' 12 %}">111</a></p>
    <p><a href="{% url 'xxx' 1324 %}">111</a></p>
    <p><a href="{% url 'xxx' 14324 %}">111</a></p>
    <p><a href="{% url 'xxx' 1234 %}">111</a></p>
  2. 后端反向解析

    手动传入的参数 只需要满足能够被正则表达式匹配到即可

    url = reverse('xxx',args=(1,))
    url1 = reverse('xxx',args=(3213,))
    url2 = reverse('xxx',args=(2132131,))

(3)有名分组匹配

url(r'^home/(?P<year>\d+)/', views.home,name='xxx'),  # 给路由与视图函数对应关系起别名
  1. 前端反向解析

    <!--使用无名分组也可以-->
    <p><a href="{% url 'xxx' 12 %}">111</a></p>
    
    <!--规范写法-->
    <p><a href="{% url 'xxx' year=1232 %}">111</a></p>
  2. 后端反向解析

    # 可以使用无名分组
    url = reverse('xxx',args=(1,))
    
    # 规范写法
    url = reverse('xxx',kwargs={'year':213123})

(四)路由分发(include)

  1. 在django中,所有的app都可以有自己独立的urls,templates,static,因此,用django开发项目就可以完全做到多人分组开发,互相不干扰,每个人只开发自己的app
  2. 路由分发可以让总路由只做任务分发,具体的应用视图函数由应用的路由去做映射,从而解决项目的总路由匹配关系过多的问题
  3. 总路由分发时推荐使用include('应用名.urls')

    ```python

    子路由1.py

    from django.conf.urls import url
    from app01 import views

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

子路由2.py

from django.conf.urls import url
from app02 import views

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

总路由.py

第一种写法

from app01 import urls as app01_urls
from app02 import urls as app02_urls

urlpatterns = [
url(r'^admin/', admin.site.urls), # url第一个参数是一个正则表达式
# 路由分发
url(r'^app01/',include(app01_urls)), # 路由分发需要注意总路由里面不能以$结尾
url(r'^app02/',include(app02_urls)),]

第二种写法(推荐写法)

urlpatterns = [
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))]
```

(五)别名冲突

当多个app中出现了别名冲突时,,会出现访问错乱的问题

(1)名称空间

路由分发的时候可以给每一个app创建一个名称空间,然后在反向解析的时候可以选择到底去哪个名称空间中查找别名

url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))

# 后端
print(reverse('app01:reg'))
print(reverse('app02:reg'))

# 前端
<a href="{% url 'app01:reg' %}"></a>
<a href="{% url 'app02:reg' %}"></a>

(2)应用名前缀

起别名的时候统一加上应用名前缀

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

urlpatterns = [
   url('^reg/',views.reg,name='app01_reg')
]

四、伪静态

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

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

五、dangjo版本区别

(一)re_path

Django2.0中的re_path与django1.0的url一样,传入的第一个参数都是正则表达式

from django.urls import re_path # django2.0中的re_path
from django.conf.urls import url # 在django2.0中同样可以导入1.0中的url
urlpatterns = [
    # 用法完全一致
    url(r'^app01/', include(('app01.urls','app01'))),
    re_path(r'^app02/', include(('app02.urls','app02'))),
]

(二)path

  1. Django2.0中新增了一个path功能,传入的第一个参数不是正则表达式
  2. 用来解决:数据类型转换问题与正则表达式冗余问题

(三)转换器

(1)内置转换器

  1. str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  2. int:匹配正整数,包含0。
  3. slug,匹配字母、数字以及横杠、下划线组成的字符串。
  4. uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  5. path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
path('articles/<int:year>/<int:month>/<slug:other>/', views.article_detail)
# 针对路径http://127.0.0.1:8000/articles/2009/123/hello/,path会匹配出参数year=2009,month=123,other='hello'传递给函数article_detail

(2)自定义转换器

可以自定义参数转换的精度或长度

  1. 在app01下新建文件path_ converters.py,文件名可以随意命名

    class MonthConverter:
        regex='\d{2}' # 属性名必须为regex
    
        def to_python(self, value):
            return int(value)
    
        def to_url(self, value):
            return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
  2. 在urls.py中,使用register_converter将其注册到URL配置中:

    from django.urls import path,register_converter
    from app01.path_converts import MonthConverter
    register_converter(MonthConverter,'mon')
    
    from app01 import views
    
    urlpatterns = [
        path('articles/<int:year>/<mon:month>/<slug:other>/',
             views.article_detail,name='aaa'),
    ]

猜你喜欢

转载自www.cnblogs.com/wick2019/p/11931328.html