django之路由层

[TOC]html

orm表关系如何创建

一对一

一张表的字段信息太多,能够人为分出一张表前端

一对多

外键字段建在 多的那一方python

多对多

多对多的外键关系须要创建第三张表来专门处理git

以图书馆里系统为例,建立图书表,做者表,出版社表正则表达式

以图书管理系统为例,在django orm 创建表关系:数据库

  • 一对一的表关系,外键字段建在任意一方均可以,可是建议建在查询频率较高的一方
  • 书与出版社是一对多关系,而且书是多的一方,因此外键字段建在书表中
  • 书与做者是多对多的关系, 外键字段建在任意一方均可以,建议建在查询频率较高的一方
class Book(models.Model):
    title = models.CharField(max_length=32)
    # 小数总共八位,小数占两位
    price = models.DecimalField(max_digits=8, decimal_places=2)

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

    # 书与做者是多对多的关系, 外键字段建在任意一方均可以,建议建在查询频率较高的一方
    author = models.ManyToManyField(to='Author')  # django orm会自动帮你建立书和做者的第三张关系表
    # author这个字段是一个虚拟字段 不能在表中展现出来,仅仅只是告诉orm,创建第三张表关系的做用


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


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 一对一的表关系,外键字段建在任意一方均可以,可是建议建在查询频率较高的一方
    author_detail = models.OneToOneField(to='Author_detail')


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

注意点:django

  • 一对多外键字段 建立的时候 ,同步到数据库中,表字段会自动加_id后缀;若是本身加了_id,会在后面再加一个_id
  • publish = models.ForeignKey(to='Publish')默认关联的是主键id,若是主键不是id,要本身关联, 能够加to_field=于指定字段作关联

django请求生命周期流程图

url.py路由层

urlpatterns = [
    url(r'^admin/', admin.site.urls), 
    url(r'test/', views.test), 
    url(r'testadd/', views.testadd)
]

若是url.py这样写,testtestadd后缀的访问路径,返回的内容是同样的,缘由以下:后端

  • url第一个参数是一个正则表达式
  • 一旦正马上结束则表达式可以匹配到内容,会马上结束匹配关系,直接执行后面对应的函数

路由匹配

启动django,在浏览器输入127.0.0.1:8000/test,django会自动加斜杠。浏览器

django匹配路由规律

不加斜杠(127.0.0.1:8000/test),先匹配一次试试,若是匹配不上,会让浏览器重定向,加一个斜杠(127.0.0.1:8000/test/)再来一次匹配,若是还匹配不上,才会报错。app

取消django自动让浏览器加斜杠的功能

在配置文件中settings.py中添加:

APPEND_SLASH = False   # 该参数默认为True

限制指定输入的url

urlpatterns = [
    url(r'^admin/', admin.site.urls),   # url第一个参数是一个正则表达式
    url(r'^test/$', views.test),  # 一旦正马上结束则表达式可以匹配到内容,会马上结束匹配关系,直接执行后面对应的函数
    url(r'^testadd/$', views.testadd)
]

这样设置,只能输入127.0.0.1:8000/test/127.0.0.1:8000/testadd/

注意:路由匹配只是匹配URL部分,不匹配get携带的参数 ?后面的参数

无名分组

正则表达式的无名分组

urlpatterns = [
    url(r'^admin/', admin.site.urls),   
    url(r'^test/([0-9]{4})', views.test),   # 表示test后面跟4个数字
    url(r'^testadd/', views.testadd)
]

当你的路由中有分组的正则表达式,那么在匹配到内容执行视图函数的时候,会将分组内正则表达式匹配到的内容看成位置参数传递给视图函数。

# 在视图函数
def test(request, xxx):
    print('多余的参数:', xxx)
    return HttpResponse('test view')

有名分组

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/(\d+)/', views.test), 
    url(r'^testadd/(?P<year>\d+)/', views.testadd)    # 正则表达式有名分组
]

当你的路由中有分组而且给分组起了别名,那么在匹配内容的时候,会将分组内的正则表达式匹配到的内容看成关键字参数传递给视图函数

# 在视图函数
def test(request, year):
    print('多余的参数:', year)
    return HttpResponse('test view')

这样就能够利用有名和无名分组,咱们就能够在调用视图函数以前给函数传递额外的参数

注意:有名分组和无名分组不能混合使用,可是同一状况下,无名分组可使用屡次,又名分组也可使用屡次

反向解析

举个例子:

# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/(\d+)/', views.test),
    url(r'^testadd/(?P<year>\d+)/', views.testadd),
    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('home')

在上述代码中,index.html页面中有不少跳转的连接,都指向home路由。若是像改变home的url地址,那么index.html页面中的不少跳转home的连接都有改变,有没有动态绑定url地址的方法呢?反向解析就是。

定义

反向解析:根据一个别名,动态解析出一个结果,该结果能够直接访问对应的url

路由中没有正则表达式,直接就是写死的

url(r'^home/', views.home,name='xxx'),   # 给路由与视图函数对应关系起别名

前端反向解析

<p><a href="{% url 'xxx'%}">111</a></p>

后端反向解析

from django.shortcuts import render,HttpResponse,redirect,reverse

def get_url(request):
    url = reverse('xxx')
    print(url)
    return HttpResponse('get_url')

无名分组的反向解析

在解析的时候,你须要手动指定正则匹配内容的是什么

url(r'^home/(\d+)/', views.home, name='xxx'),

前端反向解析

<p><a href="{% url 'xxx' 12 %}">111</a></p>

后端反向解析

def get_url(request):
    url = reverse('xxx', args=(1,))
    url2 = reverse('xxx', args=(1231,))
    print(url)
    print(url2)
    return HttpResponse('get_url')

<font color='yellow'>手动传入的参数 只须要知足 可以被正则表达式匹配便可</font>

有名分组的反向解析

url(r'^home/(?P<year>\d+)/', views.home, name='xxx'),

前端反向解析

能够直接用无名分组的状况

<p><a href="{% url 'xxx' 12 %}">111</a></p>

规范的写法:

<p><a href="{% url 'xxx' year=121 %}">111</a></p>

后端反向解析

能够直接用无名分组的状况

也能够规范写:

def get_url(request):
    url = reverse('xxx', kwargs={'year': 13123})
    print(url)
    return HttpResponse('get_url')

以编辑功能为例,反向解析的应用

# urls.py
url = (r'^edit_user/(\d+)/', views.edit_user, name='edit')

# views.py
def edit_user(request, edit_id):  # edit_id就是用户想要编辑数据主键值
    pass
<!--页面-->
{% for user_obj in user_list %}
<a href='/edit_user/{{user_obj.id}}/'>编辑</a>
<a href='{% url 'edit' user_obj.id %}'>编辑</a>
{% endfor %}

路由分发

前提:

在django中全部的app均可以有本身独立的urls.py \ templates \ static.
正是因为上面的特色 你用django开发项目就可以彻底作到多人分组开发 互相不干扰,每一个人只开发本身的app.
小组长只须要将全部人开发的app整合到一个空的django项目里面,
而后在settings配置文件注册 再利用路由分发将多个app整合到一块儿便可完成大项目的拼接

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

使用路由分发, 会出现:

  • 总路由再也不作匹配的活 而仅仅是作任务分发
  • 请求来了以后 总路由不作对应关系,只询问你要访问哪一个app的功能 而后将请求转发给对应的app去处理

使用:

总路由 (include)

只须要将全部的app的urls.py导入便可

from django.conf.urls import url, include
from app01 import urls as app01_urls
from app02 import urls as app02_urls


urlpatterns = [
    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 app02 import views


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

]

最省事的写法:

# 连导入都不须要
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))

名称空间 (namespace)

当多个app中出现了起别名冲突的状况 你在作路由分发的时候 能够给每个app建立一个名称空间 而后在反向解析的时候 能够选择到底去哪一个名称空间中查找别名

在总路由中:

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

前端:

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

后端:

print(reverse('app01:reg'))
print(reverse('app02:reg'))

可是也能够不用,你只要 保证起别名的时候,在整个django项目中不冲突便可

伪静态

就是将一个动态网页假装成一个静态网页,这样能够便于搜索引擎SEO(Search Engine Optimization),提升搜索引擎的收藏力度。

虚拟环境

  • 每建立一个虚拟环境就相似于你从新下载了一个纯净python解释器

  • 以后该项目用到上面 你就装什么(虚拟环境一台机器上能够有N多个)

django版本区别

urls.py中路由匹配的方法有区别

django 1.xx版本

用的是url

from django.conf.urls import url
urlpatterns = [
    url(r'^reg.html',views.reg,name='app01_reg')
]

django 2.xx版本

用的是path

from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]
  • 这里的path第一个参数不是正则,也不支持正则
  • django2.X还有一个re_path的方法 该方法就是django1.X里面url
  • path提供了五种转换器,可以将匹配到的数据自动转换成对应的类型
  • 还支持自定义的转换器

django后端获取文件对象

form表达传文件须要注意的事项

  • method必须改为post
  • enctype改成formdata格式
# urls.py
from django.conf.urls import url
from app02 import views


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


# views.py
def upload(request):
    if request.method == 'POST':
        print(request.FILES)   # django会将文件类型的数据自动放入request.FILES
        file_obj = request.FILES.get('myfile')  # 文件对象
        # print(file_obj)
        # print(file_obj.name)
        with open(file_obj.name, 'wb') as f:
            for line in file_obj:
                f.write(line)
    return render(request, 'upload.html')
相关文章
相关标签/搜索