Django后端笔记(五)静态文件、中间件、后台管理

其他技术

静态文件

使用

在 网页使用的css文件,js文件和图片叫做静态文件。

  1. 新建静态文件夹 static。
    在这里插入图片描述
  2. 配置静态文件所在的物理目录。Settings.py
    在这里插入图片描述
    在这里插入图片描述

STATIC_URL设置访问静态文件对应的url。
STATICFILES_DIRS设置静态文件所在的物理目录。
动态生成静态文件的路径。
在这里插入图片描述

加载目录

STATICFILES_FINDERS=(‘django.contrib.staticfiles.finders.FileSystemFinder’, ‘django.contrib.staticfiles.finders.AppDirectoriesFinder’)

中间件

中间件函数是django框架给我们预留的函数接口,让我们可以干预请求和应答的过程。
在这里插入图片描述

获取浏览器端的ip地址

使用request对象的META属性:request.META[‘REMOTE_ADDR’]

使用中间件

  1. 新建middleware.py文件。
    在这里插入图片描述

  2. 定义中间件类。
    在这里插入图片描述

在类中定义中间件预留函数。
init:服务器响应第一个请求的时候调用。
process_request:是在产生request对象,进行url匹配之前调用。
process_view:是url匹配之后,调用视图函数之前。
process_response:视图函数调用之后,内容返回给浏览器之前。
process_exception:视图函数出现异常,会调用这个函数。

middleware.py

扫描二维码关注公众号,回复: 13204759 查看本文章
from django.http import HttpResponse


class BlockedIPSMiddleware(object):
    '''中间件类'''
    EXCLUDE_IPS = ['172.16.179.152']

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        '''视图函数调用之前会调用'''
        user_ip = request.META['REMOTE_ADDR']
        if user_ip in BlockedIPSMiddleware.EXCLUDE_IPS:
            return HttpResponse('<h1>Forbidden</h1>')


class TestMiddleware(object):
    '''中间件类'''
    def __init__(self):
        '''服务器重启之后,接收第一个请求时调用'''
        print('----init----')

    def process_request(self, request):
        '''产生request对象之后,url匹配之前调用'''
        print('----process_request----')
        # return HttpResponse('process_request')

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        '''url匹配之后,视图函数调用之前调用'''
        print('----process_view----')
        return HttpResponse('process_view')

    def process_response(self, request, response):
        '''视图函数调用之后,内容返回浏览器之前'''
        print('----process_response----')
        return response


class ExceptionTest1Middleware(object):
    def process_exception(self, request, exception):
        '''视图函数发生异常时调用'''
        print('----process_exception1----')
        print(exception)

class ExceptionTest2Middleware(object):
    def process_exception(self, request, exception):
        '''视图函数发生异常时调用'''
        print('----process_exception2----')

在这里插入图片描述
在这里插入图片描述

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

3)在setting.py 注册中间件类。
在这里插入图片描述

Admin后台管理 (了解)

使用

  1. 本地化。语言和时区本地化。
    在这里插入图片描述

  2. 创建超级管理员。

python mange.py createsuperuser
  1. 注册模型类。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

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

3.2 模型管理类相关属性

  1. 列表页相关的选项。

admin.py

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

class AreaInfoAdmin(admin.ModelAdmin):
    '''地区模型管理类'''
    list_per_page = 10 # 指定每页显示10条数据
    list_display = ['id', 'atitle', 'title', 'parent'] # 列表展示模型类属性和方法
    actions_on_bottom = True  # 打开下方动作选框
    actions_on_top = False 
    list_filter = ['atitle'] # 列表页右侧过滤栏
    search_fields = ['atitle'] # 列表页上方的搜索框

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

    # 自关联属性
    aParent = models.ForeignKey('self', null=True, blank=True)

    def __str__(self):
        return self.atitle

    def title(self):
        return self.atitle
    title.admin_order_field = 'atitle' # 根据atitle进行排序 
    title.short_description = '地区名称' # 指定标题名称

    # 判断父级属性是否为空 
    def parent(self):
        if self.aParent is None:
            return ''
        return self.aParent.atitle
    parent.short_description = '父级地区名称'

在这里插入图片描述

  1. 编辑页相关的选项。

显示字段顺序

属性如下:

fields=[]
1)点击某行ID的链接,可以转到修改页面,默认效果如下图:
在这里插入图片描述

2)打开booktest/admin.py文件,修改AreaAdmin类如下:

class AreaAdmin(admin.ModelAdmin):
    ...
    fields=['aParent','atitle']

3)刷新浏览器效果如下图:
在这里插入图片描述

在下拉列表中输出的是对象的名称,可以在模型类中定义str方法用于对象转换字符串。

1)打开booktest/models.py文件,修改AreaInfo类,添加str方法。

class AreaInfo(models.Model):
    ...
    def __str__(self):
        return self.atitle

2)刷新浏览器效果如下图:

编辑页选项

分组显示

属性如下:

fieldset=(
    ('组1标题',{'fields':('字段1','字段2')}),
    ('组2标题',{'fields':('字段3','字段4')}),
)

1)打开booktest/admin.py文件,修改AreaAdmin类如下:

class AreaAdmin(admin.ModelAdmin):
    ...
    # fields=['aParent','atitle']
    fieldsets = (
        ('基本', {'fields': ['atitle']}),
        ('高级', {'fields': ['aParent']})
    )

2)刷新浏览器效果如下图:

编辑页选项

说明:fields与fieldsets两者选一使用。

关联对象

在一对多的关系中,可以在一端的编辑页面中编辑多端的对象,嵌入多端对象的方式包括表格、块两种。 类型InlineModelAdmin:表示在模型的编辑页面嵌入关联模型的编辑。子类TabularInline:以表格的形式嵌入。子类StackedInline:以块的形式嵌入。

1)打开booktest/admin.py文件,创建AreaStackedInline类。

class AreaStackedInline(admin.StackedInline):
    model = AreaInfo#关联子对象
    extra = 2#额外编辑2个子对象

2)打开booktest/admin.py文件,修改AreaAdmin类如下:

class AreaAdmin(admin.ModelAdmin):
    ...
    inlines = [AreaStackedInline]

3)刷新浏览器效果如下图:

编辑页选项

可以用表格的形式嵌入。

1)打开booktest/admin.py文件,创建AreaTabularInline类。

class AreaTabularInline(admin.TabularInline):
    model = AreaInfo#关联子对象
    extra = 2#额外编辑2个子对象

2)打开booktest/admin.py文件,修改AreaAdmin类如下:

class AreaAdmin(admin.ModelAdmin):
    ...
    inlines = [AreaTabularInline]

3)刷新浏览器效果如下图:

编辑页选项

上传图片

在python中进行图片操作,需要安装包PIL。

pip install Pillow==3.4.1

在Django中上传图片包括两种方式:

  • 在管理页面admin中上传图片
  • 自定义form表单中上传图片
    上传图片后,将图片存储在服务器上,然后将图片的路径存储在表中。

创建包含图片的模型类

将模型类的属性定义成models.ImageField类型。

1)打开booktest/models.py文件,定义模型类PicTest。

class PicTest(models.Model):
    pic = models.ImageField(upload_to='booktest/')

2)回到命令行中,生成迁移。

python manage.py makemigrations
3)打开booktest/migrations/0001_initial.py文件,删除AreaInfo部分,因为这个表已经存在。

上传图片

4)回到命令行中,执行迁移。

python manage.py migrate
5)因为当前没有定义图书、英雄模型类,会提示“是否删除”,输入“no”后回车,表示不删除。

上传图片

6)打开test5/settings.py文件,设置图片保存路径。

因为图片也属于静态文件,所以保存到static目录下。

MEDIA_ROOT=os.path.join(BASE_DIR,"static/media")
7)在static目录下创建media目录,再创建应用名称的目录,此例为booktest。

上传图片

在管理页面admin中上传图片

1)打开booktest/admin.py文件,注册PicTest。

from django.contrib import admin
from booktest.models import *


admin.site.register(PicTest)

2)运行服务器,输入如下网址。

http://127.0.0.1:8000/admin/

在这里插入图片描述
3)点击“Add”添加数据,打开新页面。

上传图片

4)选择图片,点击“save”按钮完成图片上传。 5)回到数据库命令行,查询表pictest中的数据如下图:

上传图片

6)图片被保存到目录static/media/booktest/下,如下图:

上传图片

用户自定义页面上传图片

  1. 定义用户上传图片的页面并显示,是一个自定义的表单。
    在这里插入图片描述

  2. 定义接收上传文件的视图函数。
    request对象有一个FILES的属性,类似于字典,通过request.FILES可以获取上传文件的处理对象。
    在django中,上传文件不大于2.5M,文件放在内存中。上传文件大于2.5M,文件内容写到一个临时文件中。
    Django处理上传文件的两个类:
    FILE_UPLOAD_HANDLERS= (“django.core.files.uploadhandler.MemoryFileUploadHandler”,
    “django.core.files.uploadhandler.TemporaryFileUploadHandler”)

upload_file.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传图片</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="/upload_handle">
    {% csrf_token %}
    <input type="file" name="pic"><br/>
    <input type="submit" value="上传">
</form>
</body>
</html>

view.py

from django.shortcuts import render
from django.conf import settings
from django.http import HttpResponse,JsonResponse
from booktest.models import PicTest,AreaInfo

# <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
# <class 'django.core.files.uploadedfile.TemporaryUploadedFile'>
def upload_handle(request):
    '''上传图片处理'''
    # 1.获取上传文件的处理对象
    pic = request.FILES['pic']

    # 2.创建一个文件
    save_path = '%s/booktest/%s'%(settings.MEDIA_ROOT,pic.name)
    with open(save_path, 'wb') as f:
        # 3.获取上传文件的内容并写到创建的文件中
        for content in pic.chunks():
            f.write(content)

    # 4.在数据库中保存上传记录
    PicTest.objects.create(goods_pic='booktest/%s'%pic.name)

    # 5.返回
    return HttpResponse('ok')

上传图片参考资料:

  1. http://python.usyiyi.cn/documents/django_182/topics/http/file-uploads.html
  2. http://python.usyiyi.cn/documents/django_182/ref/files/uploads.html#django.core.files.uploadedfile.UploadedFile

分页

查询出所有省级地区的信息,显示在页面上。
AeroInfo.objects.filter(aParent__isnull = True)

  1. 查询出所有省级地区的信息。
  2. 按每页显示10条信息进行分页,默认显示第一页的信息,下面并显示出页码。
  3. 点击i页链接的时候,就显示第i页的省级地区信息。
    from django.core.paginator import Paginator
    paginator = Paginator(areas, 10) #按每页10条数据进行分页
    Paginator类对象的属性:
属性名 说明
num_pages 返回分页之后的总页数
page_range 返回分页后页码的列表

Paginator类对象的方法:

方法名 说明
page(self, number) 返回第number页的Page类实例对象

Page类对象的属性:

属性名 说明
number 返回当前页的页码
object_list 返回包含当前页的数据的查询集
paginator 返回对应的Paginator类对象

Page类对象的方法:

属性名 说明
has_previous 判断当前页是否有前一页
has_next 判断当前页是否有下一页
previous_page_number 返回前一页的页码
next_page_number 返回下一页的页码

view.py

# /show_area页码
# 前端访问的时候,需要传递页码
from django.core.paginator import Paginator


def show_area(request, pindex):
    '''分页'''
    # 1.查询出所有省级地区的信息
    areas = AreaInfo.objects.filter(aParent__isnull=True)
    # 2. 分页,每页显示10条
    paginator = Paginator(areas, 10)

    # 3. 获取第pindex页的内容
    if pindex == '':
        # 默认取第一页的内容
        pindex = 1
    else:
        pindex = int(pindex)
    # page是Page类的实例对象
    page = paginator.page(pindex)

    # 4.使用模板
    return render(request, 'booktest/show_area.html', {
    
    'page':page})

show_area.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>分页</title>
</head>
<body>
<ul>
    {# 遍历获取每一条数据 #}
    {#  {% for area in page.object_list %}#}
    {% for area in page %}
        <li>{
   
   { area.atitle }}</li>
    {% endfor %}
</ul>
{# 判断是否有上一页 #}
{% if page.has_previous %}
    <a href="/show_area{
     
     { page.previous_page_number }}">&lt;上一页</a>
{% endif %}

{# 遍历显示页码的链接 #}
{% for pindex in page.paginator.page_range %}
    {# 判断是否是当前页 #}
    {% if pindex == page.number %}
        {
   
   { pindex }}
    {% else %}
        <a href="/show_area{
     
     { pindex }}">{
   
   { pindex }}</a>
    {% endif %}
{% endfor %}

{# 判断是否有下一页 #}
{% if page.has_next %}
    <a href="/show_area{
     
     { page.next_page_number }}">下一页&gt;</a>
{% endif %}
</body>
</html>

分页参考资料:
http://python.usyiyi.cn/translate/django_182/topics/pagination.html

省市县选择案例

  1. 显示省地区信息。
$.get('/prov', function(data){
})
  1. 省改变时在对应的下拉列表框中显示下级市的信息。
$.get('/city?pid='+pid, function(data){
			})
			request.GET.get(‘pid’)

或者:

	$.get('/city'+$(this).val(), function(data){
			})
  1. 市改变时在对应的下拉列表框中显示下级县的信息。
$.get('/dis?pid='+pid, function(data){
		})

或者:

$.get('/dis'+$(this).val(), function(data){
		})

area.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>省市县选择案例</title>
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <script>
        $(function () {
      
      
            // 发起一个ajax请求 /prov,获取所有省级地区的信息
            // 获取信息,使用get
            // 涉及到信息修改,使用post
            $.get('/prov', function (data) {
      
      
                // 回调函数
                // 获取返回的json数据
                res = data.data
                // 获取prov下拉列表框
                prov = $('#prov')
                // 变量res数组,获取每一个元素:[地区id, 地区标题]
                /*
                for(i=0; i<res.length; i++){
                    id = res[i][0]
                    atitle = res[i][1]

                    option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                    // 向prov下拉列表框中追加元素
                    prov.append(option_str)
                }*/
                $.each(res, function (index, item) {
      
      
                    id = item[0]
                    atitle = item[1]
                    option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                    // 向prov下拉列表框中追加元素
                    prov.append(option_str)
                })
            })

            // 绑定prov下拉列表框的change事件,获取省下面的市的信息
            $('#prov').change(function () {
      
      
                // 发起一个ajax请求 /city,获取省下面市级地区的信息
                // 获取点击省的id
                prov_id=$(this).val()
                $.get('/city'+prov_id, function (data) {
      
      
                    // 获取返回的json数据
                    res = data.data
                    // 获取city下拉列表框
                    city = $('#city')
                    // 清空city下拉列表框
                    city.empty().append('<option>---请选择市---</option>')
                    // 获取dis下拉列表框
                    dis = $('#dis')
                    // 清空dis下拉列表框
                    dis.empty().append('<option>---请选择县---</option>')
                    // 变量res数组,获取每一个元素:[地区id, 地区标题]
                    // 遍历取值添加到city下拉列表框中
                    $.each(res, function (index, item) {
      
      
                        id = item[0]
                        atitle = item[1]
                        option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                        // 向city下拉列表框中追加元素
                        city.append(option_str)
                    })
                })
            })

             // 绑定city下拉列表框的change事件,获取市下面的县的信息
            $('#city').change(function () {
      
      
                // 发起一个ajax请求 /dis,获取市下面县级地区的信息
                // 获取点击市的id
                city_id=$(this).val()
                $.get('/dis'+city_id, function (data) {
      
      
                    // 获取返回的json数据
                    res = data.data
                    // 获取dis下拉列表框
                    dis = $('#dis')
                    // 清空dis下拉列表框
                    dis.empty().append('<option>---请选择县---</option>')
                    // 变量res数组,获取每一个元素:[地区id, 地区标题]
                    // 遍历取值添加到dis下拉列表框中
                    $.each(res, function (index, item) {
      
      
                        id = item[0]
                        atitle = item[1]
                        option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                        // 向dis下拉列表框中追加元素
                        dis.append(option_str)
                    })
                })
            })
        })
    </script>
</head>
<body>
<select id="prov">
    <option>---请选择省---</option>
</select>
<select id="city">
    <option>---请选择市---</option>
</select>
<select id="dis">
    <option>---请选择县---</option>
</select>
</body>
</html>

view.py

# /areas
def areas(request):
    '''省市县选中案例'''
    return render(request, 'booktest/areas.html')


# /prov
def prov(request):
    '''获取所有省级地区的信息'''
    # 1.获取所有省级地区的信息
    areas = AreaInfo.objects.filter(aParent__isnull=True)

    # 2.变量areas并拼接出json数据:atitle id
    areas_list = []
    for area in areas:
        areas_list.append((area.id, area.atitle))

    # 3.返回数据
    return JsonResponse({
    
    'data':areas_list})


def city(request, pid):
    '''获取pid的下级地区的信息'''
    # 1.获取pid对应地区的下级地区
    # area = AreaInfo.objects.get(id=pid)
    # areas = area.areainfo_set.all()
    areas = AreaInfo.objects.filter(aParent__id=pid)

    # 2.变量areas并拼接出json数据:atitle id
    areas_list = []
    for area in areas:
        areas_list.append((area.id, area.atitle))

    # 3.返回数据
    return JsonResponse({
    
    'data': areas_list})

猜你喜欢

转载自blog.csdn.net/qq_27251475/article/details/120334133