Skip to content

Django

Django框架介绍

快速开始

  • 安装Django
bash
pip install django
  • 创建项目
bash
django-admin startproject [项目名称]
  • 创建APP
bash
python manage.py startapp [APP名称]
  • 运行项目
bash
python manage.py runserver

项目文件架构

markdown
django_project           → 项目根目录
├── manage.py            → 项目的管理,启动项目、创建app、数据管理(常使用)
└── django_project       → 项目配置目录(与项目同名)
    ├── __init__.py      → 标识为Python包
    ├── settings.py      → 全局配置(常修改)
    ├── urls.py          → 主路由配置(常修改)
    ├── asgi.py          → ASGI服务器配置, 异步接收网络请求
    └── wsgi.py          → WSGI服务器配置, 同步接收网络请求

APP

在 Django 中,APP(应用) 是一个可重用的功能模块,用于实现特定的业务逻辑。它是 Django 项目的基本组成单元,遵循 "一个APP只做一件事" 的设计原则。

  • 独立性: 每个APP是一个独立的Python包,包含完整的功能闭环(模型、视图、模板等)
  • 低耦合:APP之间应通过公共接口通信,尽量减少直接依赖
  • 可复用:每个APP可以单独摘出来跨项目复用
  • 配置分离:敏感配置应放在项目settings中,而非APP内
markdown
- 项目
  - 业务APP: 用户管理、订单系统等(需自行开发)
  - 通用APP: 评论系统、API接口等(可第三方安装)
  - 内置APP: admin(后台)、auth(认证)、sessions 等
  • 创建APP
    在项目根目录下执行

    bash
    python manage.py startapp blog

    会在此项目文件夹下创建新app如下:

    markdown
    blog                         # APP名称(Python包)
    ├── migrations/                # 数据库变更记录(自动生成)
    │   ├── __init__.py   
    
    ├── templates/                 # 专属模板目录(html文件)
    │   └── blog/                  # 推荐加APP名前缀避免命名冲突
    │       ├── base.html          
    │       ├── post_list.html     
    │       └── post_detail.html   
    
    ├── static/                    # 专属静态文件(图片、css、js等文件)
    │   └── blog/
    │       ├── js/
    │       ├── plugins/                  # 推荐加APP名前缀避免命名冲突
    │       ├── css/
    │       │   └── style.css      
    │       └── images/
    │           └── logo.png     
    
    ├── __init__.py                
    ├── admin.py                   # django默认提供了admin后台管理
    ├── apps.py                    # APP配置类(自动生成)
    ├── models.py                  # 数据模型定义(重要,数据库操作相关)
    ├── tests.py                   # 单元测试
    ├── urls.py                    # 子路由配置(需手动创建)
    └── views.py                   # 视图逻辑(重要,函数)
  • 注册APP
    将新创建的app添加到项目同名目录下的settings.py文件中的INSTALLED_APPS列表中,格式为'app_name.apps.App_nameConfig'

    python
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog.apps.BlogConfig',  # 注册新创建的app
    ]
  • 静态文件
    静态文件一般存放图片、css、js、plugin等内容,在html中引入static文件夹下的文件时,使用{% load static %}标签加载静态文件。

    html
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'blog/css/style.css' %}">

URL与视图

主路由与子路由

主路由是指项目文件夹下的urls.py,子路由是指每个应用(app)目录下的urls.py
主路由负责将请求分发到各个子路由,子路由负责将请求分发到具体的视图函数或视图类。

python
# mysite/mysite/urls.py
from django.urls import path, include
from blog import urls
urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),  # 将blog/的请求交给blog/urls.py处理
]
python
# mysite/blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
  path('articles/', views.article_list),  # 显示所有文章列表
  path('article/<int:id>/', views.article_detail),
]
python
# mysite/blog/views.py
def article_list(request):
  # 示例1:返回HTTP页面
  # 注意:django会根据app的注册顺序(项目名/settings.py - INSTALLED_APPS),
  #      在每个app的templates文件夹中寻找article_list.html
  return render(request, "article_list.html")

def article_detail(request, id)
  # 示例2:返回文本内容
  return HttpResponse(f"文章ID:{id}")

上面这些代码是如何工作的呢?

  • 当用户访问 https://xxxx/blog/article/1/ 时,Django先检查主路由mysite/urls.py, 发现 blog/include('blog.urls') 处理。
  • 然后 Django 查找 blog/urls.py,匹配到 article/<int:id>/,并调用views.article_detail(request, id=1)

path 和 re_path 方法

如何通过URL把参数传递给视图View呢?Django提供了两种设计URL的方法:pathre_path, 它们均支持想视图函数或类传递参数。

  • path方法
    python
    # 使用<变量类型:变量名> or <变量名>传递, 例如 <int:id> 或 <username>
    urlpatterns = [
      path('blog/articles/<int:id>/', views.article_detail, name = 'article_detail'),
    ]
  • re_path方法
    python
    # `re_path`方法是采用正则表达式regex匹配
    # 采用命名组(?P<变量名>表达式)的方式传递参数
    # 使用re_path时不一定总是以$结尾
    urlpatterns = [
      re_path(r'^blog/articles/(?P<id>\d+)/$', views.article_detail, name='article_detail'),
    ]

pathre_path支持传递的数据类型只有 str, int, slug, uuid四种。一般来说 re_path 更强大,但写起来更复杂一些:

python
# 示例一,PATH
from django.urls import path
from . import views

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

# 示例二:RE_PATH,与上例等同
from django.urls import path, re_path
from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

URL的命名

同样以博客为例,如果你希望设计不同的URL分别对应负责增删改查操作的视图函数或类,你可以按如下设计:

python
# mysite/blog/urls.py
from django.urls import path, re_path
from . import views

app_name = 'blog' # 命名空间
urlpatterns = [
  path('blog/articles/', views.article_list, name = 'article_list'),
  path('blog/articles/create/', views.article_create, name = 'article_create'),
  path('blog/articles/<int:id>/', views.article_detail, name = 'article_detail'),
  path('blog/articles/<int:id>/update/', views.article_update, name = 'article_update'),
  path('blog/articles/<int:id>/delete/', views.article_update, name = 'article_delete'),
]

在上述博客示例中,我们给每个URL取了一个名字,比如第一个path()中的name = article_list。它可以让你能够在Django的任意处,尤其是Template中直接引用它。假设你需要在某个模版中通过链接指向一篇具体的文章,就可以以下面方式引用:

html
<!-- 等同于:"blog/articles/article.id"-->
<a herf="% url 'article_detail' article.id %">{{article.title}}</a>

url 是一个模版标签,其作用是对命名的url进行反向解析,动态生成链接。

在View中使用命名URL

Django提供了 reverse() 方法在视图中可以对命名URL进行反向解析,生成动态链接:

python
from django.urls import reverse

# output blog/articles/id
reverse('blog:article_detail', args=[id])

URL指向基于类的视图(View)

pathre_path都只能指向视图View里的一个函数或方法,而不能直接指向一个基于类的视图(Class-based View)。Django提供了一个额外的as_view()方法,可以将一个类伪装成方法。这在当你使用Django自带的类视图或自定义类视图时非常重要。

使用方式如下

python
  # blog/urls.py
  from django.urls import path, re_path
  from . import views
  
  urlpatterns = [
      # path('blog/articles/', views.article_list, name = 'article_list'),
      path('blog/articles/', views.ArticleList.as_view(), name='article_list'),
  ]
python
  # blog/views.py
  from django.views.generic import ListView
  from .views import Article
  
  class ArticleList(ListView):
      queryset = Article.objects.filter(date__lte=timezone.now()).order_by('date')[:5]
      context_object_name = 'article_list'
      template_name = 'blog/article_list.html'

通过URL传递额外的参数

在你配置URL时,还可以通过字典的形式传递额外的参数给视图,且不用把这个参数写在链接里,如下所示:

python
# blog/urls.py
from django.urls import path, re_path
from . import views

urlpatterns = [
  path('', views.ArticleList.as_view(), name='article_list', {'blog_id': 3})
]

<更新中...>

Last Updated:

Released under the MIT License.