50、 路由层函数(无名分组、有名分组 、反向解析、路由分发)伪静态的概念、补充Django的版本区别、视图层

88 阅读7分钟

路由层-urls.py

1.urls.py:
  from django.conf.urls import url
  from django.contrib import admin
  urlpatterns = [
      url(r'^admin/', admin.site.urls),
  ]
  url(r'^admin/', admin.site.urls)  --->url(前缀的正则表达式,视图函数内存地址)
2.路由后缀的斜杠是有django自动给你添加的,默认情况,我们可以设置一些参数来修改的默认
	APPEND_SLASH = True (默认)
  APPEND_SLASH = False  ----在setting.py上加
3.url函数的第一个参数是支持正则表达式的,直接把正则表达式的相关内容拿过来就可以用

路由的匹配原则:在列表中的路由,逐个往下匹配,一旦找到一个,立即执行对应的函数,不在往下匹配

# views.py
def test(request):
    return HttpResponse('test')

def teatadd(request):
    return HttpResponse('testadd')
# urls.py
1.urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^testadd/', views.teatadd),
    url(r'^test/', views.test),]
ps:正常执行,但在浏览端中输入testadd/ddd/ergrtght/...等依然可以访问试图函数

2.
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test', views.test),
    url(r'^testadd', views.teatadd),]
ps:浏览器端输入test  ----展示test
		浏览器端输入testadd --展示test --- 其原因:testadd满足以test开头,所以执行test()试图函数
  
3.
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/$', views.test),
    url(r'^testadd/$', views.teatadd), ]
ps:正常执行,但路由中的后缀坚决不能加$ 

4.首页报错:http://127.0.0.1:8000/
解决:
		# views.py
  	def home(request):
    		return HttpResponse('home')
      
    # urls.py
		urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'', views.home),
        ]
    ps:不好,后面添加路由的时候,匹配不到了,走不到对应的路由函数
    
    # 解决
    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.home),
    url(r'^testadd/', views.teatadd),
    url(r'^test/', views.test),]

无名分组

分组:把一个正则表达式用小括号括起来

1.无名分组就是把匹配的内容当成位置参数传递给视图函数
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/(\d+)/$', views.test), ]

# views.py
def test(request,xxx):
    print(xxx)  # 3
    return HttpResponse('test')
  
ps:url(r'^test/(\d+)/$', views.test)进行了无名分组,(\d+)里面的值传给视图函数的形参,可传多个 :url(r'^test/(\d+)/(\d+)/(\d+)/(\d+)$', views.test):
def test(request,*args):
    print(args)  # ('3', '3', '4', '5')
    return HttpResponse('test')

有名分组

1.有名分组:把一个正则表达式用小括号括起来,然后给这个括起来的内容起个名字(?P<名字>正则);有名分组就是把匹配的内容当成关键字参数传递给视图函数
  # urls.py
  urlpatterns = [
      url(r'^admin/', admin.site.urls),
      url(r'^testadd/(?P<year>\d+)/$', views.teatadd)]
  # views.py 
  def teatadd(request,year):
      print(year)  # 2023
      return HttpResponse('testadd')
ps:url(r'^testadd/(?P<year>\d+)/$', views.teatadd)进行了有名分组,(?P<year>\d+),将匹配的数字命名为year,传给试图函数的形参, 可以匹配多个参数**kwargs:
  url(r'^testadd/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/$', views.teatadd)
def teatadd(request,**kwargs):
    print(kwargs)  # {'year': '2023', 'month': '5', 'day': '4'}
    return HttpResponse('testadd')

注意:无名和有名不要混合使用,但是,单个无名或者单个的有名可以多次使用

反向解析

反向解析: 可以给每一个路由起一个别名,然后,通过一些方法反向解析这个路由名字,可以得到这个路由对应的地址

1.后端反向解析:利用reverse()    首先要导模块
    # urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$', views.home),
        url(r'^index/', views.index,name = 'xxx'),]

    # views.py
      def home(request):
        print('home')  # home
        print(reverse('xxx'))  # /index/
        return HttpResponse('home')

    def index(request):
        print('index')
        return HttpResponse('index')

  
2.前段反向解析:{% url '起的别名' %}
    # urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$', views.home),
        url(r'^index/', views.index,name = 'xxx')]

    # home.html
    <a href="{% url 'xxx' %}">hello</a>

    # views.py
    def home(request):
        return render(request,'home.html')

    def index(request):
        print('index')
        return HttpResponse('index')

无名反向解析

后端反向解析
1.
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.home),
    url(r'^index/(\d+)/(\d+)', views.index, name='xxx')]

# views.py
def home(request):
    # print(reverse('xxx',args=(1,))) ## /index/1/
    print(reverse('xxx', args=(1,2)))
    return HttpResponse('hello') # /index/1/2
  
ps:这个参数我们一般应该写主键id
前端反向解析
1.{% url 'xxx' 1 2 %}  ---index/1/2
  # urls.py
  urlpatterns = [
      url(r'^admin/', admin.site.urls),
      url(r'^$', views.home),
      url(r'^index/(\d+)/(\d+)', views.index, name='xxx')]
  
  # views.py
  def home(request):
      return render(request,'home.html')
    
  # home.html
  <a href="{% url 'xxx' 1 2 %}">hello</a>

有名分组

后端反向解析
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.home),
    url(r'^index/(?P<year>\d+)/(?P<month>\d+)', views.index, name='xxx')]

# views.py
def home(request,year,month):

    # print(reverse('xxx',kwargs={'year':2023})) #/index/2023
    print(reverse('xxx', kwargs={'year': 2023,'month':4}))  # /index/2023/4
    return HttpResponse('hello') # /index/1/2
 
前端反向解析
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.home),
    url(r'^index/(?P<year>\d+)/(?P<month>\d+)', views.index, name='xxx')]


# views.py
def home(request,year,month):
    return render(request,'home.html')
  
# home.html
<a href="{% url 'xxx' year=2023 month=4 %}">hello</a>

路由分发

1.目前来说,一个django项目只有一个总路由文件:urls.py
2.由于django项目可以有多个app应用,每一个App应用都可以有自己的路由文件,称为子路由;在应用里面默认是没有urls.py的,需要手动创建
3.为什么要路由分发?
		当总路由中有非常多的路由时候,就会显得杂乱无章,我们这个时候就可以按照应用进行路由分发,把不同的路由写到对应的应用里面去,然后总路由文件做分发处理
4.路由分发步骤
		1.给每一个应用手动创建一个urls.py文件(复制Django项目包里面的urls.py)
  	2.路由分发:
    	方式一:include()--需要导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),
              url(r'^app01/', include(app01_urls)),
              url(r'^app02/', include(app02_urls))]
          ps:子路由urls.py正常写路由和视图的关系(注意把admin删除掉),在浏览器端首先输入应用名(eg:app01)
      方式二:通过句点符的方式:include(应用名.urls)
      	from django.conf.urls import url,include
        from django.contrib import admin

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

ps:总路由不能加$(路由中的后缀坚决不能加 $)

伪静态环境

1.静态文件:写死的一些东西
2.伪静态:把一些动态的网页伪装成静态网页(例如博客园文章后缀:.html)
3.为什么要伪装
    1.因为静态的网页更加容易被搜索引擎抓取到
  	2.搜索引擎其实是一个巨大的爬虫程序,你在百度中搜索一个关键词,百度拿着这个关键词去网络上去爬取数据,然后把爬到的数据处理好,返回到百度的页面
    3.为了把我们的网页被搜索引擎更好的抓取到,所以使用到了伪装
4.seo:免费的
  sem:收费的,打广告
5.如何做伪静态:在路由地址的后面拼接:.html结尾

虚拟环境

1.正常的开发,应该给每一个项目都配备一个虚拟环境(一个虚拟环境相当于是一个纯净的python解释器)
2.针对一个新的项目,解释器上只装跟本项目有关的模块,其余没用的都不装(可以节约资源)
3.虚拟环境不要创建过多,毕竟占资源
4.虚拟环境创建的方式
	1.pycharmc创建的
  2.命令创建

创建虚拟环境

虚拟环境.png

Django1和Django2的区别

1.django中的路由
	1. django1中路由使用的是url--url支持的是正则
  2. django1中路由使用的是path--path不支持正则,是精准匹配
      ps: 1.虽然path不支持正则,但也可以使用正则:re_path相当于url--->支持正则
           2.path支持五种转换器
 2. 创建表关系
  1.django1中得表关系是级联更细级联删除
  2.django2需要执行on_delete参数
  
3.补充:path支持五种转换器      
str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int:匹配正整数,包含0。
slug:匹配字母、数字以及横杠、下划线组成的字符串。
uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path:匹配任何非空字符串,包含了路径分隔符(/)(不能用?
      自定义装换器:...
eg:
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

试图层

三板斧

1.render(),redirect()本质都是HttpResponse()
	查看源码

JsonResponse

1.json格式的数据可以进行跨语言传输
2.在python、js、django中使用
    1.在python中:
  			序列化:json.dumps()
    		反序列化:json.loads()
    2.在js中:
      	序列化:JSON.stringify()
        反序列化:JSON.parse()
    3.在django中
        1.导模块:from django.http import JsonResponse
    		2.str_django = JsonResponse(data)
        from django.http import JsonResponse
        def ab_json(request):
            dic1 = {'name':'nana','age':18,'gender':'female'}
            str_django = JsonResponse(dic1)  # {"name": "nana", "age": 18, "gender": "female"}
            return HttpResponse(str_django)
3.在Django中含有中文需要序列化。
		1.python中:data = json.dumps(data, cls=encoder, ensure_ascii=False)
  	2.Django中:
    	from django.http import JsonResponse
      def ab_json(request):
          dic1 = {'name':'娜娜','age':18,'gender':'female'}
          str_django = JsonResponse(dic1)  # {"name": "\u5a1c\u5a1c", "age": 18, "gender": "female"}
          return HttpResponse(str_django)

中文解决:看源码找思路


def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
             json_dumps_params=None, **kwargs):
  if safe and not isinstance(data, dict):
    raise TypeError(
      'In order to allow non-dict objects to be serialized set the '
      'safe parameter to False.'
    )
    if json_dumps_params is None:
      json_dumps_params = {}
      kwargs.setdefault('content_type', 'application/json')
      data = json.dumps(data, cls=encoder, **json_dumps_params)
      super(JsonResponse, self).__init__(content=data, **kwargs)
      
关键:
data = json.dumps(data, cls=encoder, **json_dumps_params)
if json_dumps_params is None:
      json_dumps_params = {}
推到:
data = json.dumps(data, cls=encoder, **{'ensure_ascii': False})
data = json.dumps(data, cls=encoder, ensure_ascii=False)
from django.http import JsonResponse
def ab_json(request):
    dic1 = {'name':'娜娜','age':18,'gender':'female'}

    str_django = JsonResponse(dic1, json_dumps_params={'ensure_ascii': False}) # {"name": "娜娜", "age": 18, "gender": "female"}
    return HttpResponse(str_django)

当序列化对象是数组的时候

def ab_json(request):
    list1= [1,2,3,4]
    str_django = JsonResponse(list1)  # In order to allow non-dict objects to be serialized set the safe parameter to False.
    
# 看报错、源码解决
from django.http import JsonResponse
def ab_json(request):
    list1= [1,2,3,4]
    str_django = JsonResponse(list1,safe=False) 

Django中如何上传文件

1.表单上传数据需要的条件:
  	1. 请求方式需要是:post
		2. enctype---->form-data
    <form action="" method="post" enctype="multipart/form-data">
2.request.POST   只能接收普通参数,不能接收文件数据
3.request.FILES 接收文件数据

接收文件

def get_gift(request):
    print(request.POST)  # <QueryDict: {'username': ['nana']}>
    print(request.FILES)  # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: 创建项目1.png (image/png)>]}>
    if request.method =='POST':
        file_obj = request.FILES.get('myfile')
        print(file_obj)
        with open(file_obj.name,'wb')as f:
            for line in file_obj:
                f.write(line)
        return HttpResponse('ok')
    return render(request,"get_gift.html")
ps:file_obj.name:不要用这个名字,这个名字一般我们会重命名,自己写一个生成随机数的方法,调用这个方法,得到一个随机数,拿着这个随机数去拼接图片的后缀名:file_obj.png-----123.png---想办法吧后缀png截取出来-----随机数.pnge