一, 管理静态文件
项目中的 CSS, 图片, js 都是静态文件
配置静态文件
在 settings 文件中定义静态内容
- STATIC_URL = '/static/'
- STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
- ]
在项目根目录下创建 static 目录, 再创建当前应用名称的目录
mysite/static/myapp/
在模板中可以使用硬编码
/static/my_app/myexample.jpg
在模板中可以使用 static 编码
{ % load static from staticfiles %}
<img src="{ % static"my_app/myexample.jpg"%}" alt="My image"/>
二, 中间件
是一个轻量级, 底层的插件系统, 可以介入 Django 的请求和响应处理过程, 修改 Django 的输入或输出
激活: 添加到 Django 配置文件中的 MIDDLEWARE_CLASSES 元组中
每个中间件组件是一个独立的 Python 类, 可以定义下面方法中的一个或多个
_init _: 无需任何参数, 服务器响应第一个请求的时候调用一次, 用于确定是否启用当前中间件
process_request(request): 执行视图之前被调用, 在每个请求上调用, 返回 None 或 HttpResponse 对象
process_view(request, view_func, view_args, view_kwargs): 调用视图之前被调用, 在每个请求上调用, 返回 None 或 HttpResponse 对象
process_template_response(request, response): 在视图刚好执行完毕之后被调用, 在每个请求上调用, 返回实现了 render 方法的响应对象
process_response(request, response): 所有响应返回浏览器之前被调用, 在每个请求上调用, 返回 HttpResponse 对象
process_exception(request,response,exception): 当视图抛出异常时调用, 在每个请求上调用, 返回一个 HttpResponse 对象
使用中间件, 可以干扰整个处理过程, 每次请求中都会执行中间件的这个方法
示例: 自定义异常处理
与 settings.py 同级目录下创建 myexception.py 文件, 定义类 MyException, 实现 process_exception 方法
- from django.http import HttpResponse
- class MyException():
- def process_exception(request,response, exception):
- return HttpResponse(exception.message)
将类 MyException 注册到 settings.py 中间件中
- MIDDLEWARE_CLASSES = (
- 'test1.myexception.MyException',
- ...
- )
定义视图, 并发生一个异常信息, 则会运行自定义的异常处理
三, 上传图片
当 Django 在处理文件上传的时候, 文件数据被保存在 request.FILES
FILES 中的每个键为 < input type="file" name="" />中的 name
注意: FILES 只有在请求的方法为 POST 且提交的 < form > 带有 enctype="multipart/form-data" 的情况下才会包含数据. 否则, FILES 将为一个空的类似于字典的对象
使用模型处理上传文件: 将属性定义成 models.ImageField 类型
pic=models.ImageField(upload_to='cars/')
注意: 如果属性类型为 ImageField 需要安装包 Pilow
pip install Pillow==3.4.1
图片存储路径
在项目根目录下创建 media 文件夹
图片上传后, 会被保存到 "/static/media/cars / 图片文件"
打开 settings.py 文件, 增加 media_root 项
MEDIA_ROOT=os.path.join(BASE_DIR,"static/media")
使用 django 后台管理, 遇到 ImageField 类型的属性会出现一个 file 框, 完成文件上传
手动上传的模板代码
- <html>
- <head>
- <title > 文件上传</title>
- </head>
- <body>
- <form method="post" action="upload/" enctype="multipart/form-data">
- <input type="text" name="title"><br>
- <input type="file" name="pic"/><br>
- <input type="submit" value="上传">
- </form>
- </body>
- </html>
手动上传的视图代码
- from django.conf import settings
- def upload(request):
- if request.method == "POST":
- f1 = request.FILES['pic']
- fname = '%s/cars/%s' % (settings.MEDIA_ROOT,f1.name)
- with open(fname, 'w') as pic:
- for c in f1.chunks():
- pic.write(c)
- return HttpResponse("ok")
- else:
- return HttpResponse("error")
四, Admin 站点
通过使用 startproject 创建的项目模版中, 默认 Admin 被启用
1. 创建管理员的用户名和密码
python manage.py createsuperuser
然后按提示填写用户名, 邮箱, 密码
2. 在应用内 admin.py 文件完成注册, 就可以在后台管理中维护模型的数据
- from django.contrib import admin
- from models import *
- admin.site.register(HeroInfo)
查找 admin 文件: 在 INSTALLED_APPS 项中加入 django.contrib.admin,Django 就会自动搜索每个应用的 admin 模块并将其导入
ModelAdmin 对象
ModelAdmin 类是模型在 Admin 界面中的表示形式
定义: 定义一个类, 继承于 admin.ModelAdmin, 注册模型时使用这个类
- class HeroAdmin(admin.ModelAdmin):
- ...
通常定义在应用的 admin.py 文件里
使用方式一: 注册参数
admin.site.register(HeroInfo,HeroAdmin)
使用方式二: 注册装饰器
- @admin.register(HeroInfo)
- class HeroAdmin(admin.ModelAdmin):
通过重写 admin.ModelAdmin 的属性规定显示效果, 属性主要分为列表页, 增加修改页两部分
列表页选项
"操作选项" 的位置
actions_on_top,actions_on_bottom: 默认显示在页面的顶部
- class HeroAdmin(admin.ModelAdmin):
- actions_on_top = True
- actions_on_bottom = True
- list_display
出现列表中显示的字段
列表类型
在列表中, 可以是字段名称, 也可以是方法名称, 但是方法名称默认不能排序
在方法中可以使用 format_html()输出 html 内容
在 models.py 文件中
- from django.db import models
- from tinymce.models import HTMLField
- from django.utils.html import format_html
- class HeroInfo(models.Model):
- hname = models.CharField(max_length=10)
- hcontent = HTMLField()
- isDelete = models.BooleanField()
- def hContent(self):
- return format_html(self.hcontent)
在 admin.py 文件中
- class HeroAdmin(admin.ModelAdmin):
- list_display = ['hname', 'hContent']
让方法排序, 为方法指定 admin_order_field 属性
在 models.py 中 HeroInfo 类的代码改为如下:
- def hContent(self):
- return format_html(self.hcontent)
- hContent.admin_order_field = 'hname'
标题栏名称: 将字段封装成方法, 为方法设置 short_description 属性
在 models.py 中为 HeroInfo 类增加方法 hName:
- def hName(self):
- return self.hname
- hName.short_description = '姓名'
- hContent.short_description = '内容'
在 admin.py 页中注册
- class HeroAdmin(admin.ModelAdmin):
- list_display = ['hName', 'hContent']
- list_filter
右侧栏过滤器, 对哪些属性的值进行过滤
列表类型
只能接收字段
- class HeroAdmin(admin.ModelAdmin):
- ...
- list_filter = ['hname', 'hcontent']
- list_per_page
每页中显示多少项, 默认设置为 100
- class HeroAdmin(admin.ModelAdmin):
- ...
- list_per_page = 10
- search_fields
搜索框
列表类型, 表示在这些字段上进行搜索
只能接收字段
- class HeroAdmin(admin.ModelAdmin):
- ...
- search_fields = ['hname']
增加与修改页选项
fields: 显示字段的顺序, 如果使用元组表示显示到一行上
- class HeroAdmin(admin.ModelAdmin):
- ...
- fields = [('hname', 'hcontent')]
fieldsets: 分组显示
- class HeroAdmin(admin.ModelAdmin):
- ...
- fieldsets = (
- ('base', {'fields': ('hname')}),
- ('other', {'fields': ('hcontent')})
- )
fields 与 fieldsets 两者选一
InlineModelAdmin 对象
类型 InlineModelAdmin: 表示在模型的添加或修改页面嵌入关联模型的添加或修改
子类 TabularInline: 以表格的形式嵌入
子类 StackedInline: 以块的形式嵌入
- class HeroInline(admin.TabularInline):
- model = HeroInfo
- class BookAdmin(admin.ModelAdmin):
- inlines = [
- HeroInline,
- ]
重写 admin 模板
在项目所在目录中创建 templates 目录, 再创建一个 admin 目录
设置模板查找目录: 修改 settings.py 的 TEMPLATES 项, 加载模板时会在 DIRS 列表指定的目录中搜索
'DIRS': [os.path.join(BASE_DIR, 'templates')],
从 Django 安装的目录下 (django/contrib/admin/templates) 将模板页面的源文件 admin/base_site.html 拷贝到第一步建好的目录里
编辑 base_site.html 文件
刷新页面, 发现以刚才编辑的页面效果显示
其它管理后台的模板可以按照相同的方式进行修改
五, 分页
Django 提供了一些类实现管理数据分页, 这些类位于 django/core/paginator.py 中
Paginator 对象
Paginator(列表, int): 返回分页对象, 参数为列表数据, 每面数据的条数
属性
count: 对象总数
num_pages: 页面总数
page_range: 页码列表, 从 1 开始, 例如[1, 2, 3, 4]
方法
page(num): 下标以 1 开始, 如果提供的页码不存在, 抛出 InvalidPage 异常
异常 exception
InvalidPage: 当向 page()传入一个无效的页码时抛出
PageNotAnInteger: 当向 page()传入一个不是整数的值时抛出
EmptyPage: 当向 page()提供一个有效值, 但是那个页面上没有任何对象时抛出
Page 对象
创建对象
Paginator 对象的 page()方法返回 Page 对象, 不需要手动构造
属性
object_list: 当前页上所有对象的列表
number: 当前页的序号, 从 1 开始
paginator: 当前 page 对象相关的 Paginator 对象
方法
has_next(): 如果有下一页返回 True
has_previous(): 如果有上一页返回 True
has_other_pages(): 如果有上一页或下一页返回 True
next_page_number(): 返回下一页的页码, 如果下一页不存在, 抛出 InvalidPage 异常
previous_page_number(): 返回上一页的页码, 如果上一页不存在, 抛出 InvalidPage 异常
len(): 返回当前页面对象的个数
迭代页面对象: 访问当前页面中的每个对象
示例
创建视图 pagTest
- from django.core.paginator import Paginator
- def pagTest(request, pIndex):
- list1 = AreaInfo.objects.filter(aParent__isnull=True)
- p = Paginator(list1, 10)
- if pIndex == '':
- pIndex = '1'
- pIndex = int(pIndex)
- list2 = p.page(pIndex)
- plist = p.page_range
- return render(request, 'booktest/pagTest.html', {'list': list2, 'plist': plist, 'pIndex': pIndex})
配置 url
url(r'^pag(?P<pIndex>[0-9]*)/$', views.pagTest, name='pagTest'),
定义模板 pagTest.html
- <!DOCTYPE html>
- <html>
- <head>
- <title></title>
- </head>
- <body>
- <ul>
- {%for area in list%}
- <li>{{area.id}}--{{area.atitle}}</li>
- {%endfor%}
- </ul>
- {%for pindex in plist%}
- {%if pIndex == pindex%}
- {{pindex}}
- {%else%}
- <a href="/pag{{pindex}}/">{{pindex}}</a>
- {%endif%}
- {%endfor%}
- </body>
- </html>
六, 使用 Ajax
使用视图通过上下文向模板中传递数据, 需要先加载完成模板的静态页面, 再执行模型代码, 生成最张的 html, 返回给浏览器, 这个过程将页面与数据集成到了一起, 扩展性差
改进方案: 通过 ajax 的方式获取数据, 通过 dom 操作将数据呈现到界面上
推荐使用框架的 ajax 相关方法, 不要使用 XMLHttpRequest 对象, 因为操作麻烦且不容易查错
jquery 框架中提供了 $.ajax,$.get,$.post 方法, 用于进行异步交互
由于 csrf 的约束, 推荐使用 $.get
示例: 实现省市区的选择
引入 js 文件
js 文件属于静态文件:
修改 settings.py 关于静态文件的设置
- STATIC_URL = '/static/'
- STATICFILES_DIRS = [
- os.path.join(BASE_DIR, 'static'),
- ]
在 models.py 中定义模型
- class AreaInfo(models.Model):
- aid = models.IntegerField(primary_key=True)
- atitle = models.CharField(max_length=20)
- aPArea = models.ForeignKey('AreaInfo', null=True)
生成迁移
- python manage.py makemigrations
- python manage.py migrate
通过 workbench 向表中填充数据
在 views.py 中编写视图
index 用于展示页面
getArea1 用于返回省级数据
getArea2 用于根据省, 市编号返回市, 区信息, 格式都为字典对象
- from django.shortcuts import render
- from django.http import JsonResponse
- from models import AreaInfo
- def index(request):
- return render(request, 'ct1/index.html')
- def getArea1(request):
- list = AreaInfo.objects.filter(aPArea__isnull=True)
- list2 = []
- for a in list:
- list2.append([a.aid, a.atitle])
- return JsonResponse({'data': list2})
- def getArea2(request, pid):
- list = AreaInfo.objects.filter(aPArea_id=pid)
- list2 = []
- for a in list:
- list2.append({'id': a.aid, 'title': a.atitle})
- return JsonResponse({'data': list2})
在 urls.py 中配置 urlconf
- from django.conf.urls import url
- from . import views
- urlpatterns = [
- url(r'^$', views.index),
- url(r'^area1/$', views.getArea1),
- url(r'^([0-9]+)/$', views.getArea2),
- ]
主 urls.py 中包含此应用的 url
- from django.conf.urls import include, url
- from django.contrib import admin
- urlpatterns = [
- url(r'^', include('ct1.urls', namespace='ct1')),
- url(r'^admin/', include(admin.site.urls)),
- ]
定义模板 index.html
在项目中的目录结构如图:
修改 settings.py 的 TEMPLATES 项, 设置 DIRS 值
'DIRS': [os.path.join(BASE_DIR, 'templates')],
定义模板文件: 包含三个 select 标签, 分别存放省市区的信息
- <!DOCTYPE html>
- <html>
- <head>
- <title > 省市区列表</title>
- </head>
- <body>
- <select id="pro">
- <option value="">请选择省</option>
- </select>
- <select id="city">
- <option value="">请选择市</option>
- </select>
- <select id="dis">
- <option value="">请选择区县</option>
- </select>
- </body>
- </html>
在模板中引入 jquery 文件
<script type="text/javascript" lazyload="static/ct1/js/jquery-1.12.4.min.js"></script>
编写 js 代码
绑定 change 事件
发出异步请求
使用 dom 添加元素
- <script type="text/javascript">
- $(function(){
- $.get('area1/',function(dic) {
- pro=$('#pro')
- $.each(dic.data,function(index,item){
- pro.append('<option value='+item[0]+'>'+item[1]+'</option>');
- })
- });
- $('#pro').change(function(){
- $.post($(this).val()+'/',function(dic){
- city=$('#city');
- city.empty().append('<option value="">请选择市</option>');
- $.each(dic.data,function(index,item){
- city.append('<option value='+item.id+'>'+item.title+'</option>');
- })
- });
- });
- $('#city').change(function(){
- $.post($(this).val()+'/',function(dic){
- dis=$('#dis');
- dis.empty().append('<option value="">请选择区县</option>');
- $.each(dic.data,function(index,item){
- dis.append('<option value='+item.id+'>'+item.title+'</option>');
- })
- })
- });
- });
- </script>
四, 其它(一)
来源: http://www.bubuko.com/infodetail-2583846.html