Django入门(五)之ModelForm操作、原生Ajax、伪Ajax、文件上传和图片验证码生成

上一篇文章>Django入门(四)之Session操作、CSRF操作、自定义中间件、缓存、信号和Form组件

一、本机环境


操作系统:Red Hat Enterprise Linux Server release 7.3 (Maipo)
Python版本:python3.6
Django版本:Django-2.1.5

1、创建项目

[root@python _Django]# tree newproject1
newproject1
├── app
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       └── __init__.cpython-36.pyc
│   ├── models.py
│   ├── __pycache__
│   │   ├── admin.cpython-36.pyc
│   │   ├── __init__.cpython-36.pyc
│   │   └── models.cpython-36.pyc
│   ├── tests.py
│   └── views.py
├── manage.py
├── newproject1
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── settings.cpython-36.pyc
│   │   ├── urls.cpython-36.pyc
│   │   └── wsgi.cpython-36.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── static
│   ├── jquery-1.12.4.min.js
│   └── jquery.cookie-1.4.1.min.js
└── templates

2、生成数据库表

[root@python newproject1]# vim app/models.py
from django.db import models

class UserType(models.Model):
    caption = models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField()
    user_type = models.ForeignKey(to='UserType', to_field='id', on_delete=models.CASCADE)
[root@python newproject1]# python manage.py makemigrations
[root@python newproject1]# python manage.py migrate

二、Form和ModelForm方法对比


1、Form方法

(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path
from app import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32)
    email = fields.EmailField()
    user_type = fields.ChoiceField(
        choices = models.UserType.objects.values_list('id', 'caption')
    )

    def __init__(self, *args, **kwargs):
        super(UserInfoForm,self).__init__(*args, **kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'caption')

def index(request):
    if request.method == "GET":
        obj = UserInfoForm()
        return render(request,'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoForm(request.POST)
        obj.is_valid()
        obj.errors
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request,'index.html',{'obj':obj})
(3)配置HTML
[root@python newproject1]# vim templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="submit" value="提交" />
    </form>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/index/

在这里插入图片描述

2、ModelForm方法

适用于小程序,因为耦合度较高!!!

(1)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models

### 其实是获取了models.py的UserInfo内容
class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        ### 显示所有结果
        fields = '__all__'
        ### 只显示这2个参数
		# fields = ['username','email']
		### 显示除了此参数结果
		# exclude = ['username']
		
def index(request):
    if request.method == "GET":
        ### 修改此处
        obj = UserInfoModelForm()
        return render(request,'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoForm(request.POST)
        print (obj.is_valid())
        print (obj.cleaned_data)
        print (obj.errors)
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request,'index.html',{'obj':obj})
(2)访问并查看结果

我们可以发现就User type不同,其他都一样!!!

http://10.10.10.111:8000/index/

在这里插入图片描述
三、ModelForm操作


1、自定义label

在app_usertype中随意添加一个数据!!!
也可以在views中通过labels参数进行设置!!!

[root@python newproject1]# vim app/models.py   ###添加verbose_name参数

在这里插入图片描述

http://10.10.10.111:8000/index/

在这里插入图片描述

在这里插入图片描述

2、ModelForm参数

class Meta:
	model,                           ###对应Model
	fields=None,                     ###字段
	exclude=None,                    ###排除
	labels=None,                     ###label设置,views中:labels={'username':'用户名',}
	help_texts=None,                 ###提示信息
	widgets=None,                    ###自定义插件,eg:导入:from django.forms import widgets as Fwidgets -->> widgets = {'username':Fwidgets.Textarea(attrs={'class': 'c1'})}
	error_messages=None,             ###自定义错误信息,error_messages = {'email':{'required': '邮箱不能为空','invalid': '邮箱格式错误'}}也可以通过"__all__"来设置整体报错信息
	field_classes=None,              ###自定义字段类,from django.forms import fields as Ffields,field_classes = {'email': Ffields.URLField}
	localized_fields=('birth_date')  ###本地化,eg:根据不同时区显示数据

3、通过ModelForm实现多对多

在app_usergroup表中插入2条数据!!!

(1)配置models.py
[root@python newproject1]# vim app/models.py
from django.db import models
class UserType(models.Model):
    caption = models.CharField(max_length=32)

class UserGroup(models.Model):
    name = models.CharField(max_length=32)
    
class UserInfo(models.Model):
    username = models.CharField(verbose_name='用户名', max_length=32)
    email = models.EmailField()
    user_type = models.ForeignKey(to='UserType', to_field='id', on_delete=models.CASCADE)
    u2g = models.ManyToManyField(UserGroup)

(2)更新数据库
[root@python newproject1]# python manage.py makemigrations
[root@python newproject1]# python manage.py migrate
(3)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = '__all__'
        # fields = ['username','email']
        # exclude = ['username']

def index(request):
    if request.method == "GET":
        ### 修改此处
        obj = UserInfoModelForm()
        return render(request,'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoModelForm(request.POST)
        if obj.is_valid():
            obj.save()
            ### 等同于下面3句
            # instance = obj.save(False)
            # instance.save()
            # obj.save_m2m()
        # print (obj.is_valid())
        # print (obj.cleaned_data)
        # print (obj.errors)
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request,'index.html',{'obj':obj})
(4)访问并查看结果
[root@python newproject1]# python manage.py runserver 10.10.10.111:8000

在这里插入图片描述
可以发现app_userinfo_u2g表中有表对应的选项!!!

4、ModelForm实现多表提交数据

(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('user_list/', views.user_list),
    re_path('user_edit-(\d+)/', views.user_edit),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = '__all__'
        # fields = ['username','email']
        # exclude = ['username']

def index(request):
    if request.method == "GET":
        ### 修改此处
        obj = UserInfoModelForm()
        return render(request, 'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoModelForm(request.POST)
        if obj.is_valid():
            obj.save()
        # print (obj.is_valid())
        # print (obj.cleaned_data)
        # print (obj.errors)
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li = models.UserInfo.objects.all().select_related('user_type')
    return render(request, 'user_list.html', {'li': li})

def user_edit(request, nid):
    if request.method == "GET":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        mf = UserInfoModelForm(instance=user_obj)
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
    elif request.method == "POST":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        ### 如果不写instance将会增加数据,而不是修改
        mf = UserInfoModelForm(request.POST, instance=user_obj)
        if mf.is_valid():
            mf.save()
        else:
            print (mf.errors.as_json())
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
(3)配置HTML

<1> 配置user_list.html

[root@python newproject1]# vim templates/user_list.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for row in li %}
            <li>{row.username}-{{ row.user_type.caption }}-<a href="/user_edit-{{ row.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
</body>
</html>

<2> 配置user_edit.html

[root@python newproject1]# vim templates/user_edit.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/user_edit-{{ nid }}/" method="POST">
        {% csrf_token %}
        {{ mf.as_p }}
        <input type="submit" value="提交" />
    </form>
</body>
</html>
(4)运行并访问

可以进行编辑,并修改数据,实现对多表的操作!!!

http://10.10.10.111:8000/user_list/

5、自定制标签

(1)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
    is_rem = fields.CharField(
        widget = Fwidgets.CheckboxInput()
    )
    class Meta:
        model = models.UserInfo
        fields = '__all__'
        # fields = ['username','email']
        # exclude = ['username']

def index(request):
    if request.method == "GET":
        ### 修改此处
        obj = UserInfoModelForm()
        return render(request, 'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoModelForm(request.POST)
        if obj.is_valid():
            obj.save()
        # print (obj.is_valid())
        # print (obj.cleaned_data)
        # print (obj.errors)
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li = models.UserInfo.objects.all().select_related('user_type')
    return render(request, 'user_list.html', {'li': li})


def user_edit(request, nid):
    if request.method == "GET":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        mf = UserInfoModelForm(instance=user_obj)
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
    elif request.method == "POST":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        ### 如果不写instance将会增加数据,而不是修改
        mf = UserInfoModelForm(request.POST, instance=user_obj)
        if mf.is_valid():
            mf.save()
        else:
            print (mf.errors.as_json())
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
(2)访问并查看结果
http://10.10.10.111:8000/index/

在这里插入图片描述

四、原生Ajax


1、XmlHttpRequest对象方法

void open(String method,String url,Boolen async)
   用于创建请求
    
   参数:
       method: 请求方式(字符串类型),如:POST、GET、DELETE...
       url:    要请求的地址(字符串类型)
       async:  是否异步(布尔类型)
 
void send(String body)
    用于发送请求
 
    参数:
        body: 要发送的数据(字符串类型)
 
void setRequestHeader(String header,String value)
    用于设置请求头
 
    参数:
        header: 请求头的key(字符串类型)
        vlaue:  请求头的value(字符串类型)
 
String getAllResponseHeaders()
    获取所有响应头
 
    返回值:
        响应头数据(字符串类型)
 
String getResponseHeader(String header)
    获取响应头中指定header的值
 
    参数:
        header: 响应头的key(字符串类型)
 
    返回值:
        响应头中指定的header对应的值
 
void abort()
    终止请求

2、XmlHttpRequest对象属性

Number readyState
   状态值(整数)
 
   详细:
      0-未初始化,尚未调用open()方法;
      1-启动,调用了open()方法,未调用send()方法;
      2-发送,已经调用了send()方法,未接收到响应;
      3-接收,已经接收到部分响应数据;
      4-完成,已经接收到全部响应数据;
 
Function onreadystatechange
   当readyState的值改变时自动触发执行其对应的函数(回调函数)
 
String responseText
   服务器返回的数据(字符串类型)
 
XmlDocument responseXML
   服务器返回的数据(Xml对象)
 
Number states
   状态码(整数),如:200、404...
 
String statesText
   状态文本(字符串),如:OK、NotFound...

3、Ajax实例(get)

(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('user_list/', views.user_list),
    re_path('user_edit-(\d+)/', views.user_edit),
    re_path('ajax/$',views.ajax),
    re_path('ajax_json/$',views.ajax_json),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
    is_rem = fields.CharField(
        widget = Fwidgets.CheckboxInput()
    )
    class Meta:
        model = models.UserInfo
        fields = '__all__'
        # fields = ['username','email']
        # exclude = ['username']
        
def index(request):
    if request.method == "GET":
        ### 修改此处
        obj = UserInfoModelForm()
        return render(request, 'index.html', {'obj': obj})
    elif request.method == "POST":
        obj = UserInfoModelForm(request.POST)
        if obj.is_valid():
            obj.save()
        # print (obj.is_valid())
        # print (obj.cleaned_data)
        # print (obj.errors)
        # models.UserInfo.objects.create(**obj.cleaned_data)
        # models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li = models.UserInfo.objects.all().select_related('user_type')
    return render(request, 'user_list.html', {'li': li})

def user_edit(request, nid):
    if request.method == "GET":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        mf = UserInfoModelForm(instance=user_obj)
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })
    elif request.method == "POST":
        user_obj = models.UserInfo.objects.filter(id=nid).first()
        ### 如果不写instance将会增加数据,而不是修改
        mf = UserInfoModelForm(request.POST, instance=user_obj)
        if mf.is_valid():
            mf.save()
        else:
            print (mf.errors.as_json())
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid, })

def ajax(request):
    return render(request,'ajax.html')

def ajax_json(request):
    r = {'code': True, 'data': None}
    import json
    # return HttpResponse(json.dumps(r), status=404,reason='Not Found')
    return HttpResponse(json.dumps(r))
(3)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
    function Ajax1() {
        var xhr = new XMLHttpRequest();
        xhr.open("GET",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        // 发送请求头,可以发送CSRF
        xhr.setRequestHeader('k1','v1');
        xhr.send('name=dream;pwd=1');
    }
</script>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/ajax/     ###控制台查看network

4、Ajax实例(post)

这里我是吧setting中的CSRF注释掉了!!!

(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
    function Ajax1() {
        var xhr = new XMLHttpRequest();
        xhr.open("POST",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=dream;pwd=1');
    }
</script>
</body>
</html>
(2)配置views.py
[root@python newproject1]# vim app/views.py        ###添加

在这里插入图片描述

(3)访问并查看结果
http://10.10.10.111:8000/ajax/

在这里插入图片描述

5、实现兼容性

[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<script>
    // 判断浏览器
    function getXHR() {
        var xhr = null;
        if(XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr =new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    }
    
    function Ajax1() {
        var xhr = getXHR();
        xhr.open("POST",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=dream;pwd=1');
    }
</script>
</body>
</html>

五、伪Ajax


1、通过iframe实现发送请求

(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />
<input type="text" id="url" />
<input type="button" value="iframe请求" onclick="iframeRequest();" />
<iframe id="ifm" src="http://www.dreamya.top"></iframe>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
    // 判断浏览器
    function getXHR() {
        var xhr = null;
        if(XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr =new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    };

    function Ajax1() {
        var xhr = getXHR();
        xhr.open("POST",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=dream;pwd=1');
    };
    function iframeRequest() {
        var url = $('#url').val();
        $('#ifm').attr('src',url);
    };
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/

在这里插入图片描述

2、伪Ajax请求

(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />

<!--<input type="text" id="url" />-->
<!--<input type="button" value="iframe请求" onclick="iframeRequest();" />-->
<!--<iframe id="ifm" src="http://www.dreamya.top"></iframe>-->

<form action="/ajax_json/" method="POST" target="ifm1">
    <iframe name="ifm1"></iframe>
    <input type="text" name="username">
    <input type="text" name="email">
    <input type="submit" value="Form提交">
</form>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
    // 判断浏览器
    function getXHR() {
        var xhr = null;
        if(XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr =new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    };

    function Ajax1() {
        var xhr = getXHR();
        xhr.open("POST",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=dream;pwd=1');
    };
    // function iframeRequest() {
    //     var url = $('#url').val();
    //     $('#ifm').attr('src',url);
    // };
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/

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

3、iframe返回数据

(1)配置HTML
[root@python newproject1]# vim templates/ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="Ajax1" onclick="Ajax1();" />

<form action="/ajax_json/" method="POST" target="ifm1">
    <iframe id="ifm1" name="ifm1"></iframe>
    <input type="text" name="username">
    <input type="text" name="email">
    <input type="submit" value="Form提交" onclick="submitForm();">
</form>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
    // 判断浏览器
    function getXHR() {
        var xhr = null;
        if(XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr =new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    };

    function Ajax1() {
        var xhr = getXHR();
        xhr.open("POST",'/ajax_json/',true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                // 接收完毕数据
                // var v = xhr.responseText;

                //JSON格式
                var v = JSON.parse(xhr.responseText)
                console.log(v);
            }
        };
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=dream;pwd=1');
    };

    function submitForm() {
        $('#ifm1').load(function () {
            var t = $('#ifm1').contents().find('body').text();
            var obj = JSON.parse(t);
            console.log(obj);
        })
    }
</script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/ajax/     ###可以在控制台看到返回内容

六、文件上传


优先用iframe方式来实现,兼容性更好,jquery和原生方式都要基于FormData!!!

1、原生方式实现

(1)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('user_list/', views.user_list),
    re_path('user_edit-(\d+)/', views.user_edit),
    re_path('ajax/$',views.ajax),
    re_path('ajax_json/$',views.ajax_json),
    re_path('upload/$',views.upload),
    re_path('upload_file/$',views.upload_file),
]
(2)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
def upload(request):
    return render(request,'upload.html')

def upload_file(request):
    username = request.POST.get('username')
    uploadFile = request.FILES.get('uploadFile')
    print(username,uploadFile)
    with open(uploadFile.name,'wb') as f:
        for item in uploadFile.chunks():
            f.write(item)
    r = {'code': True, 'data': None}
    import json
    return HttpResponse(json.dumps(r))
(3)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .upload{
            display: inline-block;
            padding: 10px;
            background-color: deepskyblue;
            position: absolute;
            top: 0px;
            right: 0px;
            bottom: 0px;
            left: 0px;
            z-index: 90;
        }
        .file{
            width: 100px;height: 60px;opacity: 0;
            position: absolute;
            top: 0px;
            right: 0px;
            bottom: 0px;
            left: 0px;
            z-index: 100;
        }
    </style>
</head>
<body>
    <div style="position: relative;width: 100px;height: 60px;">
        <input class="file" type="file" id="uploadFile" name="uploadFile" />
        <a class="upload">上传</a>
    </div>
    <input type="button" value="提交XHR" onclick="xhrSubmit();" />
    <script>
        function xhrSubmit() {
            // 这里是个对象
            var file_obj = document.getElementById('uploadFile').files[0];
            var fd = new FormData();
            fd.append('username','root');
            fd.append('uploadFile',file_obj);

            var xhr = new XMLHttpRequest();
            xhr.open('POST','/upload_file/', true);
            xhr.onreadystatechange = function () {
                if(xhr.readyState == 4){
                    var obj = JSON.parse(xhr.responseText);
                    console.log(obj);
                }
            };
            xhr.send(fd);
        }
    </script>
</body>
</html>
(4)访问并查看结果
http://10.10.10.111:8000/upload/

2、jquery方式

(1)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .upload{
            display: inline-block;
            padding: 10px;
            background-color: deepskyblue;
            position: absolute;
            top: 0px;
            right: 0px;
            bottom: 0px;
            left: 0px;
            z-index: 90;
        }
        .file{
            width: 100px;height: 60px;opacity: 0;
            position: absolute;
            top: 0px;
            right: 0px;
            bottom: 0px;
            left: 0px;
            z-index: 100;
        }
    </style>
</head>
<body>
    <div style="position: relative;width: 100px;height: 60px;">
        <input class="file" type="file" id="uploadFile" name="uploadFile" />
        <a class="upload">上传</a>
    </div>
    <input type="button" value="提交jquery" onclick="jqSubmit();">
    <script src="/static/jquery-1.12.4.min.js"></script>
    <script>
        function jqSubmit() {
            var file_obj = document.getElementById('uploadFile').files[0];
            var fd = new FormData();
            fd.append('username','root');
            fd.append('uploadFile',file_obj);
            $.ajax({
                url: '/upload_file/',
                type: 'POST',
                data: fd,
                processData: false,
                contentType: false,
                success:function (a,b,c) {
                    console.log(a);
                    console.log(b);
                    console.log(c);
                }
            })
        }
    </script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/upload/

3、iframe方式

(1)配置HTML
[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
    <iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
    <input type="file" name="uploadFile">
    <input type="submit" value="iframe提交" onclick="iframeForm();">
</form>
    <script>
        function iframeForm() {
        $('#ifm1').load(function () {
            var t = $('#ifm1').contents().find('body').text();
            var obj = JSON.parse(t);
            console.log(obj);
        })
    }
    </script>
</body>
</html>
(2)访问并查看结果
http://10.10.10.111:8000/upload/

4、实现图片预览

上传的文件都保存在static目录下!!!

(1)通过按钮提交

<1> 配置views.py

[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
def upload(request):
    return render(request,'upload.html')

def upload_file(request):
    username = request.POST.get('username')
    uploadFile = request.FILES.get('uploadFile')
    import os
    img_path = os.path.join('static/',uploadFile.name)
    with open(img_path,'wb') as f:
        for item in uploadFile.chunks():
            f.write(item)
    r = {'code': True, 'data': img_path}
    import json
    return HttpResponse(json.dumps(r))

<2> 配置HTML

[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
    <iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
    <input type="file" name="uploadFile" />
    <input type="submit" value="iframe提交" onclick="iframeForm();">
</form>
    <div id="preview"></div>
    <script src="/static/jquery-1.12.4.min.js"></script>
    <script>
        function iframeForm() {
        $('#ifm1').load(function () {
            var t = $('#ifm1').contents().find('body').text();
            var obj = JSON.parse(t);

            $('#preview').empty();
            var imgTag = document.createElement('img');
            imgTag.src = "/" + obj.data;
            $('#preview').append(imgTag);
        })
    };
    </script>
</body>
</html>

<3> 访问并查看结果

http://10.10.10.111:8000/upload/
(2)自动上传

<1> 配置HTML

[root@python newproject1]# vim templates/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
    <iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
    <input type="file" name="uploadFile" onchange="changeUpload();">
    <!--<input type="submit" value="iframe提交" onclick="iframeForm();">-->
</form>
    <div id="preview"></div>
    <script src="/static/jquery-1.12.4.min.js"></script>
    <script>
        function changeUpload() {
            $('#ifm1').load(function () {
            var t = $('#ifm1').contents().find('body').text();
            var obj = JSON.parse(t);

            $('#preview').empty();
            var imgTag = document.createElement('img');
            imgTag.src = "/" + obj.data;
            $('#preview').append(imgTag);
            });
            $('#form1').submit();
        }
    </script>
</body>
</html>

<2> 访问并查看结果

http://10.10.10.111:8000/upload/

七、图片验证码+Session


1、安装pillow

(1)下载安装

下载地址:https://pypi.org/project/Pillow/5.4.1/#files
联网安装:pip install pillow

[root@python ~]# wget https://files.pythonhosted.org/packages/3c/7e/443be24431324bd34d22dd9d11cc845d995bcd3b500676bcf23142756975/Pillow-5.4.1.tar.gz
[root@python ~]# cd Pillow-5.4.1/
[root@python mnt]# tar xf Pillow-5.4.1.tar.gz
[root@python Pillow-5.4.1]# python setup.py install
(2)报错解决

<1> 报错:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "setup.py", line 812, in <module>
    raise RequiredDependencyException(msg)
__main__.RequiredDependencyException: 

The headers or library files could not be found for jpeg,
a required dependency when compiling Pillow from source.

Please see the install instructions at:
   https://pillow.readthedocs.io/en/latest/installation.html

<2> 安装依赖

[root@python mnt]# yum install -y python-devel zlib-devel  libjpeg-turbo-devel
[root@python Pillow-5.4.1]# python setup.py install

<3> 测试结果

[root@python Pillow-5.4.1]# python
Python 3.6.0 (default, Jan  8 2019, 05:27:57) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image

2、验证码生成

并在utils目录下放个Monaco.ttf字体文件,百度网盘链接:https://pan.baidu.com/s/1e4o-6rcoHvlijTIEo0cvNA 提取码: v3x9

(1)配置check_code.py
[root@python newproject1]# mkdir utils/
[root@python newproject1]# vim utils/check_code.py
#!/usr/bin/env python
#coding:utf-8
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter

_letter_cases = "abcdefghjkmnpqrstuvwxy"      ### 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper()          ### 大写字母
_numbers = ''.join(map(str, range(3, 10)))    ### 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))

def create_validate_code(size=(120, 30),
                         chars=init_chars,
                         img_type="GIF",
                         mode="RGB",
                         bg_color=(255, 255, 255),
                         fg_color=(0, 0, 255),
                         font_size=18,
                         font_type="utils/Monaco.ttf",
                         length=4,
                         draw_lines=True,
                         n_line=(1, 2),
                         draw_points=True,
                         point_chance=2):
    """
    @todo: 生成验证码图片
    @param size: 图片的大小,格式(宽,高),默认为(120, 30)
    @param chars: 允许的字符集合,格式字符串
    @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
    @param mode: 图片模式,默认为RGB
    @param bg_color: 背景颜色,默认为白色
    @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
    @param font_size: 验证码字体大小
    @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
    @param length: 验证码字符个数
    @param draw_lines: 是否划干扰线
    @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
    @param draw_points: 是否画干扰点
    @param point_chance: 干扰点出现的概率,大小范围[0, 100]
    @return: [0]: PIL Image实例
    @return: [1]: 验证码图片中的字符串
    """

    width, height = size  # 宽高
    ### 创建图形
    img = Image.new(mode, size, bg_color)
    draw = ImageDraw.Draw(img)  # 创建画笔

    def get_chars():
        """生成给定长度的字符串,返回列表格式"""
        return random.sample(chars, length)

    def create_lines():
        """绘制干扰线"""
        line_num = random.randint(*n_line)  # 干扰线条数

        for i in range(line_num):
            # 起始点
            begin = (random.randint(0, size[0]), random.randint(0, size[1]))
            # 结束点
            end = (random.randint(0, size[0]), random.randint(0, size[1]))
            draw.line([begin, end], fill=(0, 0, 0))

    def create_points():
        """绘制干扰点"""
        chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]

        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    def create_strs():
        """绘制验证码字符"""
        c_chars = get_chars()
        strs = ' %s ' % ' '.join(c_chars)  # 每个字符前后以空格隔开

        font = ImageFont.truetype(font_type, font_size)
        font_width, font_height = font.getsize(strs)

        draw.text(((width - font_width) / 3, (height - font_height) / 3),
                  strs, font=font, fill=fg_color)

        return ''.join(c_chars)

    if draw_lines:
        create_lines()
    if draw_points:
        create_points()
    strs = create_strs()

    ### 图形扭曲参数
    params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
              1 - float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
              ]
    img = img.transform(size, Image.PERSPECTIVE, params)  # 创建扭曲
    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜,边界加强(阈值更大)
    return img, strs
(2)配置urls.py
[root@python newproject1]# vim newproject1/urls.py
from django.contrib import admin
from django.urls import path,re_path
from app import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('user_list/', views.user_list),
    re_path('user_edit-(\d+)/', views.user_edit),
    re_path('ajax/$',views.ajax),
    re_path('ajax_json/$',views.ajax_json),
    re_path('upload/$',views.upload),
    re_path('upload_file/$',views.upload_file),
    re_path('code/$',views.get_code),
    path('code_img.html/',views.code_img),
]
(3)配置views.py
[root@python newproject1]# vim app/views.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from app import models
from django.forms import widgets as Fwidgets
...
from io import BytesIO
from utils.check_code import create_validate_code
### 验证码页面
def get_code(request):
    return render(request,'code.html')

def code_img(request):
    ### 创建一个内存地址存放图片
    f = BytesIO()
    ### 调用方法生成图片对象和验证码
    img, code = create_validate_code()
    ### 设置session
    request.session['check_code'] = code
    print(code)
    ### 保存图片
    img.save(f, 'PNG')
    return HttpResponse(f.getvalue())
(4)配置HTML
[root@python newproject1]# vim templates/code.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img src="/code_img.html" id="code_img">
<script src="/static/jquery-1.12.4.min.js" type="text/javascript"></script>
<script>
    $('#code_img').click(function () {
    this.src = this.src + '?';
    })
</script>
</body>
</html>
(5)访问并查看结果
http://10.10.10.111:8000/code/

在这里插入图片描述
在这里插入图片描述
下一篇文章>Django入门(六)之搜索功能、JSONP实现跨域请求、XSS过滤和单例模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wielun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值