Django 中URL和Views相关知识梳理(极简版)

提示:仅供梳理参考,很多相关的细节内容忽略。

1.URL 

(1)URL匹配的规则是正则,关于正则不再赘述。

(2)URL优先级顺序:从urlpatterns的底部开始搜索,一直往上搜索,需要注意的是,并不是一搜到匹配的URL正则式就停止了,而是继续往上搜索,如果上面还有匹配的URL正则,则上面的有效,所以在urlpatterns中写url与views或者include的映射关系时,应该是细分的在上面,比较粗略的正则写下面,但如果采用'^ some RegEx$' 的精确的正则,就不存在优先级的问题。

(3)url带参:通过正则name group实现,比如'^fruit/(?P<fruit_name>[a-zA-Z]+)/',可以获取一个名为'fruit_name'的参数,该参数至少有一个字母,然后传递给相应的view函数,如:

def someMethod(request,fruit_name,extra):  #extra 解释见下面的(4)
    
    #something using fruit_name
    return render(request,'demo.html',context_dict)

  

该函数可以是FVB或者CVB,如果是CVB可直接传递至相应的template模板,如url('^someRegEx$',TemplateView.as_view(template_name='drinks/index.html'))

(4)url的optional extra:例如 url('^someRegEx$',views.someMethod,{'extra':'extra_data'}),最后一项就是optional extra,可选的参数,该参数随url中的参数一起,可以被传入views 中的函数或者CVB指明的模板。

(5)url的name:在映射url和view函数时候,经常带一个name,如 url('^apple/$',views.appleMethod,name='apple'),这里name是为了反向代理,意思就是在html模板中可以使用{% url 'apple' %}来代表硬生生写的 'apple/$'这个url,因为如果^apple/$'变动了,所有含有硬生生写的'apple/$'都要变,非常麻烦。

(6)如果是多个app,则每个app下的name不能一样,因为这样就是多个url对应一个name,反向代理,一个name对应哪个url?不确定。一个粗暴的方法就是每个name都加后缀,但也非常不方便。所以为了可以让每个app下的name 也可以相同,引入了namespace,但namespace必须与include一起使用,所以在reverse或者模板中就可以用“namespace:name"的方法来反向代理url。

(7)【用的情况比较少】如果多个url对应同一个app(必须用多个include+namespace,是使用app_name的前提),需要在该app的url中设置app_name,,这样可以通过app_name:name(该name是该app中urlpatterns中的name)来动态的捕捉到是通过哪个url进入的该app的url。如主urls.py中有


urlpatterns = [ path('admin/', admin.site.urls), url('^coffee-banners/',include('banners.urls',namespace='coffee-banners')), url('^food-banners/',include('banners.urls',namespace='food-banners')) ]

 banners的urls.py为:

app_name='banners_adverts'
urlpatterns=[
    url('^$',views.index,name='index')
]

banners的views.py:

def index(request):
    return render(request,'banners/index.html')

banners的index.html为:

{% extends '../base.html' %}
{% block body_block %}
{% url 'banners_adverts:index' %}
{% endblock %}

 所以当通过/food-banners/进来时,{% url 'banners_adverts:index' %}显示的是/food-banners/如下图:

 当通过/coffee-banners/进来时,{% url 'banners_adverts:index' %}显示的是/coffee-banners/如下图:

 2.view

(1)view method request:是django.http.request.HttpRequest类的实例,在调用view method前,它包含了比如浏览器,Django的middleware类的一些信息。

(a)request.method(b)request.GET, request.POST(c)request.META(d)request.user。详见https://docs.djangoproject.com/en/3.1/ref/request-response/

(2)view method response:详见https://docs.djangoproject.com/en/3.1/ref/request-response/,三种生成view method response的方法,

(a)render(request,'demo.html',context_dict),该方法还有三个可选参数,'content_type',默认为'text/html',‘status'默认为200,'using',要么是'jinja2',要么'django'。(b)TemplateResponse(request,'demo.html',context_value),输入参数与render基本一样,多一个'charset'参数。

(c)

from django.http import HttpResponse
from django.template import loader,Context 
response=HttpResponse()
t=loader.get_template('demo.html')
c=Context(context_dict)
response.write(t.render(c))

 这是最灵活的一种方法,当视图方法的response需要高级选项时,这是一种推荐的方法。

(3)Response 的Status 和 Content-Type选项

(a) status:三位数,表示对给定的request回应的response的回应状态。比如,200是返回成功,404是未找到资源。

(b)Content-type: 是个'MIME(multipurpose Internet Mail Extensions)'的字符串类型,表面在response中的内容的类型,比如,’text/html',是一个标准的response的content type,'image/gif',表明返回的是一个GIF图像。

(c) buit-in response shortcuts and template for common HTTP Status: 404(Not Fount), 500(Internal Server Error), 400(Bad Request), and 403(Forbidden):

当django找不到页面,会自动触发404response,当django view 方法中抛出异常,会自动触发 500 response,但也可以显式地触发这些response,方法如下:

Http status code             python code sample
404                                from django.http import Http404
                                     raise Http404

500                                raise Exception

400                                from django.core.exceptions import SuspiciousOperation
                                      raise SuspiciousOperation

403                                 from django.core.exceptions import PermissionDenied
                                      raise PermissionDenied

 对于404 和500,它们还取决于 settings.py中的DEBUG的值。

也可以用定制的页面覆盖默认的这些错误代码对应的response页面。要创建一个定制的页面,必须建立个以错误代码命名的html文件,比如对于Http403错误,创建403.html放到TEMPLATES列表中的变量DIRS定义的路径下。(再一次注意,404.html和500.html仅在DEBUG=False时有效,因为为True的模式下,是要查找django项目内在的错误,所以提供了默认的带有Exception traceback 的错误页面,来方便调试,寻找错误) ,详见https://i.cnblogs.com/posts/edit-done;postId=13584840

 (d)Buit-in response shortcuts for inline and streamed content

之前所有的response都建立在通过一个template来构建内容的基础上的,然而,还有很多情况,没有必要用template来输出response的内容,比如只需要一行输出'Nothing to see here",还有使用template来输出内容根本就不妥当的情况,比如redirect(Http301,Http302)

另外,比如一些response返回的是其他文本格式,如csv,详细的例子见https://docs.djangoproject.com/en/3.1/howto/outputting-csv/ , 或者pdf (from django.http import FileResponse , return FileResopnse(open('demo.pdf','rb'))).

例:该view 方法的response为下图:

def index(request):
    response=HttpResponse(content_type='text/csv')
    response['Content-Disposition']='attachment;filename=somefile.csv'
    writer=csv.writer(response)
    writer.writerow(['First row','Foo','Bar'])
    writer.writerow(['second row','A','B','C'])
    return response

  

 (d)View method middleware 

在大多数情况下,在request 和response中的数据都在view 方法中被添加,删除,更新,然而有时候需要对所有requests 和response进行一些操作,比如对所有response 进行强制性安全检查。这时候,用middleware就是个比较好的办法。

middleware 是request/response过程中的钩子框架,也就说,从发起request到返回response,request或response都要经历middleware,因此它可以轻松的改变Django 的输入输出,每个middleware 组件都负责一个特定的功能,比如AuthenticationMiddleware,它通过sessions将user和request联结了起来。

 有关其机制的小demo见https://www.cnblogs.com/johnyang/p/13592340.html 

(4)middleware flash messages:

使用条件:settings.py中MIDDLEWARE包含了django.contrib.messages.middleware.MessageMiddleware;INSTALLED_APPS有django.contrib.messages.value,在TEMPLATES的'OPTIONS'下有django.contrib.messages.context_processors.messages

(a)添加flash message

from django.contrib import messages
messages.add_message(request,message.DEBUG,'the following sql statements were executed')

#或者如下方式
messages.debug(request,'The following sql statements were executed')

  需要注意的是,默认情况上面两个会被忽略,因为Django默认处理INFO层以上的信息,所谓层就是不同message对应的value,而DEBUG小于该值,所以默认被忽略,message-->value如下:

DEBUG-->10 (最低);INFO-->20;SUCCESS-->25;WARNING-->30;ERROR-->40(最高);

更改message level:

#globally, settings.py
from django.contrib.messages import constant as message_constants
MESSAGE_LEVEL=message_constants.DEBUG

#set default Djanog message level on a per request basis,in some method defined in views.py
from django.contrib import messages
def index(request):
    messages.set_level(request,messages.SUCCESS)
    messages.add_message(request,messages.INFO,'it is info')
    return render(request,'banners/index.html')

 (b)Access Flash messages

message的属性有'message': message中的实际文本;‘level':数字;’level_tag':字符代表,比如对于INFO,就是'info'。

可通过template来访问:

{% extends '../base.html' %}
{% block body_block %}
<!-- {% url 'banners_adverts:index' %} -->
{% if messages %}
<ul class="messages">
    {% for msg in messages %}
    <li>
        <div class="alert alert-{{msg.level_tag}}" role="alert">
            {{msg.message}}
        </div>
    </li>
    {% endfor %}
</ul>

{% endif %}
{% endblock %}

  其中base.html是带有bootstrap的html,效果如下:

 (5)CBV(class-based-views)

django.views.generic.View:所有其他CBV的父类,若创建一个继承该类的类,则可以自定义get(),post()方法来应对request的get和post方法。

django.views.generic.TemplateView:允许一个url,而不需要一个view方法,当然也可以通过在views.py中创建一个继承该类的类,然后设定类属性template_name,类方法get_context_data。

需要注意的是在urls.py中,都是需要CBV的as_view()方法

##### 愿你一寸一寸地攻城略地,一点一点地焕然一新 #####
原文地址:https://www.cnblogs.com/johnyang/p/13574315.html