一。数据库的关系建立。
在原生的数据库语句中,建立表与表之间的联系,就是添加一个字段,将联系的表的id值添加到该字段中。
django所作的也就是这些。
以图书管理系统为例,图书管理系统有四张表:书籍表,作者表,出版社表,书籍细节表。他们之间的对应关系如下:
书籍对应书籍细节表是一对一。
书籍对应作者表是多对多。
出版社对应书籍表是一对多。
这些在django都有相关的字段或者虚拟字段来建立。
1。建立一对多的关系。
对于一对多的字段需要将其添加到多的那张表中,也就是书籍表:
class Book(models.Model): title = models.CharField(max_length=64) price=models.DecimalField(max_digits=8,decimal_places=2) publish = models.ForeignKey(to='Publish') authors = models.ManyToManyField(to='Author')
其中关键字ForeignKey,外键,就默认将PUblish中的数据的id添加到外键中。
其中外键也可以这样写:
publish = models.ForeignKey(to=Publish)
直接将对象作为参数传入,但是需要将该参数写在上面,因为解释器是从上往下编译。
补充:max_digits是指整数位的显示位数,decimal_places是小数位显示的个数。
2.多对多。
多对多的情况只需要在两表中的一个建立ManyToManyField即可,建立的不是真正的字段,是一个虚拟的。会重新建一个表表示两者的对于关系。
3.一对一。
一对一的关系体现在书籍和书籍详情上,可以使用关键字:OneToOneField字段进行绑定,一般绑定在查询频率较高的表中。
class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail',null=True)
在foreignkey中,字段后面会自动添加_id作为区分。无论你原来有没有。
二。django的生命周期。
一般的,从前端的请求发送都会发送到wsgiref模块进行处理,然后从路由urls中寻找相应视图函数,最后通过模板和数据库的渲染,返回到页面。
三。路由匹配。
当前端发送数据请求时通常携带请求信息等,其中就包括路,路由决定了后端提交给前端的模板,通过路由可以搜寻到相关的视图函数。
在django中,路由匹配通常是url开头的以正则表达式为基础的匹配。
当正则表达式匹配上路由时,就不会往下继续匹配。
1.加斜杠二次匹配。
当在浏览器中没有加斜杠就进行匹配而没能匹配到结果时,会自动加上/再次进行匹配。如果没有比配到就会报错。
如果需要取消这一机制,需要在settings配置文件:
APPEND_SLASH = False # 该参数默认是True
通常,如果需要精准匹配路由,都会在首和尾添加符号^$。
2,^$应用。
我们可以通过正则表达式^$来匹配初始页面,用来渲染该项目的初始页面。
3.''空应用。
在匹配的最后可以加上空字节匹配所有路由,当第一次匹配,没有任何结果时就返回错误页面渲染,但是这样就不能使用第一条的二次匹配了。
四。有名分组与无名分组。
在url路由匹配时,由于匹配的性质时正则表达式,所以,可以在正则表达式中书写分组。
复习:在正则表达式中,出现了分组时()findall就会事先展示分组中的内容。
无名分组。
而在这里,分组匹配的内容会作为位置参数传给它的视图函数,所以,视图函数中需要指定一个位置参数来接受该值。
def test(request,xx,year): print(year) print(xx) return HttpResponse('test')
url(r'^test/([0-9]{4})/', views.test)
有名分组:
当正则表表达式给分组中匹配的值起了别名后,就会像视图传入一个关键字参数,所以后端需要传入相应的名字的参数作为接受。
url(r'^test/(?P<year>\d+)/', views.test)
注意:无名分组和有名分组不能混合使用,即不能出现以下情况:
url(r'^test/(\d+)/(?P<year>\d+)/', views.test),
但是同一种分组下支持多个使用:
# 无名分组支持多个 # url(r'^test/(\d+)/(\d+)/', views.test), # 有名分组支持多个 # url(r'^test/(?P<year>\d+)/(?P<xx>\d+)/', views.test),
五,反向解析
对于反向解析,就是返回一个能够访问对应url的地址给后端,所以需要匹配正则。
反向解析可以让后端和前端动态的拿到url。
首先需要对对应的url起别名。:
url(r'^index/$',views.index,name='kkk')
1.前端反向解析:
通过以下函数可以在前端拿到对应 的url:
{% url 'kkk' %}
2.后端反向解析:
from django.shortcuts import render,HttpResponse,redirect,reverse reverse('kkk')
注意,这个函数是根据别名拿对应的url即使不是本函数的url也可以拿到!
3.无名分组反向解析。
当url中出现正则表达式有分组的出现,其需要匹配一定的数值才能拿到该url,具体如下。
url(r'^index/(\d+)/$',views.index,name='kkk')
直接通过kkk是不能获取对应的url的,需要添加一定的参数:
后端反向解析 reverse('kkk',args=(1,)) # 后面的数字通常都是数据的id值 前端反向解析 {% url 'kkk' 1%} # 后面的数字通常都是数据的id值
一般的,后端反向解析都是用来跳转页面用的,前端都是用来传递关键信息(猜测)。
4。有名分组反向解析。
当有名分组时,需要反向解析其实和无名可以公用一个方法:
url(r'^index/(?P<year>\d+)/$',views.index,name='kkk')
后端反向解析:
print(reverse('kkk',args=(1,)))
可以使用关键字传参:
print(reverse('kkk',kwargs={'year':1}))
前端反向解析:
<a href="{% url 'kkk' 1 %}">1</a>
关键字传参:
<a href="{% url 'kkk' year=1 %}">1</a>
注意:在同一个应用下,别名不能重复。
六。路由分发。
当你的django项目特别庞大的时候 路由与视图函数对应关系特别特别多,那么你的总路由urls.py代码太过冗长 不易维护。
每一个应用都可以有自己的urls.py,static文件夹,templates文件夹。所以在app中创建这些文件即可。
项目下的urls只需要分发路由即可:
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))
]
在项目中再调用相应的函数执行:
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
当然,django支持简写,也就是导入模块,直接以字符串代替模块名
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls')), ]
总路由中 一级路由的后面千万不加$符号
七。名称空间。
在多个app中,如果多个路由起了相同的别名,在视图进行反向解析是,会是哪个呢。
答案是只能返回最后一个app中的那个别名对应的路由。
解决方法1:
在路由分发时,给其定义一个名称空间,在解析时,加上名称空间即可区分:
总路由 url(r'^app01/',include('app01.urls',namespace='app01')) url(r'^app02/',include('app02.urls',namespace='app02'))
后端解析:
reverse('app01:index') reverse('app02:index')
前端解析:
{% url 'app01:index' %} {% url 'app02:index' %}
解决方法2:
在其名字时不要冲突即可,在起别名时通常将app名字加在前面:
name = 'app01_index' name = 'app02_index'
八。伪静态。
静态网页:数据是写死的 万年不变。
伪静态网页的设计是为了增加百度等搜索引擎seo查询力度。
所有的搜索引擎其实都是一个巨大的爬虫程序。
这是一个网站优化相关的知识,通过伪静态确实可以提高你的网站被查询出来的概率,但是再怎么优化也抵不过RMB玩家。
该方法就是在网站后面加(.html)
九。虚拟环境。
一般情况下,每一个项目都会配置本地环境给它,就是装载,相同的模块,就是本地环境。
而每一个项目需要不同的环境运行时,就需要虚拟环境为每个项目配置不同 的环境。
在虚拟环境创建时,会重新下载一个全新的解释器。
十。Django1.x和2.x的区别
路由区别:
路由层1.X用的是url,而2.X用的是path。
2.X中的path第一个参数不再是正则表达式,而是写什么就匹配什么 是精准匹配。
在2.x中也有re_path与url的使用方式一样。
2.x中的re_path就是1.X的url
默认的转换器。
虽然2.x版中path不支持正则表达式,但是它提供了五种默认的转换器。
1.0版本的url和2.0版本的re_path分组出来的数据都是字符串类型。
默认有五个转换器:
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式。
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
用法:
path('index/<int:id>/',index) # 会将id匹配到的内容自动转换成整型
其中id可以传到后端去。
path还支持自定义的转化器:
class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value 占四位,不够用0填满,超了则就按超了的位数来! register_converter(FourDigitYearConverter, 'yyyy') urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<yyyy:year>/', views.year_archive), ... ]
十一。视图层。
1,视图层三个常用的函数:
1.HttpResponse 2.render 3.redirect
django视图函数必须要给返回一个HttpResponse对象。因为其他的方法内部都是返回的HttpResponse。
2.JsonReponse。
JsonReponse函数主要是返回一个json后的对象给前端,需要使用这个函数。
from django.http import JsonResponse def index(request): data = {'name':'名字','password':123} l = [1,2,3,4,5,6,7,8] # res = json.dumps(data,ensure_ascii=False) # return HttpResponse(res) # return JsonResponse(data,json_dumps_params={'ensure_ascii':False}) return JsonResponse(l,safe=False)
# 如果返回的不是字典 只需要修改safe参数为false即可
这个等同于使用json模块转换后使用httpresponse传输。
其中,如果需要传输的数据中有中文,在json中需要加关键字参数:ensure_ascii=False。
在这个模块需要将这个字段作为字典传入,内部会自动解析:
JsonResponse(data,json_dumps_params= {'ensure_ascii':False})
如果要传字典以外的参数,需要将safe参数设置为false。
一般的,在开发者模式中,有前后端分离的开发者模式,需要后端将参数作为字典传给前端供其处理。
补充:
前端处理json数据:
JSON.stringify() json.dumps()
JSON.parse() json.loads()
3.上传文件。
在上传文件时,有些事项需要注意:
1.enctype需要由默认的urlencoded变成formdata。
2.method需要由默认的get变成post。
在后端获取文件时,并不是在POST中获取文件,而是在request.FILES中获取文件。
def down(request): if request.method == 'POST': file_obj = request.FILES.get('my_file') with open(file_obj.name,'wb') as f: for i in file_obj.chunks(): f.write(i) return HttpResponse('收到了') return render(request,'down_load.html')
其中chunks()是将其变成可迭代对象,file也是一个可迭代对象,所以可以不加。
FILES中取值方式和GET中一样,取出列表中的最后一个。
其他request中的参数(部分):
request.method #判断get post request.GET request.POST request.FILES request.path # 只回去url后缀 不获取?后面的参数 request.get_full_path() # 后缀和参数全部获取
request.body #原生的二进制数据
RBAC(role based access control)
基于角色的权限管理。
需要对用户访问的路由进行限制。