Python Django总结②

需要学习的内容
在这里插入图片描述

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标记默认是会被转义的。

模板硬编码中的字符串默认不会经过转义,如果需要转义,那需要手动进行转义。

小于号< 转换为&lt;
大于号> 转换为&gt;
单引号' 转换为&#39;
双引号" 转换为 &quot;
与符号& 转换为 &amp;

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:'&lt;h1&gt;hello&lt;/h1&gt;' }}
</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>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值