python之第一个Django项目

## URL 是 Uniform Resource Locator 的简写,简称统一资源定位符,一个 URL 一般由以下几部分组成:

    scheme://host:port/path/?query-string=xxx#anchor

    * scheme 代表的是访问的协议,一般为 http 或者 https 以及 ftp 等。
    * host 主机名或域名,比如:www.baidu.com。
    * port 端口号,http 协议默认端口号为80,https 默认为443。
    * path 查找路径,比如:https://home.cnblogs.com/u/lanten2020 中的 u/lanten2020。
    * query-string 查询字符串,比如:https://www.jianshu.com/search?q=python&page=1&type=note 中的 q=python、page=1 和 type=note 都是查询字符串。
    * anchor 锚点,只是前端用来做页面定位的功能,后台一般都不用管。

    注意:URL 中所有字符都是 ASCII 字符集,如果出现非 ASCII字符,比如中文,浏览器会先进行编码再进行传输。

## 创建第一个 django 项目:

    1、通过命令行方式创建:

     > 首先要进入到安装了 django 工具的虚拟环境,然后在虚拟环境中执行下面命令:

'''
django-admin startproject [项目名称]
'''

     > 进入到刚才创建的项目目录下,通过下面命令启动项目:

'''
python manage.py runserver
'''

     > 验证项目是否启动成功,在浏览器中输入下面地址:

'''
http://127.0.0.1:8000/
'''

     如何返回页面是正常的,表示 django 项目正常启动。

    2、通过 pycharm 方式创建:

   > 点击 pycharm 左上角的“File”-“New Project...”,然后在“New Project”窗口中选择“Django”,并在右侧的填写项目路径、项目名称,选择 python 虚拟环境,然后点击“Create”如下图所示:

     > 项目创建完成后,点击有上角的绿色三角符号启动项目,如下图所示:

     > 验证项目是否启动成功,在浏览器中输入下面地址:

'''
http://127.0.0.1:8000/
'''

     如何返回页面是正常的,表示 django 项目正常启动。

## 项目结构分析:

     * manage.py 整个项目的主函数文件,以后和项目的交互基本上都是基于这个文件,输入:python manage.py help 可以查看函数包含的子命令。
     * settings.py 保存项目所有的配置信息。
     * urls.py 用来做 url 与视图函数映射的,每当有一个新的请求,就会从这个文件中找到匹配的视图函数。
     * wsig.py 专门用来做部署的,不需要去修改。

## Django 推荐的项目规范:

     按照功能或者模块进行分层,分成一个个的 app,所有和某个模块相关的视图都写在对应的 app 的 views.py 文件中,并且模型和其他模块也类似。然后 django 已经提供一个比较方便创建 app 的命令:"python manage.py startapp [app名称]"。

## DEBUG 模式:

     1、如果开启了 DEBUG 模式,那么以后修改了 Django 项目的代码,然后按下 "ctrl+s",Django 就会自动的帮我们重启项目。
     2、如果开启了 DEBUG 模式,在 Django 项目出现 bug 时,浏览器中会打印相信的错误信息。
     3、在生产环境中,禁止开启 DEBUG 模式,不然会存在很多的安全隐患。
     4、如果将 DEBUG 设置为 False,那么必须要设置 ALLOWED_HOSTS。

## ALLOWED_HOSTS:

   这个变量是用来限定别人只能通过此变量中设置的 IP 地址或者域名进行访问。

## 视图函数:

     1、视图函数的第一个参数必须是 request,这个参数不能缺少。
     2、视图函数的返回值必须是 "django.http.response.HttpResponseBase" 的子类的对象。

## URL 映射:

     1、因为在 "settings.py" 文件中的 "ROOT_URLCONF" 变量指定了 "urls.py" 文件,因此 django 会自动去 "urls.py" 查找指定的视图函数映射。
     2、在 "urls.py" 文件中所有的映射都应放在 "urlpatterns" 变量中。
     3、所有映射都是使用 "path" 函数或者是 "re_path" 函数进行包装。

## URL 中添加参数,传给视图函数:

     1、采用在 url 中使用变量的方式:在 "path" 函数的第一个参数中添加 "<参数名>" 方式可以给视图函数传递参数,在视图函数中要有一个和参数名一样的变量名与之对应,否则将提示无法查找到此参数。其中 url 中可以传递多个参数。代码展示如下:

""" python viems.py
def book_detail(request, book_name):
    text = "您正在查找的书籍名称为:%s" % book_name
    return HttpResponse(text)
"""

     2、采用查询字符串方式:在访问地址中的 "?xxx=xxx" 的形式来传递参数给视图函数,视图函数不需要添加任何变量,只需要通过 request.GET['id'] 或者 request.GET.get('id') 即可获取传递的参数。所有以 "?xxx=xxx" 形式都属于 get 请求,因为 'GET' 请求的类型是一个类似于字典的数据类型,所有获取的值跟获取字典的方式一致。代码展示如下:

"""python viems.py
def author_detail(request):
    author_id = request.GET.get('id')    # id 为用户访问浏览器是传递参数的键名,id=1
    author_name = request.GET['name']
    text = "您所查询作者的ID为:%s,作者为:%s" % (author_id, author_name)
    return HttpResponse(text)
"""

## url 参数的转换器(django内置5中类型的转换器):

     1、str:匹配除了斜杆 "/" 的所有字符串,例如:a1$sa。代码展示如下:

"""python urls.py
    path("book/convertor/<str:convertor_id>/", convertor_detail)
"""

     2、int:匹配一个或者多个阿拉伯数字,例如:123976。代码展示如下:

"""python urls.py
    path("book/convertor/<int:convertor_id>/", convertor_detail)
"""

     3、path:匹配除了的所有字符串,例如:a%s-d/@!1s39。代码展示如下:

"""python urls.py
    path("book/convertor/<path:convertor_id>/", convertor_detail)
"""

     4、uuid:匹配满足"uuid.uuid4()"函数返回的字符串类型格式,例如:b30c8b8a-752b-4a45-8e78-9f81a648853f。代码展示如下:

"""python urls.py
    path("book/convertor/<uuid:convertor_id>/", convertor_detail)
"""

     5、slug:匹配一个或者多个英文中的横杠"-",下划线"_",字符串或者阿拉伯数字,例如:-sa_3-asd_a12。代码展示如下:

"""python urls.py
    path("book/convertor/<slug:convertor_id>/", convertor_detail)
"""

     注意:如果内置转换器参数值中有"#"和"?",浏览器会自动的在"#"和"?"前面加上"/","/"和它后面的所有值都不会被匹配。内置转换器类:from django.urls import converters

## urls 分层模块使用:

     当项目变得越来越大,如果所有的 url 都写在同一个 "urls.py" 中,将会不方便进行管理,因此可以在每个 app 自己的 url 放置到自己的 app 中进行管理,通常是在 app 项目中创建一个 "urls.py" 文件进行统一存储所有这个 app 的 url,然后在进行如下相关配置:
     1、在主项目的 "urls.py" 文件中通过 include() 函数将 app 的 url 导入进来,代码如下:

"""python urls.py
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/', include('book.urls'))    # 通过 include() 函数将 book 这个 app 中的所有 url 设置导入进来
]
"""

     2、在 app 的 "urls.py" 中,需要定义一个 "urlpatterns" 变量,并将所有的 URL 匹配放到这个变量中,代码如下:

"""python urls.py
from django.urls import path
from .views import *
urlpatterns = [
    # 访问图书首页
    path("", book),
    # 通过 URL 传递参数给视图函数,变量名必须和视图函数的一致
    path("book_detail/<book_name>/", book_detail),
]
"""

     3、最后在 app 中编写 url 设置的视图函数代码。

## url 命名:

     在开发过程中 url 是经常变化的,如果将其写死的话,将会对后期代码维护带来得多的不便,因此可以给 url 取个名字。只需在 "urls.py" 文件中的 path() 函数中添加一个 "name='xxxx'" 的参数即可,以后在需要使用 url 时候可以通过该 name 进行反转来获取 url 信息,即使修改了 url 前缀,仍可以正常的找到该 url 地址。示例代码如下:

"""python urls.py
urlpatterns = [
    path("", views.index, name="index"),    # 前端首页
    path("signin/", views.login, name="login"),    # 前端登录首页
]

    python views.py
from django.shortcuts import redirect,reverse
def index(request):
    # 如果用户直接访问首页,没有进行登陆的话,将跳转到登陆页面, ?usernam=xxxx
    username = request.GET.get("username")
    if username:
        return HttpResponse("前端首页")
    else:
        login_url = reverse("login")    # reverse() 函数可以根据给定的 url 名称反转成 url 匹配的路径
        print(login_url)
        return redirect(login_url)    # redirect() 函数用来重定向 url
"""

## 应用命名空间:

     在多个 app 项目之间,存在同名的 url 是正常的事情,此时为了避免在反转 url 时候程序产生混淆,可以使用在每个 app 自己的 "urls.py" 文件中定义一个 "app_name='xxx'" 应用命名空间变量来区分。示例代码如下:

"""python url.py
app_name = "front"    # app 应用命名空间,用于让 django 可以区分不同的 app
urlpatterns = [
    path("", views.index, name="index"),    # 前端首页
    path("signin/", views.login, name="login"),    # 前端登录首页
]
"""

     以后在进行 url 反转时候,直接使用 "app_name:url_name" 的方式进行反转即可。示例代码如下:

"""python views.py
from django.shortcuts import redirect,reverse
def index(request):
    # 如果用户直接访问首页,没有进行登陆的话,将跳转到登陆页面, ?usernam=xxxx
    username = request.GET.get("username")
    if username:
        return HttpResponse("前端首页")
    else:
        login_url = reverse("front:login")    # reverse() 函数可以根据给定的 url 名称反转成 url 匹配的路径
        print(login_url)
        return redirect(login_url)    # redirect() 函数用来重定向 url
"""

## 应用命名空间和实例命名空间区别:

     一个 app 可以同时创建多个实例,并且多个 url 也可以映射到同一个 app 中,因此只是通过应用命名空间来进行 url 的反转的话,将会产生 url 的混淆,此时可以通过给 url 中 include() 函数添加一个 "namespace" 实例命名空间变量来区分当前访问的具体是哪个实例,示例代码如下:

"""python url_name_demo/urls.py
urlpatterns = [
    # path('admin/', admin.site.urls),
    path("", include("front.urls"), name="front"),    # name 参数给 url 命令,后续调用时,可以直接通过 name 值来匹配。
    path("cms1/", include("cms.urls", namespace="cms1"), name="cms"),    # namespace 参数是实例命名空间,通过实例命名空间可以区分不同前缀的url转跳到同一个视图函数。
    path("cms2/", include("cms.urls", namespace="cms2"), name="cms"),
]
"""

     然后在需要进行反转时候,就可以通过该实例命名空间来指定具体的 url,示例代码如下:

"""python cms/views.py
def index(request):
    username = request.GET.get("username")
    if username:
        return HttpResponse("CMS首页")
    else:
        # 通过 request 的 GET 方法可以获取当然 URL 设置的实例命名空间
        current_namespace = request.resolver_match.namespace
        print(current_namespace)
        return redirect(reverse("%s:login" % current_namespace))
"""

     注意:在指定一个 "namespace" 实例命名空间时,必须要在对应的 app 中指定 "app_name" 应用命名空间,否则项目启动将报错。

## include 函数详解:

"""
1. include(module, namespace=None),示例代码如下:
   """ python
       path("book/", include("book.urls"), name="book")
   """
2. include((pattern_list, app_namespace), namespace=None),示例代码如下:
   """ python
       path("book/", include(("book.urls", "book"), name="book"))
   """
3. include(pattern_list),示例代码如下:
   """ python
       from movie import views
       path("movie/", include([
           path("", views.index),
           path("list/", views.movie_list),
       ]))
   """
   * module: 子 url 的模块字符串。
   * namespace=None: 实例命名空间。
   * pattern_list: 必须是一个可迭代的 path 或者 re_path 清单。
   * app_namespace: 应用命名空间。
"""

## re_path 函数详解:

     re_path 函数和 path 函数的作用都是一样的,区别在于 re_path 可以在 url 中使用正则表达式来匹配用户传递的参数值是否合规。在写正则表达式时候建议使用原生字符串的方式,即以 'r' 开头的字符串。 并且在正则表达式中将需要获取的参数用括号 () 括起来,然后通过 ?P 后面跟需要获取的参数变量名称,后续在视图函数通过这个变量获取用户输入 URL 的值。示例代码如下:

"""python article/url.py
from django.urls import re_path
from . import views

urlpatterns = [
    re_path(r"^$", views.article, name="index"),
    # 正则表达式中将需要获取的参数用括号 () 括起来,?P 后面跟需要获取的参数变量名称,后续视图函数通过这个变量获取用户输入 URL 的值。
    re_path(r"^list/(?P<year>\d{4})-(?P<month>\d{2})/$", views.article_list, name="article_list"),
]
"""
"""python article/views.py
from django.http import HttpResponse

def article(request):
    return HttpResponse("文章首页。")

def article_list(request, year, month):
    text = "当前文章的日期是:%s-%s" % (year, month)
    return HttpResponse(text)
"""

## reverse 函数详解:

     1、在进行 url 反转时,可以通过在 reverse 函数后面手动拼接字符串的方式给 url 传递查询字符串参数。示例代码如下:

"""python viems.py
from django.http import HttpResponse
from django.shortcuts import redirect, reverse

def index(request):
    username = request.GET.get("username")
    if username:
        return HttpResponse("前端首页")
    else:
        # 在进行 url 反转时,通过在 reverse 函数后面手动拼接字符串的方式给 url 传递查询字符串参数
        login_url = reverse("login") + "?next=%2F"
        return redirect(login_url)

def login(request):
    return HttpResponse("登陆首页")
"""

    2、在进行 url 反转时,可以通过给 reverse 函数添加关键字参数变量的方式传递指定的参数到需要反转的 url 中,示例代码如下:

"""python viems.py
from django.http import HttpResponse
from django.shortcuts import redirect, reverse

def index(request):
    username = request.GET.get("username")
    if username:
        return HttpResponse("前端首页")
    else:
        # 通过给 reverse 函数添加关键字参数变量的方式传递指定的参数到需要反转的 url 中
        article_url = reverse("article", kwargs={'article_id': 1, 'page_id': 5})
        return redirect(article_url)

def article_detail(request, article_id, page_id):
    text = "文章ID为:%s,页数ID为:%s" % (article_id, page_id)
    return HttpResponse(text)
"""

## 自定义 URL(PATH) 转换器:

     需求:实现一个获取文章列表的 demo,用户可以根据 "/article/list/文章列表分类/" 的方式来获取文章列表。其中文章列表分类是采用 "list1+list2+list3..." 的方式拼接的,当只有一个列表分类时,不需要加号。需求示例如下:

"""
# 第一种:获取 python 分类下的文章
/article/list/python/
# 第二种:获取 python 和 django 分类下的文章
/article/list/python+django/
# 第三种:获取 python 和 django 还有 flask 分类下的文章
/article/list/python+django+flask/
以此类推...
"""

     实现方式一:通过在 "urls.py" 文件中给 re_path 函数添加正则表达式来匹配用户传递的 url 参数,然后将参数传给视图函数的变量即可。示例代码如下:

"""python article/urls.py
from django.urls import path, re_path
from . import views

urlpatterns = {
    path("", views.article, name="index"),
    # \w: [0-9a-zA-Z_]
    re_path(r"list/(?P<categories>\w+|(\w+\+\w+)+)/", views.article_list, name="article_list"),
}
"""

     实现方式二:通过自定义 url 转换器,然后在 url 中配置该转换器,就可以将用户传入的参数获取了。示例代码如下:

"""pyrhon article/converters.py
from django.urls import register_converter

class CategoryConverter(object):
    regex = '\w+|(\w+\+\w+)+'

    # 当程序调用转换器时,会执行 to_python 函数
    def to_python(self, value):
        # 将 "python+django+java" 转换成 "['python', 'django', 'java']"
        result = value.split("+")
        return result

    # 当程序进行 url 反转时,会执行 to_url 函数
    def to_url(self, value):
        # 判断 value 是否为 list 类型
        if isinstance(value, list):
            # 将 "['python', 'django', 'java']" 反转成 "python+django+java"
            result = "+".join(value)
            return result
        else:
            # 当 value 类型不为 list 时,抛出异常
            raise RuntimeError("反转的 URL 的分类参数必须为列表类型!")

# 将自定义的转换器注册到代码中
register_converter(CategoryConverter, "category")
"""

"""python article/urls.py
from django.urls import path, re_path
from . import views

urlpatterns = {
    path("", views.article, name="index"),
    path("list/<category:categories>/", views.article_list, name="article_list"),
}
"""

     建议:为方便管理将自定义的转换器单独存放在一个名为 "converters.py" 中,然后在 "__init__.py" 添加一行 "from . import converters" 代码,就可以在启动程序时候自动将自定义转换器注册到代码中。

## url 映射时指定默认参数:

     在视图函数中给变量指定一个值即可。示例代码如下:

"""python views.py
from django.http import HttpResponse

books_list = [
"三国演义",
"我们仨",
"水浒传"
]

def books(request, page=0):
return HttpResponse(books_list[page])
"""
"""python urls.py
from django.urls import path
from . import views

urlpatterns = [
path("", views.books, name="index"),
path("books/<int:page>/", views.books, name="books"),
]
"""
posted @ 2020-12-28 16:41  Zombie☠️  阅读(147)  评论(0)    收藏  举报