zoukankan      html  css  js  c++  java
  • 9_17 django数据库表关联,路由和视图

    一。数据库的关系建立。

      在原生的数据库语句中,建立表与表之间的联系,就是添加一个字段,将联系的表的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)

        基于角色的权限管理。

        需要对用户访问的路由进行限制。

  • 相关阅读:
    Windows安装使用wget
    Ubuntu16.04 安装和卸载MySQL数据库
    申请百度翻译API
    Linux配置JDK
    vmware的三种网络连接模式
    3、linux-目录管理:mkdir、rmdir、mv
    2、linux-添加组groupadd、修改组groupmod、删除组groupdel
    1、linux-用户管理useradd,usermod,userdel
    在Linux操作系统里有Ext2、Ext3、Linux swap和VFAT四种格式
    第四次作业 简易计算器
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11537821.html
Copyright © 2011-2022 走看看