需要学习的内容
1. 视图
1. url匹配过程
注册应用
配置模板文件
配置数据库
init设置pymysql
设置包含应用的urls文件
配置应用urls文件或views
2. 错误视图
3. 捕获url参数
- 总结:
4. 登录案例
-
views.py
def login(request): '''显示登录页面''' return render(request,'booktest/login.html') def login_check(request): '''登录校验视图''' #request.POST保存的是post方式提交的参数 QueryDict # request.GET保存的是get方式提交的参数 #1. 获取提交的用户名和密码 username=request.POST.get('username') password=request.POST.get('password') #2. 进行登录的校验 #实际开发:根据用户和密码查找数据库 #模拟:smart 123 if username=='smart' and password=='123': #用户名密码正确,跳转到首页 return redirect('/index') else: #用户名或密码错误,跳转到登录页面 return redirect('/login')
-
urls.py
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^index$',views.index) ,#首页 url(r'^showarg(\d+)', views.showarg), url(r'^login$',views.login), #显示登录页面 url(r'^login_check$',views.login_check), ]
-
html
-
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/login_check"> 用户名:<input type="text" name="username"><br/> 密码:<input type="password" name="password"><br/> <input type="submit" value="登录"> </form> </body> </html>
-
- 总结
5. ajax请求
-
test_ajax.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ajax</title> <script src="/static/js/jquery.min.js"></script> <script> $(function () { $('#btnAjax').click(function () { alert(1) $.ajax({ 'url':'/ajax_handle', 'type':'get', 'dataType':'json', 'async':false, //同步的ajax请求 }).success(function (data) { alert('2') //进行处理 if (data.res == 1){ $('#message').show().html('提示信息') } else $('#message').show().html('错误') }) alert(3) }) }) </script> <style> #message{ display: none; color: red; } </style> </head> <body> <input type="button" id="btnAjax" value="ajax请求"> <div id="message"></div> </body> </html>
-
urls.py
def ajax_test(request): return render(request,'booktest/test_ajax.html') def ajax_handle(request): print('66') return JsonResponse({'res':1})
6. Ajax登录案例
def login_ajax_check(request):
'''ajax登录页面'''
username=request.POST.get('username')
password = request.POST.get('password')
if username == 'smart' and password== '123':
return JsonResponse({'res':1}) #ajax请求在后台,不要返回页面或者重定向
else:
return JsonResponse({'res':0})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax登录页面</title>
<script src="/static/js/jquery.min.js"></script>
<script>
$(function () {
$('#btnLOGIN').click(function () {
// 获取用户密码
// 发起ajax请求
username = $('#username').val()
password = $('#password').val()
$.ajax({
'url':'/login_ajax_check',
'type':'post',
'dataType':'json',
'data':{'username':username,'password':password}
}).success(function (data) {
if (data.res==0){
$('#errmsg').show().html('用户名密码不正确')
}
else {
location.href = '/index'
}
})
})
})
</script>
<style>
#errmsg{
display: none;
color: red;
}
</style>
</head>
<body>
用户名:<input type="text" id="username"><br/>
密码:<input type="password" id="password"><br/>
<input type="submit" id="btnLOGIN" value="登录">
</form>
<div id="errmsg"></div>
</body>
</html>
7. Cookie与Session
7.1 cookie
1. 设置cookie
def set_cookie(request):
res=HttpResponse('设置setcookie')
res.set_cookie('num',1,max_age=14*24*3600) #设置一个cookie值 name:num vaulue:1 max_age过期时间
# res.set_cookie('num',1,expires=datetime.now()+timedelta(days=14))
return res
def get_cookie(request):
num = request.COOKIES['num']
return HttpResponse(num)
2. cookie记住用户名
def login(request):
'''显示登录页面'''
# 获取登录用户名
if 'username' in request.COOKIES:
username = request.COOKIES['username']
else:
username = ''
return render(request,'booktest/login.html',{'username':username})
def login_check(request):
'''登录校验视图'''
#request.POST保存的是post方式提交的参数 QueryDict
# request.GET保存的是get方式提交的参数
#1. 获取提交的用户名和密码
username=request.POST.get('username')
password=request.POST.get('password')
remember = request.POST.get('remember')
print(remember)
#2. 进行登录的校验
#实际开发:根据用户和密码查找数据库
#模拟:smart 123
if username=='smart' and password=='123':
#用户名密码正确,跳转到首页
response = redirect('/index')
if remember == 'on':
# 设置cookie 过期时间为1周
response.set_cookie('username',username,max_age=7*24*3600)
return response
else:
#用户名或密码错误,跳转到登录页面
return redirect('/login')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form method="post" action="/login_check">
用户名:<input type="text" name="username" value="{{ username }}"><br/>
密码:<input type="password" name="password"><br/>
<input type="checkbox" name="remember">记住用户名</br>
<input type="submit" value="登录">
</form>
</body>
</html>
7.2 session
1. session过程
2. session的存储与特点
3. 设置与获取session
def set_session(request):
'''设置session'''
request.session['username'] = 'smart'
request.session['age'] = 18
return HttpResponse('设置session')
def get_session(request):
'''获取session'''
username = request.session['username']
age = request.session['age']
return HttpResponse(username+':'+str(age))
- 展示
- 数据库记录
- 通过sessionid来获取session的值
4. session对象及方法
def set_session(request):
'''设置session'''
request.session['username'] = 'smart'
request.session['age'] = 18
request.session.set_expiry(5)
return HttpResponse('设置session')
def get_session(request):
'''获取session'''
username = request.session['username']
age = request.session['age']
return HttpResponse(username+':'+str(age))
def clear_session(request):
'''清除所有session'''
request.session.clear() # clear 删除值的部分
request.session.flush() # flush 删除整条数据
return HttpResponse('清除成功')
def login(request):
'''显示登录页面'''
# 判断用户是否登录
if request.session.has_key('islogin'): #通过sessionid获取
return redirect('/index')
else:
# 获取登录用户名
if 'username' in request.COOKIES:
username = request.COOKIES['username']
else:
username = ''
return render(request,'booktest/login.html',{'username':username})
def login_check(request):
'''登录校验视图'''
#request.POST保存的是post方式提交的参数 QueryDict
# request.GET保存的是get方式提交的参数
#1. 获取提交的用户名和密码
username=request.POST.get('username')
password=request.POST.get('password')
remember = request.POST.get('remember')
print(remember)
#2. 进行登录的校验
#实际开发:根据用户和密码查找数据库
#模拟:smart 123
if username=='smart' and password=='123':
#用户名密码正确,跳转到首页
response = redirect('/index')
if remember == 'on':
# 设置cookie 过期时间为1周
response.set_cookie('username',username,max_age=7*24*3600)
# 记住用户登录状态
request.session['islogin'] =True
return response
else:
#用户名或密码错误,跳转到登录页面
return redirect('/login')
7.3 应用场景及案例
2. 模板
1. 模板变量
def temp_var(request):
my_dict = {'title':'字典'}
my_list = [1,2,3]
book = BookInfo.objects.get(id=1)
context = {'my_dict':my_dict, 'my_list':my_list, 'book':book}
return render(request,'booktest/temp_var',context)
<!DOCTYPE html>
<br lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<br>
使用字典:{{ my_dict.title }}</br>
使用列表:{{ my_list.1 }}</br>
对象属性:{{ book.btitle }}
</body>
</html>
2. 模板标签
逻辑运算:not and or
django内置标签与过滤器文档
-
temp_tags
def temp_tags(request): """模板标签""" books = models.BookInfo.objects.all() return render(request, 'booktest/temp_tags.html', {'books': books})
-
temp_tags.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板标签</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .red {background-color: red;} .blue {background-color: blue;} .gray {background-color: gray;} </style> </head> <body> <h1>模板标签</h1> <ul> {% for book in books %} {% if book.id <= 2 %} <li class="red">{{ forloop.counter }}--{{ book.btitle }}</li> {% elif book.id <= 3 %} <li class="blue">{{ forloop.counter }}--{{ book.btitle }}</li> {% else %} <li class="gray">{{ forloop.counter }}--{{ book.btitle }}</li> {% endif %} {% endfor %} </ul> </body> </html>
3. 过滤器
- views.py
def temp_filter(request): """模板过滤器""" books = models.BookInfo.objects.all() return render(request, 'booktest/temp_filter.html', {'books': books})
- temp_filter.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板过滤器</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .red {background-color: red;} .blue {background-color: blue;} .gray {background-color: gray;} </style> </head> <body> <h1>模板标签</h1> <ul> {% for book in books %} {% if book.id <= 2 %} <li class="red">{{ book.btitle }}--{{ book.bpub_date|date:'Y年-m月-d日' }}</li> {% else %} {# 加了length后,会将原来的图书名编程图书名长度的数字 #} <li class="gray">{{ book.btitle|length }}--{{ book.bpub_date }}</li> {% endif %} {% endfor %} </ul> default过滤器: {# 如果content没有值,则过滤器会显示默认的值 #} {{ content|default:"hello" }} </body> </html>
自定义过滤器
-
自定义过滤器
1.在自己的应用下面新建一个 templatetags 文件夹,名字固定;
2.在templatetags文件夹下面新建一个py文件,名字自定义,比如filters.py;
3.1.在文件中,引入Library类;
3.2.创建一个Library类的对象;
3.3.定义自己的函数,给函数添加装饰器@register.filter进行过滤器装饰;
-
使用自定义装饰器
1.在需要使用的html文件中导入自定义装饰器文件,{% load filters %},即 load 文件名;
2.使用过滤器;
示例
-
testbook.templatetags.filters.py
from django.template import Library # 创建一个Library类的对象 register = Library() # 注册过滤器 @register.filter def mod(num): """判断num是否为偶数""" # 如果传过来的num是偶数,则返回True,否则返回False return num % 2 == 0
<!DOCTYPE html> <html lang="en"> {# 加载文件名 #} {% load filters %} <head> <meta charset="UTF-8"> <title>模板过滤器</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .red {background-color: red;} .blue {background-color: blue;} .gray {background-color: gray;} </style> </head> <body> <h1>模板标签</h1> <ul> {% for book in books %} {% if book.id|mod %} <li class="red">{{ book.id }}--{{ book.btitle }}--{{ book.bpub_date|date:'Y-m-d' }}</li> {% else %} <li class="gray">{{ book.btitle }}--{{ book.bpub_date }}</li> {% endif %} {% endfor %} </ul> </body> </html> html使用一个参数的过滤器
两个参数的自定义过滤器
# 自定义的过滤器,最少有一个参数,最多有两个参数
# 只有一个参数的话,由|前面的参数传过来,两个参数的话,:后面再跟一个参数
# 应注意过滤器参数的前后顺序
@register.filter
def mod_val(num, val):
"""判断num是否能把value整除"""
return num % val == 0
<ul>
{% for book in books %}
{# {% if book.id <= 2 %} #}
{# % if book.id|mod %} #}
{% if book.id|mod_val:3 %}
<li class="red">{{ book.id }}--{{ book.btitle }}--{{ book.bpub_date|date:'Y-m-d' }}</li>
{% else %}
{# 加了length后,会将原来的图书名编程图书名长度的数字 #}
<li class="gray">{{ book.btitle|length }}--{{ book.bpub_date }}</li>
{% endif %}
{% endfor %}
</ul>
4. 模板注释
模板注释的内容在网页源代码中看不到
5. 模板继承
父模板
在父模板里可以定义块,使用标签:
{% block 块名 %}
块中间可以写内容,也可以不写
{% endblock 块名%}
子模板
子模板去继承父模板之后,可以重写父模板中的某一块的内容。
继承格式:
{% extends 父模板文件路径%}
{% block 块名 %}
{{ block.super}} #获取父模板中块的默认内容
重写的内容
{% endblock 块名%}
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}base模板文件的title{% endblock title %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>base模板的header</h1>
{% block b1 %}
<h2>base父模板的block1</h2>
{% endblock b1 %}
{% block b2 %}
<h2>base模板的block2</h2>
{% endblock b2 %}
<h1>base模板的footer</h1>
</body>
</html>
{% extends 'booktest/base.html' %}
{% block title %}child模板中的title{% endblock title %}
{% block b1 %}
{{ block.super }}
<h2>child模板的block1</h2>
{% endblock b1 %}
{% block b2 %}
<h2>child模板的block2</h2>
{% endblock b2 %}
<h1>base模板的footer</h1>
</body>
</html>
6. 转义
场景:
编辑商品详情信息,数据表中保存的是html内容。
在模板上下文中的html标记默认是会被转义的。
模板硬编码中的字符串默认不会经过转义,如果需要转义,那需要手动进行转义。
小于号< 转换为<
大于号> 转换为>
单引号' 转换为'
双引号" 转换为 "
与符号& 转换为 &
safe和autoescape的区别
safe只能转义一个模板变量,而autoescape可以转义多个变量;
示例
# /html_escape
def html_escape(request):
"""模板转义"""
return render(request, 'booktest/html_escape.html', {'content': '<h1>hello</h1>'})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板转义</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
html转义结果:<br>
{{ content }}<br>
使用safe过滤器关闭转义结果:<br>
{{ content|safe }}<br>
使用autoescape关闭转义结果:<br>
{% autoescape off %}
{{ content }}
{{ content }}
{% endautoescape %}<br>
模板硬编码中的字符串默认不会转义,即会经过html渲染:<br>
{{ test|default:'<h1>hello</h1>' }}<br>
手动对硬编码进行转义:<br>
{{ test|default:'<h1>hello</h1>' }}
</body>
</html>
3. django功能-静态文件、中间件、后台
1. 静态文件static
settings.py
#设置访问静态文件对应的url地址
STATIC_URL = '/static/'
#设置静态文件存放的物理目录
STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]
views.py
from django.shortcuts import render
from django.conf import settings
# Create your views here.
# /static_test
def static_test(request):
'''静态文件'''
print(settings.STATICFILES_FINDERS)
return render(request,'booktest/static_test.html')
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>静态文件</title>
</head>
<body>
<img src="/static/images/1.png"><br/>
动态获取STATIC_URL,拼接静态文件路径:<br/>
<img src="{% static 'images/1.png' %}">
</body>
</html>
2. 中间件
在booktest应用下新建middleware.py文件.
定义中间件类,中间件类的名字可以自己起,但是类里面的中间件函数名不可以随便起,这些函数都是Django预留的接口.
定义限制ip登录装饰器
def blocked_ips(view_func):
def wrapper(request, *view_args, **view_kwargs):
user_ip = request.META['REMOTE_ADDR'] # 获取浏览器端的ip地址
if user_ip in EXCLUDE_IPS: #['127.0.0.1']
return HttpResponse('<h1>您的ip被禁止</h1>')
else:
return view_func(request, *view_args, **view_kwargs)
return wrapper
定义中间件类禁止IP
booktest/middleware.py
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class BlockedIPSMiddleware(MiddlewareMixin):
'''中间件类'''
EXCLUDE_IPS = ['127.0.0.1']
def process_view(self,request,view_func,*view_arg,**view_kwargs):
'''视图函数调用之前会调用'''
user_ip=request.META['REMOTE_ADDR'] #获取浏览器端的ip地址
if user_ip in BlockedIPSMiddleware.EXCLUDE_IPS:
return HttpResponse('<h1>Forbidden</h1>')
中间件demo
middleware.py
class TestMiddleware(object):
'''中间件类'''
def __init__(self):
'''服务器重启之后接受第一个请求时候调用'''
print('__init__')
def process_request(self,request):
'''产生request之后,url匹配之前调用'''
print('process_request中间件函数')
def process_view(self,request,view_func,*view_args,**view_kwargs):
'''url匹配之后,视图函数调用之前'''
print('process_view')
def process_response(self,request, response):
'''视图函数调用之后,内容返回浏览器之前'''
print('process_response')
return response
class ExceptionTestMiddleware(MiddlewareMixin):
# 如果注册多个process_exception函数,那么函数的执行顺序与注册的顺序相反。(其他中间件函数与注册顺序一致)
# 中间件函数,用到哪个就写哪个,不需要写所有的中间件函数。
def process_exception(self, request, exception):
'''视图函数发生异常时调用'''
print('----process_exception1----')
print(exception)
中间件的设定与使用
_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
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.middleware.TestMiddleware',
]
4.admin后台管理
列表页选项
创建管理员的用户名和密码。
- 按提示填写用户名、邮箱、密码。
python manage.py createsuperuser
注册模型类
-
admin.py
from django.contrib import admin from booktest.models import BookInfo # Register your models here. # 自定义模型管理类 class BookInfoAdmin(admin.ModelAdmin): '''图书模型管理类''' list_per_page = 5 #定义每页显示5条信息 list_display = ['id', 'title', 'btitle','bpub_date'] # 使后台数据按行显示,title为models返回的方法 admin.site.register(BookInfo,BookInfoAdmin)
- 定义父级属性
- 定义父级属性
控制管理页展示
# 图书类
class BookInfo(models.Model):
'''图书模型类'''
btitle = models.CharField(verbose_name='标题2',max_length=20)
bpub_date = models.DateField()
# 返回值类型
def __str__(self):
return self.btitle
# 改变后台显示的列名
def title(self):
return self.btitle
# 方法列是不能排序的,如果需要排序需要为方法指定排序依据。(点击列标题可排序)
title.admin_order_field = 'btitle'
# 更改标题
title.short_description = '标题'
"操作选项"的位置
admin.py
# 自定义模型管理类
class BookInfoAdmin(admin.ModelAdmin):
'''图书模型管理类'''
list_per_page = 5 #定义每页显示5条信息
list_display = ['id', 'title', 'btitle','bpub_date'] # 使后台数据按行显示,title为models返回的方法
# 顶部显示的属性,设置为True在顶部显示,设置为False不在顶部显示,默认为True
actions_on_bottom = True
# 底部显示的属性,设置为True在底部显示,设置为False不在底部显示,默认为False。
actions_on_top = False
右侧栏过滤器
list_filter = ['btitle'] # 右侧栏过滤器
搜索框
属性如下,用于对指定字段的值进行搜索,支持模糊查询。列表类型,表示在这些字段上进行搜索。
search_fields = ['atitle'] # 搜索框
https://www.cnblogs.com/kayb/articles/7257620.html
编辑页选项
编辑字段
fields与fieldsets两者选一使用
# fields = ['btitle','bpub_date'] #显示字段顺序
fieldsets = (
('基本',{'fields':['btitle']}),
('高级', {'fields': ['bpub_date']}),
) #分组显示
关联对象
关联对象
-
在一对多的关系中,可以在一端的编辑页面中编辑多端的对象,嵌入多端对象的方式包括表格、块两种
-
类型InlineModelAdmin:表示在模型的编辑页面嵌入关联模型的编辑
-
子类TabularInline:以表格的形式嵌入
-
子类StackedInline:以块的形式嵌入
booktest/admin.py,创建AreaStackedInline类
from django.contrib import admin
from booktest.models import BookInfo, AreaInfo
# Register your models here.
class AreaStackedInline(admin.StackedInline):
'''写多类的名字'''
model = AreaInfo
extra = 2 #额外编辑2个子对象
# 自定义模型管理类
class BookInfoAdmin(admin.ModelAdmin):
'''图书模型管理类'''
...
# fields = ['btitle'] #显示编辑页的字段
fieldsets = (
('基本',{'fields':['btitle']}),
('高级', {'fields': ['bpub_date']}),
)
inlines = [AreaStackedInline]
重写模板
模板文件加载顺序
-
1.首先会到配置模板路径下找模板文件
-
2.如果上一布没找到,之后会到项目中的setting.py中去找INSTALLED_APPS中每个应用下面去找模板文件,前提是应用中有templates文件夹
打开当前虚拟环境中Django的目录,再向下找到admin的模板,目录如下
/home/python/.virtualenvs/py_django/lib/python2.7/site-packages/django/contrib/admin/templates/admin
在templates/目录下创建admin目录,结构如下图
其它后台的模板可以按照相同的方式进行修改
上传文件
配置
项目的setting里面配置
MEDIA_ROOT = os.path.join(BASE_DIR,'static/media') #设置上传文件的保存目录
在static文件夹里新建media文件夹
model.py
class PicTest(models.Model):
'''上传图片'''
good_pic = models.ImageField(upload_to='booktest') #相对于media的文件目录
-
需要重新
python manage.py makemigrations # 迁移文件 python manage.py migrate #更新到数据库
如果有
django.db.utils.OperationalError: (1050, "Table 'booktest_pictest' already exists")
的报错,则在 数据库中django_migrations删除对应的迁移文件,并更改migrations文件夹下的迁移文件的值删除文件的值
migrations.CreateModel( name='AreaInfo', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('atitle', models.CharField(max_length=20)), ('aParent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='booktest.AreaInfo')), ], ),
后台上传
django会自动识别你的上传文件是否为图片类型
用户上传
uoload_pic.html
注意表单一定要是post方式,还有enctype参数,以及csrf防护.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>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
def show_upload(request):
return render(request,'booktest/upload_pic.html')
def upload_handle(request):
'''上传图片处理'''
# 1.拿到上传文件的处理对象
pic = request.FILES['pic']
# print(pic.name)
# print(pic.chunks)
# <bound method InMemoryUploadedFile.chunks of <InMemoryUploadedFile: 捕获3.PNG (image/png)>>
# 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(good_pic='booktest/%s'%pic.name)
# 5.返回
return HttpResponse('ok')
分页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>分页</title>
</head>
<body>
<ul>
{% for area in page %}
<li>{{ area.atitle }}</li>
{% endfor %}
</ul>
{% if page.has_previous %} {# 判断是否有上一页 #}
<a href="/show_area{{ page.previous_page_number }}">上一页</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 }}">下一页</a>
{% endif %}
</body>
</html>
# insert into booktest_areainfo value('110000','京城',NULL);
# insert into booktest_areainfo value('110100','北京市','110000');
# insert into booktest_areainfo value('110001','东城区','110100');
# insert into booktest_areainfo value('110002','西城区','110100');
# insert into booktest_areainfo value('110003','丰台区','110100');
# 前段访问需要传递页码
from django.core.paginator import Paginator
def show_area(request,pindex):
'''分页'''
# 1. 查询信息
areas = AreaInfo.objects.filter() #aParent__isnull=True 父级为空
print(areas)
# 2. 分页,每条显示2条数据
paginator = Paginator(areas, 2)
# print(paginator.num_pages) # 3
# print(paginator.page_range) # range(1, 4)
# 3. 获取第pindex页内容
if pindex == '':
# 默认取第一页
pindex=1
else:
pindex = int(pindex)
page =paginator.page(pindex) #返回分页后的数据
# return render(request,'booktest/show_area.html',{'areas':areas})
return render(request,'booktest/show_area.html',{'page':page})
urls.py
url(r'^show_area(?P<pindex>\d*)', views.show_area), #分页
实现 省 市 县 自关联的下拉级联
urls.py
url(r'^areas$', views.getAreas), # 省市县下拉选择联动
url(r'^prov$',views.getProvince), # ajax请求处理页,返回所有省
url(r'^city<pid>',views.city), # ajax请求处理页,返回所有市
url(r'^dis<pid>',views.city), # ajax请求处理页,返回所有县,因为和市所用过程相同,所以使用同一个处理函数city
views.py
# 级联菜单
def getAreas(request):
return render(request,'booktest/areas.html')
#获得省份
def getProvince(request):
provinces = AreaInfo.objects.filter()# aParent__isnull = True
res = []
for i in provinces:
res.append( [i.id , i.atitle] )
print(res)
return JsonResponse({'provinces':res})
#获得城市
def getCity(request):
city_id = request.GET.get('city_id')
cities = AreaInfo.objects.filter(aParent_id=city_id)
res = []
for i in cities:
res.append([i.id, i.atitle])
return JsonResponse({'cities':res})
#获得区 县
def getDistrict(request):
district_id = request.GET.get('district_id')
cities = AreaInfo.objects.filter(aParent_id=district_id)
res = []
for i in cities:
res.append([i.id, i.atitle])
return JsonResponse({'district': res})
areas.html
<!DOCTYPE html>
<html>
<head>
<title>下拉表-省市联动</title>
</head>
{% load static %}
<!-- <script src="{% static 'js/jquery.js' %}"></script> -->
<script src="/static/js/jquery.min.js"></script>
<script>
$(function(){
$.get('/prov',function(data){
res=data.data //【1】返回的数据
prov=$('#prov') //【2】得到省份的DOM位置
/*//【方法1】循环处理get请求返回的数据
for (i =0; i<res.length; i++) {
id=res[i][0] //【1】得到返回数据的ID
title=res[i][1] //【2】得到返回的标题
//【3】拼接option字段
option_str='<option value="'+id + '">'+ title+ '</option>'
prov.append(option_str) //【4】把数据逐个添加到省的下拉列表中
}*/
//【方法2】循环处理get请求返回的数据
$.each(res,function(index,item){
console.log(index)
console.log(item)
id=item[0]
title=item[1]
option_str='<option value="'+id + '">'+ title+ '</option>'
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>
<body>
<select id='prov'>
<option>下拉选择省</option>
</select>
<select id='city'>
<option>下拉选择市</option>
</select>
<select id='dis'>
<option>下拉选择县</option>
</select>
</body>
</html>