Django第一个项目以及URL学习
一、创建第一个Django项目
使用命令行的方式创建
1、创建项目,打开终端,使用命令:django-admin startproject [项目名称] 即可创建。比如:django-admin startproject first_project。
2、创建应用(app):一个项目类似于一个架子,但真正起作用的还是app。在终端进入到项目所在的路径,然后执行python manage.py startapp [项目名称]创建一个app。
第一个Django程序的结构
运行项目
先进入项目中,然后执行python manage.py runserver
然后在浏览器中访问http://127.0.0.1:8000/
项目就成功运行起来了。
Ctrl+Fn+Pause即可退出程序
使用pycharm的方式创建
选择django,指定项目所在路径、以及python解释器,再点击Create即可创建项目。
pycharm创建的文件结构
运行程序
用pycharm运行项目,需要避免一个项目运行多次。
二、指定端口号和IP地址进行访问
python manage.py runserver 端口号
可以通过9000端口号访问网页
使用pycharm访问
访问网页
如果使用其他设备访问本设备的Django项目,需要在settings ALLOWED_HOSTS中放开其他设备的IP地址,关闭防火墙。
在windows主机上安装openssh
使用 PowerShell 安装 OpenSSH
若要使用 PowerShell 安装 OpenSSH,请先以管理员身份运行 PowerShell(win+x快捷键进行打开)。 为了确保 OpenSSH 可用,请运行以下 cmdlet:
1 | Get - WindowsCapability - Online | Where - Object Name - like 'OpenSSH*' |
如果两者均尚未安装,则此操作应返回以下输出:
1 2 3 4 5 | Name : OpenSSH.Client~~~~ 0.0 . 1.0 State : NotPresent Name : OpenSSH.Server~~~~ 0.0 . 1.0 State : NotPresent |
然后,根据需要安装服务器或客户端组件:
1 2 3 4 5 | # Install the OpenSSH Client Add - WindowsCapability - Online - Name OpenSSH.Client~~~~ 0.0 . 1.0 # Install the OpenSSH Server Add - WindowsCapability - Online - Name OpenSSH.Server~~~~ 0.0 . 1.0 |
这两者应该都会返回以下输出:
1 2 3 | Path : Online : True RestartNeeded : False |
启动并配置 OpenSSH 服务器
若要启动并配置 OpenSSH 服务器来开启使用,请以管理员身份打开 PowerShell,然后运行以下命令来启动 sshd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | service: # Start the sshd service Start - Service sshd # OPTIONAL but recommended: Set - Service - Name sshd - StartupType 'Automatic' # Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify if (!(Get - NetFirewallRule - Name "OpenSSH-Server-In-TCP" - ErrorAction SilentlyContinue | Select - Object Name, Enabled)) { Write - Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..." New - NetFirewallRule - Name 'OpenSSH-Server-In-TCP' - DisplayName 'OpenSSH Server (sshd)' - Enabled True - Direction Inbound - Protocol TCP - Action Allow - LocalPort 22 } else { Write - Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists." |
这样Linux可以通过22端口号访问windows
三、Django项目结构
1、manage.py 以后和项目交互基本上都是基于这个文件。一般都是在终端输入python manage.py[子命令],可以输入python manage.py help看下帮助
2、settings.py 项目的设置项,以后所有和项目相关的配置都是放在这个里面
3、urls.py 这个文件是用来配置URL路由的。比如访问http://127.0.0.1/news/ 是访问新闻列表页,这些配置需要再这个文件中完成。
4、wsgi.py 项目与WSGI协议兼容的web服务器的入口,部署的时候需要用到,一般情况下不需要修改。
四、Url与视图函数的映射
将生成的django项目中的url.py更改为如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from django.contrib import admin from django.urls import path from django.http import HttpResponse def index(request): return HttpResponse( "首页" ) def movie(request): return HttpResponse( '电影' ) def book(request): return HttpResponse( '书籍' ) urlpatterns = [ path( "admin/" , admin.site.urls), # http://127.0.0.1:8000 path('', index), path( 'movie/' , movie), path( 'book/' , book), ] |
如果改变返回首页为HttpResponse("首页")
返回电影页
返回书籍页
重构程序结构,生成book、movie package包,分割业务
将原始urls.py业务分割至book包和movie包中
urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.urls import path from django.http import HttpResponse from book.views import book from movie.views import movie def index(request): return HttpResponse( "首页" ) urlpatterns = [ path( "admin/" , admin.site.urls), # http://127.0.0.1:8000 path('', index), path( 'movie/' , movie), path( 'book/' , book), ] |
book.views.py
1 2 3 4 | from django.http import HttpResponse def book(request): return HttpResponse( '书籍' ) |
movie.views.py
1 2 3 4 | from django.http import HttpResponse def movie(request): return HttpResponse( '电影' ) |
新建书籍模型book models和电影模型movie models
如果处理表单验证类的可以新建两个forms.py
已经被安装的app
使用命令行创建app python manage.py startapp [app的名称]
可以看到django_001中多出了city app
五、Debug模式详解
开启debug模式的代码
开启debug模式的好处
1、如果开启了DEBUG模式,那么以后我们修改了Django项目的代码,然后按下Ctrl+S,那么Django就会自动给我们重启项目,不需要手动重启。
2、如果开启了DEBUG模式,那么如果以后Django项目中的代码中出现bug了,那么浏览器中和控制台会打印出错信息。
views.py
1 2 3 4 5 6 7 | from django.http import HttpResponse def book(request): a = 1 b = 0 c = a / b return HttpResponse( '书籍' ) |
3、在生产环境中,禁止开启DEBUG模式,不然有很大的安全隐患
4、如果关闭DEBUG模式,将DEBUG设置为False。必须要设置ALLOWED_HOSTS是用来设置以后通过这个变量中的IP地址和域名来进行访问。
如果不设置会产生错误:
将Run-configurations改为0.0.0.0
添加ALLOWED_HOSTS,以后访问必须通过ALLOWED_HOSTS中的IP地址进行访问,其他地址不允许
访问 http://本机IP:8000/
六、URL分发器
视图
视图一般都写在app的view.py中,并且视图的第一个参数永远都是request(一个HttpRequest)对象。这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息等。在视图中,一般是完成逻辑相关的操作。比如这个请求是添加一篇博客,那么可以通过request来接收到这些数据,然后存储到数据库中,最后再把执行的结果返回给浏览器。视图函数的返回结果必须是"django.http.HttpRespoonseBase"对象或者子类的对象。视图函数的第一个参数必须是request,这个参数不能少。示例代码如下:
使用python manage.py startapp books先生成books项目
books.views.py
1 2 3 4 | from django.http import HttpResponse # Create your views here. def books(request): return (HttpResponse( '图书首页' )) |
urls.py
1 2 3 4 5 6 7 8 9 10 | from django.contrib import admin from django.urls import path from books.views import books urlpatterns = [ path( 'admin/' , admin.site.urls), # http://127.0.0.1:8000 path('', index), path( 'books/' , books), ] |
程序结构:
运行返回结果:
七、URL映射
视图写完后,需要与URL进行映射,也即用户在浏览器中输入什么URL的时候可以请求到这个视图函数,在用户输入了某个url,请求到我们的网站的时候,django会从项目的urls.py文件中寻找对应的视图。在urls.py文件中有一个urlpatterns变量,以后django就会从这个变量中读取所有的匹配规则。匹配规则需要使用django.urls.path函数进行包裹,这个函数会根据传入的参数返回URLPattern或者是URLResolver的对象。示例代码如下:
1 2 3 4 5 6 7 8 | from django.contrib import admin from django.urls import path from books.views import books urlpatterns = [ path( 'admin/' , admin.site.urls), path( 'books/' , books), ] |
1、由于在settings.py中指定了ROOT_URLCONF为“django_001.urls“,所以去urls.py寻找映射。
2、在urls.py中我们所有的映射,都应该放在urlpatterns变量中,django会固定去urlpatterns去寻找映射路径。
3、所有的映射都是使用path函数或者是re_path函数进行包装。
URL传递参数给视图函数
新建一个django_002项目2,并加入book app
book.views.py
1 2 3 4 5 6 7 8 9 | from django.http import HttpResponse # Create your views here. def book(requests): return HttpResponse( "图书首页" ) def book_detail(requests,book_id): #可以从数据库中根据book_id提取这个图书的信息 text = "您获取的图书id是%s" % book_id return HttpResponse(text) |
django_002.urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/" ,views.book_detail) ] |
django_002.urls.py的映射参数的book_id与book.views.py中book_detail函数的参数book_id名称需要一致。
访问http://127.0.0.1:8000/book/detail/565/
访问http://127.0.0.1:8000/book/
修改为多个参数
book.views.py
1 2 3 4 5 6 7 8 9 | from django.http import HttpResponse # Create your views here. def book(requests): return HttpResponse( "图书首页" ) def book_detail(requests,book_id,book_category): #可以从数据库中根据book_id提取这个图书的信息 text = "您获取的图书id是%s图书分类是%s" % (book_id,book_category) return HttpResponse(text) |
django_002.urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail) ] |
运行结果:
Url传参数
1、采用url中使用变量的方式,在path的第一个参数中,使用'<参数名>'的方式可以传递参数,然后在视图函数中也要写一个参数,视图参数中的参数必须和url中的参数名称保持一致,不然就找不到这个参数。另外,url中可以传递多个参数
2、可以采用查询字符串的方式:在url中,不需要单独的匹配查询字符串的部分,只需要在视图函数中使用"request.GET.get('参数名称')"的方式来获取。
采用查询字符串传参
book.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from django.http import HttpResponse # Create your views here. def book(requests): return HttpResponse( "图书首页" ) def book_detail(requests,book_id,book_category): #可以从数据库中根据book_id提取这个图书的信息 text = "您获取的图书id是%s图书分类是%s" % (book_id,book_category) return HttpResponse(text) def author_detail(requests): author_id = requests.GET.get( 'id' ) text = "作者的id是:%s" % author_id return HttpResponse(text) |
django_002.urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail) ] |
输出结果:http://localhost:8000/book/author/?id=1
八、Path函数
path函数定义为:path(route,view,name=None,kwargs=None),以下对这几个参数进行讲解。
1、route参数:url的匹配规则,这个参数中可以指定url中需要传递的参数,比如在访问文章详情页的时候,可以传递一个id。传递参数是通过<>尖括号来进行指定的。并且在传递参数的时候,可以指定这个参数的数据类型,比如文章的id都是int类型,那么可以这样写<int id>,以后匹配的时候,就只会匹配id为int类型的url,而不会匹配其他的url,并且在视图函数中获取这个参数的时候,就已经被转换为一个int类型了。还有几种常用的类型:
- str:非空的字符串类型。默认的转换器,但是不能包含斜杠/
- int:匹配任意的0或者正数的整型。到视图函数中就是一个int类型。
- slug:由英文中的横杠-或者下划线_连接英文字符或者数字组成的字符串。
- uuid:匹配uuid字符串
- path:匹配非空的英文字符串,可以包含斜杠
这些都是类型转换器可以转换的类型
类型转换器覆盖类型
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from django.http import HttpResponse # Create your views here. def book(requests): return HttpResponse( "图书首页" ) def book_detail(requests,book_id,book_category): #可以从数据库中根据book_id提取这个图书的信息 text = "您获取的图书id是%s图书分类是%s" % (book_id,book_category) return HttpResponse(text) def author_detail(requests): author_id = requests.GET.get( 'author_id' ) text = "作者的id是:%s" % author_id return HttpResponse(text) def publisher_detail(requests,publisher_id): text = '出版社的id是::%s' % publisher_id return HttpResponse(text) |
urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail), path( "book/publisher_detail/<int:publisher_id>" ,views.publisher_detail) ] |
运行结果:
如果更改为字符串转换器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views from django.urls import converters def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail), path( "book/publisher_detail/<str:publisher_id>" ,views.publisher_detail) ] |
运行结果:
默认为str字符串转换器。字符串转换器不可识别/
如果更改为UUID类型
先生成一个UUID
1 2 | >>> import uuid >>> print (uuid.uuid4()) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views from django.urls import converters def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail), path( "book/publisher_detail/<uuid:publisher_id>" ,views.publisher_detail) ] |
输出结果为:
如果更改为slug类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views from django.urls import converters def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail), path( "book/publisher_detail/<slug:publisher_id>" ,views.publisher_detail) ] |
输出结果为:
如果更改为path类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.contrib import admin from django.http import HttpResponse from django.urls import path from book import views from django.urls import converters def index(request): return HttpResponse( "Hello, world. You're at the book index." ) urlpatterns = [ path( "admin/" , admin.site.urls), path("", index), path( "book/" , views.book), # /book/detail/1 path( "book/detail/<book_id>/<book_category>" ,views.book_detail), path( "book/author/" ,views.author_detail), path( "book/publisher_detail/<path:publisher_id>" ,views.publisher_detail) ] |
输出结果为:
2、view参数:可以为一个视图参数或者类视图.as_view()或者是django.urls.include()函数的返回值。
3、name参数:这个参数是给这个url取个名字的,这在项目比较大,url比较多的时候用处很大
4、kwargs参数:有时候想给视图参数函数传递一些额外的参数,就可以通过kwargs参数进行传递。这个参数接收一个字典,传到视图函数中的时候,回座位一个关键字参数传过去。
九、URL模块化
在项目中,不可能只有一个app,如果把所有的views中的视图都放在urls.py中进行映射,肯定会让代码显得非常乱。因此django给我们提供了一个方法,可以在app内部包含自己的url的匹配规则,而在项目的urls.py中再统一包含这个app的urls。使用这个技术需要include函数。示例如下:
首先新建一个项目Django_003 djangoProject
在项目中加入book模块
在book中新建一个urls.py
1 2 3 4 5 6 7 8 | from django.urls import path from . import views urlpatterns = [ path("", views.book), path( "detail/<book_id>/" , views.book_detail), path( "book_list/" , views.book_list), ] |
book中的views.py
1 2 3 4 5 6 7 8 9 10 11 12 | from django.http import HttpResponse # Create your views here. def book(request): return HttpResponse( "图书首页" ) def book_detail(request,book_id): text = '图书的id是%s' % book_id return HttpResponse(text) def book_list(request): return HttpResponse( "图书列表页面" ) |
djangoProject中的urls.py文件
1 2 3 4 5 6 7 8 9 | from django.contrib import admin from django.urls import path,include from book import views urlpatterns = [ path( "admin/" , admin.site.urls), path( "book/" , include( 'book.urls' )), ] |
访问的url相当于djangoProject中的urls与books中的urls进行一个拼接,include使用的是相对于项目的路径。
运行如下:
url模块化:
如果项目变得越来越大,那么url会变得越来越多,如果都放在"urls.py"文件中,那么将不太好管理,因此我们可以将每个app自己的urls放到自己的app中进行管理。一般我们会在app中新建一个urls.py文件用来存储所有和这个app相关的子url。
需要注意的地方:
1、应该使用"include"函数包含"urls.py",并且这个"urls.py"的路径相对于项目的路径。
2、在'app'的'urls.py'中,所有的url匹配也要放在一个叫做'urlpattern'的变量中,否则找不到
3、'url'是会根据主'urls.py'和app中的'urls.py'进行拼接的,因此注意不要多加斜杠。
十、url命名
在pycharm中新建一个url_name_demo的项目
设置它的work interpreter
创建两个app front用来管理前台相关的代码,cms用来管理后台相关的代码
项目结构
分别在front模块和cms模块加入views.py视图
front.views.py
在front.views.py加判断获取用户名,如果非空返回首页,否则返回front登录页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.http import HttpResponse from django.shortcuts import redirect # Create your views here. def index(request): #先判断是否有username username = request.GET.get( 'username' ) if username: return HttpResponse( "front首页%s" % username) else : return redirect( '/login/' ) def login(request): return HttpResponse( "front登录页面" ) |
cms.views.py
1 2 3 4 5 6 7 | from django.http import HttpResponse # Create your views here. def index(request): return HttpResponse( "CMS首页" ) def login(request): return HttpResponse( "CMS登录页面" ) |
分别在front模块、cms模块、url_name_demo中加入urls.py
front.urls.py
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path('', views.index), path( 'login/' ,views.login) ] |
cms.urls.py
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path('', views.index), path( 'login/' ,views.login) ] |
url_name_demo.urls.py
1 2 3 4 5 6 7 8 | from django.contrib import admin from django.urls import path, include urlpatterns = [ path( "admin/" , admin.site.urls), path(' ', include(' front.urls')), path( 'cms/' , include( 'cms.urls' )), ] |
运行结果:
不加参数访问时
加参数访问时
反转url
front.view.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django.http import HttpResponse from django.shortcuts import redirect,reverse # Create your views here. def index(request): #先判断是否有username username = request.GET.get( 'username' ) if username: return HttpResponse( "front首页%s" % username) else : login_url = reverse( 'siginin' ) print (login_url) return redirect(login_url) def login(request): return HttpResponse( "front登录页面" ) |
front.urls.py
这里的siginin url会反转为login登录跳转至login中
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path(' ', views.index,name=' index'), path( 'siginin/' ,views.login,name = 'login' ), ] |
CMS.urls.py
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path('', views.index), path( 'login/' ,views.login) ] |
CMS.views.py
1 2 3 4 5 6 7 | from django.http import HttpResponse # Create your views here. def index(request): return HttpResponse( "CMS首页" ) def login(request): return HttpResponse( "CMS登录页面" ) |
url_name_demo.urls.py
1 2 3 4 5 6 7 8 | from django.contrib import admin from django.urls import path, include urlpatterns = [ path( "admin/" , admin.site.urls), path(' ', include(' front.urls')), path( 'cms/' , include( 'cms.urls' )), ] |
运行结果如下:
1、为什么需要给url命名?
因为url是需要经常变化的,如果在代码中写死可能会经常改代码,给url取个名字,以后使用url的时候就是用其名字反转即可。
2、如何给一个url指定名称
1 2 3 4 | urlpatterns = [ path(' ', views.index,name=' index'), path( 'siginin/' ,views.login,name = 'login' ), ] |
十一、命名空间
当不指定命名空间时,如果不同模块取名相同,会跳转错误的链接,如下
CMS.urls.py
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
CMS.views.py
1 2 3 4 5 6 7 | from django.http import HttpResponse # Create your views here. def index(request): return HttpResponse( "CMS首页" ) def login(request): return HttpResponse( "CMS登录页面" ) |
front.urls.py
1 2 3 4 5 6 7 | from . import views from django.urls import path urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
front.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django.http import HttpResponse from django.shortcuts import redirect,reverse # Create your views here. def index(request): #先判断是否有username username = request.GET.get( 'username' ) if username: return HttpResponse( "front首页%s" % username) else : login_url = reverse( 'login' ) print (login_url) return redirect(login_url) def login(request): return HttpResponse( "front登录页面" ) |
url_name_demo.urls.py
1 2 3 4 5 6 7 8 | from django.contrib import admin from django.urls import path, include urlpatterns = [ path( "admin/" , admin.site.urls), path(' ', include(' front.urls')), path( 'cms/' , include( 'cms.urls' )), ] |
当直接访问localhost:8000时,会自动跳转至CMS登录界面,但是我们希望的是跳转至front/login中
需要使用应用命名空间
改写front.urls
1 2 3 4 5 6 7 8 | from . import views from django.urls import path app_name = 'front' urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
改写cms.urls
1 2 3 4 5 6 7 8 | from . import views from django.urls import path app_name = 'cms' urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
改写front.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django.http import HttpResponse from django.shortcuts import redirect,reverse # Create your views here. def index(request): #先判断是否有username username = request.GET.get( 'username' ) if username: return HttpResponse( "front首页%s" % username) else : login_url = reverse( 'front:login' ) print (login_url) return redirect(login_url) def login(request): return HttpResponse( "front登录页面" ) |
此时可以正确的跳转到front login url
应用命名空间:在多个app之间,有可能产生同名的url,这时候为了避免反转url的时候产生混淆,可以使用应用命名空间做区分。定义应用命名空间非常简单,只要在'app'的urls.py中定义app_name即可。以后在做反转时可以使用“应用命名空间:url名称”的方式可以进行反转。
应用(app)命名空间和实例命名空间:
一个app,可以创建多个实例,可以使用多个url映射同一个app,所以这就会产生一个问题,以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆,为了避免这个问题,我们可以使用实例命名空间,实例命名空间只需要在"include"函数中传递一个"namespace"变量即可。
url_name_demo.urls.py
1 2 3 4 5 6 7 8 9 | from django.contrib import admin from django.urls import path, include urlpatterns = [ path( "admin/" , admin.site.urls), path(' ', include(' front.urls')), path( 'cms1/' , include( 'cms.urls' ,namespace = 'cms1' )), path( 'cms2/' , include( 'cms.urls' ,namespace = 'cms2' )), ] |
CMS.urls.py
1 2 3 4 5 6 7 8 | from . import views from django.urls import path app_name = 'cms' urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
以后在做反转的时候可以根据实例命名空间来指定具体的url,示例代码如下:
CMS.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.http import HttpResponse from django.shortcuts import redirect from django.urls import reverse # Create your views here. def index(request): username = request.GET.get( 'username' ) if username: return HttpResponse( 'CMS首页, %s!' % username) else : current_namespace = request.resolver_match.namespace return redirect(reverse( "%s:login" % current_namespace)) def login(request): return HttpResponse( "CMS登录页面" ) |
front.urls.py
1 2 3 4 5 6 7 8 | from . import views from django.urls import path app_name = 'front' urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
front.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django.http import HttpResponse from django.shortcuts import redirect,reverse # Create your views here. def index(request): #先判断是否有username username = request.GET.get( 'username' ) if username: return HttpResponse( "front首页%s" % username) else : login_url = reverse( 'front:login' ) print (login_url) return redirect(login_url) def login(request): return HttpResponse( "front登录页面" ) |
此时可以实现多url单映射场景
十二、include()函数详解
include函数的三种用法
1、include(module,namespace=None)
module:子url的模块字符串
namespace:实例命名空间,这个地方需要注意一点,如果指定实例命名空间,那么前提必须要先指定应用命名空间,也就是在子"urls.py"中添加"app_name"这个变量。
2、include(pattern_list)
include可以指定列表的形式,pattern_list是一个列表,这个列表中装的是'path'或者're_path'函数。
3、include(pattern_list,app_namespace,namespace=None)
函数的第一个参数既可以为一个字符串,也可以是一个元组,如果是一个元组,那么元组的第一个参数是子'urls.py'模块的字符串,也可以为一个元组,那么元组的第一个参数是子'urls.py'模块的字符串,元组的第二个参数是应用命名空间,也就是说,应用命名空间既可以在子'urls.py'中通过'app_name'指定,也可以在'include'函数中指定。
1、include(module,namespace=None)
需要指定应用命名空间之后在指定实例命名空间,如果只指定实例命名空间不指定应用命名空间会报错。比如:
cms.urls.py
1 2 3 4 5 6 7 8 | from . import views from django.urls import path # app_name = 'cms' urlpatterns = [ path(' ', views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), ] |
url_name_demo.urls.py
1 2 3 4 5 6 7 8 9 | from django.contrib import admin from django.urls import path, include urlpatterns = [ path( "admin/" , admin.site.urls), path(' ', include(' front.urls')), #在没有指定应用命名空间的时候,直接指定的是实例命名空间 path( 'cms1/' , include( 'cms.urls' ,namespace = 'cms1' )), path( 'cms2/' , include( 'cms.urls' ,namespace = 'cms2' )), ] |
报错如下:
当不在实例命名空间中指定app_name时,可以在url_name_demo.urls.py使用include函数直接指定实例命名空间。
book.urls.py
1 2 3 4 5 6 7 8 9 10 | from django.urls import path from . import views # app_name='book' urlpatterns = [ path("", views.book), path( "detail/<book_id>/" , views.book_detail), path( "book_list/" , views.book_list), ] |
url_name_demo.urls.py
1 2 3 4 5 6 7 8 | from django.contrib import admin from django.urls import path,include from book.views import book urlpatterns = [ path( "admin/" , admin.site.urls), path( "book/" , include(( 'book.urls' , 'book' ),namespace = 'book' )) ] |
运行结果如下:
2、include(pattern_list)
include可以指定列表的形式。
在项目中加入movie模块
books.urls.py
1 2 3 4 5 6 7 8 9 10 | from django.urls import path from . import views # app_name='book' urlpatterns = [ path("", views.book), path( "detail/<book_id>/" , views.book_detail), path( "book_list/" , views.book_list), ] |
books.views.py
1 2 3 4 5 6 7 8 9 10 11 12 | from django.http import HttpResponse # Create your views here. def book(request): return HttpResponse( "图书首页" ) def book_detail(request,book_id): text = '图书的id是%s' % book_id return HttpResponse(text) def book_list(request): return HttpResponse( "图书列表页面" ) |
movie.urls.py
1 2 3 4 5 6 7 8 9 | from django.urls import path from . import views # app_name='book' urlpatterns = [ path("", views.movie), path( "movie_list/" , views.movie_list), ] |
movie.views.py
1 2 3 4 5 6 7 8 | from django.http import HttpResponse # Create your views here. def movie(request): return HttpResponse( "电影首页" ) def movie_list(request): return HttpResponse( "电影列表页" ) |
djangoProject.urls.py
1 2 3 4 5 6 7 8 9 10 11 12 | from django.contrib import admin from django.urls import path,include from movie import views urlpatterns = [ path( "admin/" , admin.site.urls), path( "book/" , include(( 'book.urls' , 'book' ),namespace = 'book' )), path( "movie/" , include([ path('',views.movie), path( 'list/' ,views.movie_list), ])) ] |
访问http://localhost:8000/movie/
http://localhost:8000/movie/list/
十二、re_path函数详解
1、re_path和path作用都是一样的,只不过re_path是在写url的时候可以使用正则表达式,功能更加强大。
2、写正则表达式推荐使用原生字符串,也就是以"r"开头的字符串
3、在正则表达式中定义变量,需要使用圆括号括起来,这个参数是有名字的,那么需要使用"?p<参数的名字>",然后在后面添加正则表达式的规则。
4、如果不是特殊要求,尽量少使用re_path,使用path解决。
示例代码如下:
首先新建项目re_path_demo,然后在项目中加入article app
article.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.shortcuts import render # Create your views here. from django.http import HttpResponse def article(request): return HttpResponse( '文章首页' ) def article_list(request,year): text = "您输入的年份是%s" % year return HttpResponse(text) def article_list_month(request,month): text = "您输入的月份是%s" % month return HttpResponse(text) |
article.urls.py
1 2 3 4 5 6 7 8 | from . import views from django.urls import re_path urlpatterns = [ # r"",代表的是原生字符串(raw) re_path(r '^$' , views.article), re_path(r "^list/(?P<year>\d{4})/$" , views.article_list), re_path(r "^list/(?P<month>\d{2})/$" , views.article_list_month), ] |
re_path_demo.urls.py
1 2 3 4 5 | from django.urls import path, include urlpatterns = [ path( "article/" , include( 'article.urls' )), ] |
运行结果如下:
十三、reverse函数补充
1、如果在反转url的时候,需要添加参数,那么可以传递kwargs参数到reverse函数中。
2、如果是想要添加查询字符串字段,则必须手动进行拼接。
新建项目reverse_demo,并加入app front
使用kwargs关键字添加参数
reverse_demo.front.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.http import HttpResponse from django.shortcuts import reverse,redirect def index(request): username = request.GET.get( 'username' ) if username : return HttpResponse( '首页' ) else : detail_url = reverse( "article_detail" ,kwargs = { 'article_id' : 1 }) # /detail/1 return redirect(detail_url) def login(request): return HttpResponse( "登录页面" ) def article_detail(request,article_id): text = "您的文章id是:%s" % (article_id) return HttpResponse(text) |
reverse_demo.py
1 2 3 4 5 6 7 8 | from front import views from django.urls import path urlpatterns = [ path(' ',views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), path( 'article_detail/<article_id>' ,views.article_detail,name = 'article_detail' ), ] |
运行结果如下:
这时候直接访问http://localhost:8000/会跳转至article_detail函数中去,kwargs的关键字是article_id为1
添加查询字符串
reverse_demo.front.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.http import HttpResponse from django.shortcuts import reverse,redirect def index(request): username = request.GET.get( 'username' ) if username : return HttpResponse( '首页' ) else : # # 添加查询字符串 login_url = reverse( 'login' ) + "?next=/" return redirect(login_url) def login(request): return HttpResponse( "登录页面" ) def article_detail(request,article_id): text = "您的文章id是:%s" % (article_id) return HttpResponse(text) |
reverse_demo.urls.py
1 2 3 4 5 6 7 8 | from front import views from django.urls import path urlpatterns = [ path(' ',views.index,name=' index'), path( 'login/' ,views.login,name = 'login' ), path( 'article_detail/<article_id>' ,views.article_detail,name = 'article_detail' ), ] |
运行结果如下:
这个时候直接访问http://localhost:8000/会自动跳转
十三、自定义path转换器
之前已经学习过一些django的内置url转换器,包括int、uuid等,有时候这些内置的url的转换器并不能满足我们的需求,因此django给我们提供了一个接口可以让我们自己定义自己的url转换器。
自定义url转换器按照以下5个步骤:
1、定义一个类,这个类直接继承自object就可以了
2、在类中定义一个属性regex,这个属性是用来保存url转换器规则的正则表达式
3、实现to_python(self,value)方法,这个方法是将url中的值转换一下,然后给视图函数的。
4、实现to_url(self,value)方法,这个方法是在做url反转的时候,将传进来的参数转换后拼接成一个正确的url
5、将定义好的转换器,注册到django中。
新建项目path_converter_demo,并加入article模块
article.urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from . import views from django.urls import path, re_path # 需求: # 实现一个获取文章列表的demo,用户可以根据"/articles/文章分类" # 的方式来获取文章。其中文章分类采用的是"分类1+分类2+分类3..." # 的方式拼接的,并且如果只有一个分类,那就不需要加号。示例如下: # #第一种:获取python分类下的文章 # /article/python # #第二种:获取python和django分类下的的文章 # /articles/python+django/ # #第三种:获取python和django和flask下的文章 # /articles/python+django+flask/ urlpatterns = [ path('', views.article), # \w: 0-9,a-z,A-Z # re_path(r'list/(?P<category_name>\w+|(\w+\+\w+)+/', views.article_list), path( "list/<cate:category_name>/" , views.article_list,name = 'list' ), path( 'detail/<int:article_id>/' ,views.article_detail,name = 'detail' ), ] |
article.views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.http import HttpResponse from django.urls import reverse def article(request): return HttpResponse( "文章首页" ) def article_list(request,category_name): reverse( 'list' , kwargs = { 'category_name' : category_name}) text = '您填写的分类是:%s' % category_name return HttpResponse(text) def article_detail(request,article_id): reverse( 'detail' ,kwargs = { 'article_id' :article_id}) print ( type (article_id)) return HttpResponse( "文章详情%s" % article_id) |
在article中实现CategoryConverter converter.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from django.urls import converters,register_converter class CategoryConverter( object ): regex = r '\w+|(\w+\+\w+)+' def to_python( self , value): # python+django+flask # ['python','django','flask'] result = value.split( "+" ) return result def to_url( self , value): # value:['python','django','flask'] # python+django+flask if isinstance (value, list ): result = "+" .join(value) return result else : return RuntimeError( "转换url的时候,分类参数必须要为列表!" ) register_converter(CategoryConverter, "cate" ) |
在article.__init__.py中引入converter
1 | from . import converter |
path_converter_demo.urls.py
1 2 3 4 5 | from django.urls import path, include urlpatterns = [ path( 'article/' , include( 'article.urls' )), ] |
运行结果如下:
十四、指定默认的参数
使用path或者是re_path之后,在route中都可以包含参数,而有时候想指定默认的参数,这时候可以通过在views.py中指定默认参数来完成。
新建项目default_params_demo
urls.py
1 2 3 4 5 6 7 | from django.urls import path from . import views urlpatterns = [ path("", views.books), path( "page/<int:page>/" ,views.books) ] |
views.py
1 2 3 4 5 6 7 8 9 10 11 | from django.http import HttpResponse book_list = [ '三国演义' , '水浒传' , '西游记' , '红楼梦' ] def books(request,page = 0 ): return HttpResponse(book_list[page]) |
访问http://localhost:8000/,会自动填充http://localhost:8000/page/0/
当在访问page/的时候,在page函数中,又有page=0这个默认参数,因此这时候就可以不用传递参数,而如果访问page/1的时候,因为在传递参数的时候传递了page,这时候也会执行views.books,然后把传递进来的参数传给books函数中的page。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2019-05-30 比较两个文件内容是否相同