【Django 笔记】常用功能--静态文件、中间件、后台管理

笔记主要基于官方文档,从中提取要点和记录笔记,关键处包含了官方文档链接。详见官方文档。

官方文档:Django documentation 

博客推荐:Django2.2教程

目录

静态文件

配置静态文件

2.中间件

3.后台管理

3.1.Admin的使用

3.2.自定义模型管理类

ModelAdmin属性 options

3.3.重写模板自定义Admin页


静态文件、中间件、后台管理  等常用功能的笔记

静态文件

官方文档中:可参考静态文件入门。 更多关于设置和框架的资料,参考 管理静态文件 和 静态文件指南部署静态文件 介绍了如何在真实服务器上使用静态文件。

项目中的CSS、图片、js等都是静态文件。

Django中,提供了django.contrib.staticfiles ,它将各个应用的静态文件(和一些你指明的目录里的文件)统一收集起来,这样一来,在生产环境中,这些文件就会集中在一个便于分发的地方。

 

配置静态文件

  1. 项目目录下创建一个名为 static 的目录。Django 将在该目录下查找静态文件。通常,将每个应用的静态文件放入各自的 命名空间 。也就是把这些静态文件放入 另一个 与应用名相同的目录中(在static目录下创建)。

  2. 确保 INSTALLED_APPS 包含了 django.contrib.staticfiles

  3. 在配置文件中,定义 STATIC_URL设置访问静态文件对应的URL地址。例子:

    STATIC_URL = '/static/'
  4. 在模板中,用 static 模板标签基于配置 STATICFILES_STORAGE 位给定的相对路径构建 URL。

    {% load static %}
    
    使用静态文件:
    <img src="{% static "my_app/example.jpg" %}" alt="My image">

静态文件保存在程序中名为 static 的目录中

工程中可能包含未与任何应用绑定的静态资源。除了在 apps 中使用 static/ 目录,可以在setting.py配置文件中定义一个目录列表 (STATICFILES_DIRS) ,设置静态文件存放的物理目录,Django 会从中寻找静态文件。例子:

STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]

参考 STATICFILES_FINDERS 配置的文档了解 staticfiles 是如何找到你的文件的细节。

静态文件的查找顺序

  1. Django会先去配置的目录去找。
  2. 找不到的话,再去应用的static目录下去找

导入from django.conf import setting,使用 sprint(settings.STATICFILES_FINDERS) 就可以看到查找的顺序:

['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder']

上面所述其实不适合生产环境!参考 部署静态文件 了解如何正确地在生产环境提供静态文件服务的策略。

注:良好的目录结构是每个应用都应该创建自己的urls、forms、views、models、templates和static,每个templates包含一个与应用同名的子目录,每个static也包含一个与应用同名的子目录。

2.中间件

官方文档:中间件  概览 | 内建的中间件类

Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件函数是django框架给我们预留的函数接口,让我们可以干预请求和应答的过程

 

浏览器请求和应答中的中间件:红色箭头的是通过中间件进行干预

 

Django在中间件中预置了一些方法,这些方法的区别在于不同的阶段执行,对输入或输出进行干预。

在中间件类中,实现以下方法的至少一种。(中间件类名是自由定义的,但是方法名是固定的)

方法如下:

1)初始化:服务器响应第一个请求的时候调用一次,用于确定是否启用当前中间件。

def __init__(self, get_response):
    pass

2)处理请求前:在每个请求上,request对象产生之后,url匹配之前调用,返回None或HttpResponse对象。

def process_request(self, request):
    pass

3)处理视图前

process_view(request, view_func, view_args, view_kwargs)

在每个请求上,url匹配之后,视图函数调用之前调用,返回None或HttpResponse对象。

def process_view(self, request, view_func, *view_args, **view_kwargs):
    pass

4)处理响应后视图函数调用之后,所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象。

def process_response(self, request, response):
    pass

5)异常处理

process_exception(request, exception)

当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象。

(如果注册的多个中间件类中包含process_exception函数的时候,调用的顺序跟注册的顺序是相反的。)

def process_exception(self, request,exception):
    pass

6)视图刚好执行完毕

process_template_response(request, response)

在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象;

request 是一个 HttpRequest 对象。response 是 TemplateResponse 对象(或者等效对象),它通过 Django 视图或中间件返回

设想一个场景,我们需要禁止某些ip的浏览器访问我们的网址。可以有以下解决办法:

法1:在每一个视图中进行判断,浏览器的ip是否在禁止列表中(使用request对象的META属性,可获取浏览器端的ip地址);

法2:使用装饰器,装饰器用到每一个视图中;

以上方法都会有代码较大冗余,这时就可以使用中间件

(1)在应用的目录新建文件,通常命名为 middleware.py 。定义中间件类。(使用了process_view)

# 方法1:接收get_response参数
from django.http import HttpResponse

class BlockedIPSMiddleware(object):
    '''中间件类'''
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        response = self.get_response(request)
        return response
    EXCLUDE_IPS = ['192.168.43.28']  # 禁止访问的地址列表

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        '''视图函数调用之前会调用'''
        user_ip = request.META['REMOTE_ADDR']
        print(user_ip)
        if user_ip in BlockedIPSMiddleware.EXCLUDE_IPS:   # 运行验证时,启动服务时指明ip,设置ALLOWED_HOSTS = ['*']
            return HttpResponse('<h1>Forbidden</h1>')


# 方法2:兼容旧版本Django(推荐)
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin

class BlockedIPSMiddleware(MiddlewareMixin):
    EXCLUDE_IPS = ['192.168.43.28']  # 禁止访问的地址列表
    def process_view(self, request, view_func, *view_args, **view_kwargs):
        '''视图函数调用之前会调用'''
        user_ip = request.META['REMOTE_ADDR']
        print(user_ip)
        if user_ip in BlockedIPSMiddleware.EXCLUDE_IPS:   # 运行验证时,启动服务时指明ip,设置ALLOWED_HOSTS = ['*']
            return HttpResponse('<h1>Forbidden</h1>')

可以使用 MiddlewareMixin 使中间件与1.10之前和1.10之后的Django版本兼容升级 Django 1.10 之前的中间件

(2)注册激活中间件组件,将其添加到 Django setting.py 设置中的 MIDDLEWARE 列表中。在 MIDDLEWARE 中,每个中间件组件由字符串表示:指向中间件工厂的类或函数名的完整 Python 路径。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'booktest.middleware.BlockedIPSMiddleware',  # 注册激活中间件类(booktest为应用名
]

关于中间件的一个坑:https://blog.csdn.net/qq_23996069/article/details/104922501

3.后台管理

官方文档:管理Admin

相关博客:https://www.liujiangblog.com/course/django/157

概况

Admin站点是Django有别于其它Web框架最重要的一点。通过读取你的模型数据,快速构造出一个可以对实际数据进行管理的Web站点,常用于开发测试,简单管理等场合,适用于部门内部为工作方便的场合,但不建议在生产环境中使用。

Admin在创建应用时,默认会启用。使用时需注意:

  1. 确保添加 'django.contrib.admin'  和它所依赖的 django.contrib.authdjango.contrib.contenttypes,、django.contrib.messages and django.contrib.sessions 到setting.py的 INSTALLED_APPS 中。
  2. 在settings文件中的TEMPLATES中的context_processors选项内添加django.contrib.auth.context_processors.authdjango.contrib.messages.context_processors.messages这两条。同样,将django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddleware添加到settings的MIDDLEWARE内。默认情况下,这些都是配置好的
  3. 决定哪些模型需要在admin内进行管理,在admin.py文件中注册它们。
  4. 对于每个模型,可以创建一个对应的ModelAdmin类,这个类将封装对模型的所有自定义设置。
  5. 实例化一个AdminSite,将模型、模型对应的ModelAdmin类传给它。
  6. 链接AdminSite的URLs和URLconf.。这一步通常默认已经完成。

python manage.py createsuperuser命令创建管理员账户。打开/admin/ 访问Admin登陆。

3.1.Admin的使用

1) 本地化。语言和时区本地化。

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

2) 创建超级管理员

python mange.py createsuperuser

3) 注册模型类

决定哪些模型需要在admin内进行管理,在admin.py文件中注册它们。

from django.contrib import admin
from 你的应用名.models import 你的模型名

# Register your models here.

admin.site.register(你的模型名)

 

4)    自定义管理页面

   自定义模型管理类。

   注册模型类的时候给register函数添加第二个参数,就是自定义模型管理类的名字。

3.2.自定义模型管理类

只对模型类注册往往是不够,有时需要对admin进行各种深度定制,以满足我们的需求。这时就要使用Django为我们提供的模型管理类 ModelAdmin类

1)创建一个ModelAdmin的子类,2)注册的时候,将原模型和ModelAdmin的子类耦合起来

 

ModelAdmin类是一个模型在admin页面里的展示方法。通常保存在app的admin.py文件。点击ModelAdmin objects 查看官方文档和例子

 

ModelAdmin属性 options

真正用来定制admin的手段,大部分都集中在这些ModelAdmin内置的属性上。它有许多内置属性,帮助我们自定义admin的界面和功能。详情可点击ModelAdmin options查看官网,或参考:https://www.liujiangblog.com/course/django/158

所有的属性都定义在ModelAdmin的子类中,如下方式:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'

常用的如下(点击可查看官网示例):

ModelAdmin.list_per_page:设置每页显示的数量。

ModelAdmin.list_display:列表页中的列。注意,list不仅可以写模型类的属性,还可以写模型类的方法,值为方法的返回值。

ModelAdmin.list_filter: 列表页右侧过滤栏

ModelAdmin.search_fields: 列表页上方的搜索框,以什么属性搜索传什么参数:search_fields = ['atitle']

ModelAdmin.fields:编辑页显示字段的顺序

ModelAdmin.fieldsets:编辑页分组的显示,根据字段对页面进行分组显示或布局了。

关联对象

一对多的关系中,可以在一端的编辑页面中编辑多端的对象,嵌入多端对象的方式包括表格两种。

  • 类型 InlineModelAdmin objects:表示在模型的编辑页面嵌入关联模型的编辑。
  • 子类 TabularInline:以表格的形式嵌入。
  • 子类 StackedInline:以块的形式嵌入。

admin中无法直接访问关联对象的属性或方法,可以在模型类中封装方法,访问关联对象的成员。

以块的形式:定义一个类,继承于admin.StackedInline。model属性写多类的名字。在一类的模型管理类,定义一个属性 inlines = [定义的类]

块的形式:定义一个类,继承于admin.TabularInline。
 

上面一些相关的例子如下:(以地区管理的模型类为例)

models.py

from django.db import models

# Create your models here.


class AreaInfo(models.Model):
    '''地址模型类'''
    # 地区名称
    atitle = models.CharField(verbose_name='标题', max_length=20)  # verbose_name:在admin中,指定属性的列名
    # 自关联属性
    aParent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)

    def __str__(self):  # 在admin中,以字符串显示字段
        return self.atitle

    def title(self):  # 定义函数,在admin中,可以显示函数的返回值
        return self.atitle

    title.admin_order_field = 'atitle'  # 在admin中,指定方法title对应的列可以依照atitle排序
    title.short_description = '地区名称'  # 在admin中,指定方法title对应的列的标题

    def parent(self):
        if self.aParent is None:  # 处理没有父级地区导致的错误
            return ''
        return self.aParent.atitle
    parent.short_description = '父级地区名称'

admin.py

from django.contrib import admin
from booktest.models import AreaInfo
# Register your models here.


# 关联对象,以块的形式,继承于admin.StackedInline
# class AreaStackedInline(admin.StackedInline):
#     # model属性写多类的名字
#     model = AreaInfo
#     extra = 2  # 控制编辑页的空行数


# 关联对象,以块的形式,继承于admin.TabularInline
class AreaTabularInline(admin.TabularInline):
    model = AreaInfo
    extra = 2


# 创建一个ModelAdmin的子类
class AreaInfoAdmin(admin.ModelAdmin):
    '''地区模型管理类'''
    list_per_page = 10 # 指定每页显示10条数据
    list_display = ['id', 'atitle', 'title', 'parent']
    actions_on_bottom = True  # 在下方显示actions的下拉列表框
    actions_on_top = False
    # list_filter = ['atitle']  # 列表页右侧过滤栏
    search_fields = ['atitle']  # 列表页上方的搜索框

    # fields = ['aParent', 'atitle']  # 编辑页显示字段的顺序
    # 编辑页分组的显示
    fieldsets = (
        ('基本', {'fields': ['atitle']}),
        ('高级', {'fields': ['aParent']})
    )
    # inlines = [AreaStackedInline]
    inlines = [AreaTabularInline]


# 注册的时候,将原模型和ModelAdmin的子类耦合起来
admin.site.register(AreaInfo, AreaInfoAdmin)

3.3.重写模板自定义Admin页

官方文档:Overriding admin templates

复制模板文件base_site.html到项目目录,进行修改。详见官方文档。

-----end-----

发布了50 篇原创文章 · 获赞 10 · 访问量 6589

猜你喜欢

转载自blog.csdn.net/qq_23996069/article/details/104910791
今日推荐