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:

Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'

如果两者均尚未安装,则此操作应返回以下输出:

Name : OpenSSH.Client~~~~0.0.1.0
State : NotPresent

Name : OpenSSH.Server~~~~0.0.1.0
State : NotPresent

然后,根据需要安装服务器或客户端组件:

# 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

这两者应该都会返回以下输出:

Path :
Online : True
RestartNeeded : False

启动并配置 OpenSSH 服务器
若要启动并配置 OpenSSH 服务器来开启使用,请以管理员身份打开 PowerShell,然后运行以下命令来启动 sshd 

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更改为如下代码:

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

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

from django.http import HttpResponse

def book(request):
    return HttpResponse('书籍')

movie.views.py

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

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

from django.http import HttpResponse
# Create your views here.
def books(request):
    return(HttpResponse('图书首页'))

 urls.py

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的对象。示例代码如下:

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

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

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

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

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

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

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

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

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)
]

运行结果:

如果更改为字符串转换器

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

>>> import uuid
>>> print(uuid.uuid4())

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类型

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类型 

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

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

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文件

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登录页面

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

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

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index),
    path('login/',views.login)
]

cms.urls.py

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index),
    path('login/',views.login)
]

url_name_demo.urls.py  

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

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中

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index,name='index'),
    path('siginin/',views.login,name='login'),
]

CMS.urls.py

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index),
    path('login/',views.login)
]

CMS.views.py

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

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指定名称

urlpatterns = [
    path('', views.index,name='index'),
    path('siginin/',views.login,name='login'),
] 

 十一、命名空间

当不指定命名空间时,如果不同模块取名相同,会跳转错误的链接,如下

CMS.urls.py

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index,name='index'),
    path('login/',views.login,name='login'),
]

CMS.views.py

from django.http import HttpResponse
# Create your views here.
def index(request):
    return HttpResponse("CMS首页")

def login(request):
    return HttpResponse("CMS登录页面")

front.urls.py

from . import views
from django.urls import path

urlpatterns = [
    path('', views.index,name='index'),
    path('login/',views.login,name='login'),
]

front.views.py  

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

from django.urls import path
from . import views

# app_name='book'

urlpatterns = [
    path("", views.movie),
    path("movie_list/", views.movie_list),
]

movie.views.py

from django.http import HttpResponse

# Create your views here.
def movie(request):
    return HttpResponse("电影首页")

def movie_list(request):
    return HttpResponse("电影列表页")

 djangoProject.urls.py

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

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  

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

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

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

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

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

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

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

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

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

from . import converter

path_converter_demo.urls.py

from django.urls import path, include

urlpatterns = [
    path('article/', include('article.urls')),
]

 运行结果如下:

 

十四、指定默认的参数

使用path或者是re_path之后,在route中都可以包含参数,而有时候想指定默认的参数,这时候可以通过在views.py中指定默认参数来完成。

新建项目default_params_demo

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path("", views.books),
    path("page/<int:page>/",views.books)
]

views.py

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。

posted @ 2024-05-30 22:44  leagueandlegends  阅读(34)  评论(0编辑  收藏  举报