路由层-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.命令创建
创建虚拟环境
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