day64 url用法以及django的路由系统
此篇博客是以备后查的,用到的时候记得过来查找即可!
路由系统:就是我们的django项目创建的时候自带的那个urls.py
它本身里面是映射的对应关系,一个大的列表里面,一个个元祖,元祖里面是url或者网址,对应一个函数,视图函数(处理业务逻辑)
url配置(URLconf)就像django所支撑的网站目录,它的本质是URL与要为该URL调用的视图函数之间的映射表
就像我们在创建django的时候系统自动生成的那个url.py文件一样,里面的url列表里面我们就是写入了一个个的元祖,然后每一个元祖里面是url地址和与之对应的那个函数名,我们使用这个url的时候就是要执行那个函数,
urlconf配置
基本格式如下:
from django.conf.urls import url urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
] django2.0版本中的路由系统已经替换成了下面的写法:
from django.urls import path urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
] 在web中的参数传递有两种方式,一种是写到类或者是函数的参数中,同时在URL中也显示出来,以‘?xxx=xxx’的方式显示出来,还有一种就是隐性传参的方式,用request.POST/GET.get()的方式获取参数。
跟前端的交互方式也不一样 参数说明:
正则表达式,一个正则表达式字符串,
正则表达式的url匹配模式,我们的正则是有分组的,如果是单纯的分组的话,它的分好的每一个组都是位置参数,我们的位置参数是使用
arg去接收的,
我们的分组是会有分组命名的,那么命好的名字就是关键字参数,我们使用**kwargs来接收2我们的关键字传参
views视图函数,一个可调用对象,通常为一个视图函数或者一个指定视图函数路径的字符串
参数:可选的要传递给视图函数的默认参数(字典形式)
别名:一个可选的name参数 正则表达式详解
基本配置:
我们之前写的那些url映射关系里面,都是写死的,就是一个url我们对应一个视图函数,这样使用起来很不方便,
我们需要进行优化,把他们的规律掌握了之后,在一定范围内都使用一个视图函数,这样就可以极大地提高我们的工作效率了
所以我们需要使用正则来找到他们的规律
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
这里我们使用正则匹配的时候就是按照我们之前所学的那些正则的规则去一一匹配,
这里是没有异议的
注意事项:
- urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
- 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的'r' 是可选的但是建议加上。
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True 分组命名匹配:
我们的上面的正则是无法取到该页面的,需要进行分组来执行才可以得到我们需要的结果,传参数的时候顺序要一一对应,
我们使用的正则是有分组的,每个分组之间用()来分割,
上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。
在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。
(?P<name>pattern) ====>这里面的(?)都是固定格式,P也是固定的,它就是分组命名的关键字,我们的P后面的<>存放我们自定义的分组的名字,
把上面的urlconf使用命名组重写:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
而我们的分组命名匹配写到了我们的url里面,那样我们的url因为分组的原因,仅仅是因为分组加上了括号,意义就大不一样了,它系统识别到了分组就会把分组的每一个组生成一个操作,这个操作就是每一个分组都是一个参数,而且是直接传递过去的参数,一旦我们刷新页面的时候那个生成的分组的参数就自动传递给了后端,而后端没有接收到它的话就会报错,提示你有关键字参数需要传递,而你没有接收它,这就是问题所在,所以我们需要在我们的views函数里面加上参数去接收我们在分组里面的传值操作,
我们的分组里面如果有命名的话,我们命的名字要和我们在views函数里面的接收的参数名保持一致或者我们直接就用到我们的**kwargs,来接收所有传过来的关键字参数,
我们的url配置参数里面的name属性里面的值跟我们在HTML文件里面,form表单里面的action对应的值是有关系的,这里就牵扯到了反向解析的问题,我们为了使用动态的效果,需要使用到反向解析的概念,这里就牵扯到一个命名的问题,我们的命名是不可以出现重复的,但是我们这里可以解决命名重复的问题,那就涉及到命名空间的使用了,我们可以把这些名字都存放于一个空间里面,在这个空间里面我们不使用重复的名字就好,但是超过这个空间的范围我们就可以使用到重复的name值了,
所以我们使用命名空间的话,我们需要在我们的HTML文件里面的action里面加上名称空间的名字,这里使用:进行拼接,我们上面提到的正则分组里面涉及到参数传递的问题,在views函数里面需要有参数传递,在对应的HTML文件里面也需要有参数设定,参数使用我们在分组正则里面命名的那个参数,也是键对值的方式,使用=连接,
还有就是我们的url网址输入的时候,我们需要把我们自己的App里面的那个url地址和我们的django项目里面的url地址拼接到一起,输入到网页的地址栏里面,拼接的时候使用/分割,这样就可得到我们的预期结果了.
1,使用url的时候,注意我们的url地址拼接,在网址栏输入时的地址拼接
2.注意正则匹配的时候我们的分组,以及分组命名,要跟我们的views视图函数以及我们的HTML文件里面的 action对应的值,以及里面的参数配置
urlconf匹配的位置
urlconf在请求的url上查找,将它作为一个普通的python字符串来使用,不包括get和post以及参数和域名
例如一个网址:http://www.example.com/myapp/ 这里面我们的urlconf只查找myapp/
在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/
。 后面的?就是分隔符,我们的请求网址截止到?后面就是参数了,而.com前则是域名,参数和域名我们都是不包括在内的
捕获的参数永远都是字符串,
每个在urlconf中捕获的参数都作为一个普通的python字符串传递个视图,无论正则表达式用什么样的匹配方式得到结果,它的本质是不会变的,都是字符串,
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
传递到视图函数views.year_archive()
中的year
参数永远是一个字符串类型。
我们的url路由配置里面,如果遇到了CBV,类视图函数:
url(r'^login/$',views.LoginView.as_view), # 这里我们解释一下,如果是类视图函数的话,我们的正则匹配的地址后面,要写上我们的类名+View.as_view 这是固定格式,我们的类视图函数需要继承View,必须首字母大写,固定格式.
视图函数中指定默认值:
# urls.py中
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
# views.py中,可以为num指定默认值
def page(request, num="1"):
pass
include其他的urlconfs:
#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.
#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件
]
这里的应用场景是,我们一个项目做成不是基于一个人,而是一整个团队的努力我们的团队里面是有分工合作的,既然牵扯到团队的话,我们需要分工合作,每个人负责不同的部分,一个人负责的片区我们可以把它放到一个类似于口袋的地方,我们一整个项目完成后,再后期需要有更新或者功能的完善等等都需要找到每个人自己负责的部分进行修补或者更新,那么我们就需要找到那个口袋,
而我们的django项目里面的url配置参数里面,使用到include,后面加上括号,在括号里面可以写多个url路由系统参数,[我们的django项目会有很多的app,每个小功能都是存放于app里面的,所以我们的app里面的url配置参数都按照每个人负责的部分来进行划分,放到专属的include里面]这样我们就可以很方便的找到自己负责的部分进行操作了
格式是这样写的:url(r'^who/',include(aps_urls), -------->我们这里的正则who就相当于是前缀,我们需找到这个前缀下面的aps_urls,然后它里面可以写很多的url配置参数,我们在include里面只能够写一个url配置参数,不可以写多个,规则就是这样的,我们要遵守人家的规则,所谓的多个是在aps_urls里面写多个,而不是在include里面
传递额外的参数给视图函数:
URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url()
函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在此例中,对于/blog/2005/请求中,django将调用views.year_archive(request,year="2005",foo="bar"). 这个技术在syndication框架中使用,来传递元数据和选项给视图
命名url和url反向解析[官方翻译版]
在使用django项目是,一个常见的需求是获得url的最终形式,以用于嵌入到生成的内容中,(视图中和显示给用户的内容)或者用于处理服务器端的导航(重定向等).
我们编码这些url费力不可扩展同时还容易产生错误,如果涉及一种与urlconf不相关的专门的URL生成机制,因为这样容易导致一定程度上产生过期的url
本质上是需要一个DRY机制,它允许设计的url可以自动更新而不用遍历项目的源代码,来搜索并替换过期的url,获取一个url最开始想到的是信息处理它视图的标识,查找正确的url的其他必要的信息有视图参数的类型(位置参数,关键字参数)和值,django提供一个办法是让url映射是url设计唯一的地方,你填充你的urlconf,然后可以双向使用它:
根据用户浏览器发起的url请求,它调用正确的django视图,并从url中提取它的参数需要的值,
根据django视图的标识和将要传递给他的参数的值,获取与之关联的url.
第一种方式是我们在前面的章节中一直讨论的用法,第二种方式叫做反向解析url反向url匹配,反向url查询或者简单的url反查,
在模板中,使用url模板标签
在python代码中使用django.core.urlresolvers.reverse()函数.
在高层的与处理django模型实例相关的代码中,使用get_absolute_url()方法,
=========================================================================
简单来说就是给我们的url匹配规则起个名字,一个url匹配模式起一个名字,这样我们以后就不需要写死url代码了,只需要通过名字来调用当前的url,
例如:
url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home
url(r'^index/(\d*)', views.index, name='index'), # 给我的url匹配模式起名为index 然后在HTML模板里面就这样引用:{% url'home' %}
在views函数中可以这样引用:
from django.urls import reverse
reverse("index", args=("2018", )) 考虑下面的urlconf:
from django.conf.urls import url
from . import views
urlpatterns =[
# ...
url(r"^articles/([0-9]{4})/$", views.year_archive, name="news-year-archive'),
#... 根据这里的设计,某一年nnnn对应的归档的url是/articles/nnnn/
你可以在这里的模板的代码中使用下面的方法获取他们:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
在python代码中可以这样使用
from django.urls import reverse
from django.shortcuts import redirect
def redirect_to_year(request):
#...
year = 2005
#...
return redirect(reverse('news-year-archive', args=(year,)))
如果处于某种原因决定按年归档文章发布的url应该调整一下,那么你将只需要修改urlconf中的内容,在某些场景中,一个仕途上hi通用的,所以在url和视图之间存在多对一的关系,对于这些情况,当反查url时,只有视图的名字还不够,
注意:
为了完成上面例子中的url反查,你将需要使用命名的url模式,url的名称使用的字符串可以包含任何你喜欢的字符,不只限制在合法的python名称,当命名你的url模式时,请确保使用的名称不会与其他的应用中名称冲突,如果你的url模式叫做comment而另外一个应用中也有一个同样的名称,当你在模板中国使用这个名称的时候不能保证将插入哪个url.
在url名称中加上一个前缀,比如应用的名称,将减少冲突的可能,我们建议使用myapp-comment而不是commet
Django-2.0命名空间模式更新语法
project中的urls.py
from django.conf.urls import url, include
# 官网上的例子
# 这是跟setting文件同级目录的url文件
urls.py
from django.urls import include, path urlpatterns = [
path('author-polls/', include('polls.urls', namespace='author-polls')), # 这里的路由随意设定,include中的第一个参数必须要是app的名字.urls,第二个参数也随意设定。
path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
] # 这是app下的URL文件,
polls/urls.py
from django.urls import path from . import views
# 下面这一行是必须加上的,要有参数“app_name”,参数值建议写app的名字(当然了,你硬是要瞎写个别的乱字符串,也不会报错,只要不是空字符串就行),否则会报错
“”“
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name
attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
”“”
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
...
]
模板中引用:
{% url'app01:detail' pk=12 pp=99 %}
views中的函数引用
v=reverse('app01:detail', kwargs={'pk':11})
==================================================================================================================================================我们之前写的那些django项目里面,学生,班级,老师的管理系统,统统都是不规范的,那样写仅仅是为了便于我们去理解,其实是有很多的问题的,虽然我们已经理解了,然后还都实现了那些功能,感觉还挺开心的,
======================================================================================================
我们这里把url路由配置和视图的知识点结合着一起整理到一块,这样便于记忆
现在我们需要把那些都推翻了,然后以一种更加规范更加合理的方式去写出来,我们一般的项目都没有直接写到我们的django 项目里面的,都是写到Django项目下面的app里面的,我们的templates是在创建django项目的时候就要自己手动创建好的,用于存放我们的HTML页面,然后我们创建的那些app就需要根据app的名字把对应的需要用到的那些HTML文件归类存放,用起来的时候会方便很多,我们命名的时候可以随意起名,只要你知道你用的时候去哪里找就行,但是为了方便起见一般会给app所对应的那个templates里面的内层文件夹起同样的名字,跟我们的App的名字一样,然后我们在views里面写视图函数的时候在return部分要渲染HTML页面,那个页面我们可以就像之前一样直接写HTML的名字,你在运行项目的时候pycharm会自动给你把HTML页面的前缀加上的,如果我们的templates下面的App对应的文件夹名字有变动的话,pycharm也会自动给你把views视图里面的return后面的渲染页面给你自动变更下面有截图为例:
我们以后不一定就是使用pycharm写项目,有可能是用其他的软件去写项目,所以我们最好是知道这一点然后养成习惯把它加上,毕竟系统是需要这个东西的,不然也不会给你自动增加上
视图:
我们的路由配置里面(urls.py文件即是)一个url网址对应一个视图函数,我们的url网址一旦有一丁点的改动都无法执行视图函数,有一个举例的场景里面,我们的博客管理系统,我们前面的学生老师班级信息显示内容都是从数据库里面取出数据然后把他们提交到前端页面,这样的话我们的博客如果数据量巨大的话,我们需要写海量的复用性极高的代码,这样显然是不科学的,在正常的工作环境中是不可能出现这样的情况,所以我们不能够这样写
首先我们需要解决url配置的问题,使用正则的话就可以把含有一定规律的url都概括到这样一个正则里面,我们只要满足这个正则的要求,就可以正常执行那个url所对应的视图函数,
如下所示:
urlpatterns=[
url(r'^text/$', views.text, name='text'), # FBV方式 F(function,函数)----B(base,基于)-----V(views, 视图)======>基于函数的视图
我们在这里解释一下这个url路由配置的意思,我们之前写的例子里面就是一个url对应一个视图函数,我们的r后面是自定义的url网址,后面的views是我们的App里面的views,我们的项目视图函数都是写到views里面的,他就是一个路径的意思,我们之前直接写到django项目里的时候就是直接把视图函数里面的函数名写到这里的,我们有App之后就需要把路径指定一下,在函数名前面加上App的views路径,,后面的name才是关键的重点,我们的HTML页面里面的acion里面跳转的页面就是使用的name里面的值,就是我们这里的路由配置里面的name里面的值下面有图,会更易理解一些
]
上面使用的是FBV,
在视图里面还有一个CBV,我们这里来详解一下,C--class(类)B---base(基于),V---views(视图)====>基于类的视图
首先在url配置里面,我们来看一下它是怎么配置的
urlpatterns=[
url(r'^tes/$', aps.Tex.as_view(), name='tet'), # 这里的as_view() 是对于请求做出判断,判断请求是什么方式,它本质就是对于发送过来的请求进行判断,我们的应用场景是在CBV里面,因为C是class是类,类里面会有很多的方法,我们要在拿到这个请求的时候在这里对其进行判断,判断是什么方式然后使用相应的类里面的相应的方法,而我们在FBV里面是不需要使用这一层判断的,我们的FBV里面只有一个方法,没得选,我们定义的是什么函数就使用什么函数方法去操作我们的请求,没有选择的余地也不需要选择.
] # 前面是正则匹配,后面是从app文件路径里找到函数名,然后后面加上as_view(),这里是CBV里具有的特殊用法,后面的name就是我们上面所写的方法一样的,关联我们的form表单里面的action,动态改变网址
如图所示:
分组匹配就不多赘述了,上面有详解,本身也不是多难的概念
include
还有一个命名空间,以防止命名重复的问题,我们在url里面写的name的值是不能够重复的,除非我们可以把他们归纳到一个小范围里面,就相当于我们的一个一个小组,这个小组里面可以有一个人叫a,但是不能够在这个组里有重名的,我们有另外一个小组,那个小组里面有一个人叫a,这样的情况就可以,但是我们的同一个小组里面不能够有重复的人叫a,这样的话我们就可以有重复的名字了,至少在大范围内是可以有重复的
然后我们再反向解析,我们上面一直在重复一件事,就是我们的url里面的那个name所对应的值是我们的HTML里面的form表单里面action所对应的那个需要跳转的页面,那个页面我是写成了动态的,我们的name是一个总称,是我们的url路由系统里面正则的总称,把它放到我们action里面之后,我们拿到这个name就可以去找到我们的正则里面的真实的地址,这里就是反向解析,也就是说我们name的值跟action值所对应的这段关系就是反向解析的过程
day64 url用法以及django的路由系统的更多相关文章
- python 之 Django框架(路由系统、include、命名URL和URL反向解析、命名空间模式)
12.36 Django的路由系统 基本格式: from django.conf.urls import url urlpatterns = [ url(正则表达式, views视图函数,参数,别名) ...
- Python学习(三十一)—— Django之路由系统
转载自:http://www.cnblogs.com/liwenzhou/p/8271147.html Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLc ...
- Django之路由系统 Dj
Django之路由系统 Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调 ...
- Django框架----路由系统(详细)
Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表. ...
- Django之 路由系统
Django的路由系统 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于这个URL调用这 ...
- Django 基础 路由系统
Django框架简介 MVC框架和MTV框架(了解即可) MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图 ...
- Django 的 路由系统
Django 的路由系统 URL 配置(URLconf)就像Django 锁支撑网站的目录. 它的本质就是URL 与要为该URL 调用的视图函数之间的映射表. 你就是以这种方式告诉Django, 对于 ...
- 6月19日 python学习总结 Django之路由系统
Django之路由系统 Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调 ...
- Django 的路由系统
Django 的路由系统 Django 的路由系统 路由层 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$',views.ho ...
随机推荐
- Spring Boot (一): Spring Boot starter自定义
前些日子在公司接触了spring boot和spring cloud,有感于其大大简化了spring的配置过程,十分方便使用者快速构建项目,而且拥有丰富的starter供开发者使用.但是由于其自动化配 ...
- Tornado学习笔记(二) 路由/post/get传参
本章我们学习 Tornado 的路由传参等问题 路由 路由的匹配 Tornado的路由匹配采用的是正则匹配 一般情况下不需要多复杂的正则,正则的基本规则如下(站长之家) 举个例子 (r'/sum/(\ ...
- 弃 Java 而使用 Kotlin 的你后悔了吗?| kotlin将会是最好的开发语言
自从 2011 年发布以来,Kotlin 凭借强大的功能在开发者中的欢迎程度与日俱增.且在一年前,Google 宣布 Kotlin 正式成为 Android 官方开发语言,由此引发了从 Java 迁移 ...
- iOS -- Effective Objective-C 阅读笔记 (2)
1: 多用类型常量, 少用 #define 预处理指令 #define 预处理指令会把碰到的所有 指定名称 一律换位 定义的内容, 这样的话, 假设此指令在某个头文件中, 那么所有引入这个头文件的代码 ...
- Confluence 6 基于 Confluence 数据中心的 SAML 单点登录
安全申明标记语言(Security Assertion Markup Language (SAML))是一个基于 XML 的数据格式,允许各个软件平台通过identity provider (IdP) ...
- 基于Web的漏洞利用
1.Nikto 基于Web的漏洞信息扫描 nikto 自动扫描web服务器上没有打补丁的软件,同时同时也检测驻留在服务器上的危险文件,nikto能够识别出特定的问题,检测服务器的配置问题, 检测某台主 ...
- bzoj 1856
做这题之前先看道高考真题(好像是真题,我记不清了) 例:已知一个由n个0和n个1排列而成的数列,要求对于任意k∈N*且k∈[1,2n],在前k个数中1的个数不少于0的个数,求当n=4时这样的数列的数量 ...
- Ubuntu 更改屏幕分辨率
安装完Ubuntu后发现分辨率不合适,平时习惯了看小一点的文字,所以搜了一下修改屏幕分辨率的命令,具体操作如下: 1.先用 xrandr 命令查看一下当前系统支持的分辨率 wayde@wayde-Al ...
- oracle 备份脚本
本文是一个shell脚本.主要用于Oracle 数据库备份.默认情况下,在周一晚上进行全备.其他时间进行累积增量备份. 使用方法: 假如脚本保存名为: oracle_backup.sh 使用方法为 o ...
- 目标检测算法SSD之训练自己的数据集
目标检测算法SSD之训练自己的数据集 prerequesties 预备知识/前提条件 下载和配置了最新SSD代码 git clone https://github.com/weiliu89/caffe ...