Python学习笔记:7.3.5 Django快速建站 - AJAX

前言:本文是学习网易微专业的《python全栈工程师 - Django快速建站》课程的笔记,欢迎学习交流。同时感谢老师们的精彩传授!

一、课程目标

  • 了解AJAX
  • Django项目中使用AJAX技术
  • 使用JS插件

二、详情解读

2.1.什么是AJAX
  • AJAX:全称是 Asynchronous JavaScript and XML, 即异步JavaScriptXML。它可以用JavaScript向服务器发送必要数据,数据格式有XMLJSON格式的,同时,AJAX也可以接收服务器的反馈。
  • 最大优点,能在不更新整个页面的前提下维护数据。
2.2.上传个人头像
2.2.1.功能描述
  • 在个人信息页面,显示个人头像,上传个人头像。
2.2.2.前端插件
  • 使用JS插件
    – 部署JS插件
    – 在项目中使用

实操一: 下载并导入ImgCrop插件
ImgCrop地址:https://github.com/qiwsir/DjangoPracticeProject/tree/master/ImgCrop

Step1:将imgCrop插件的cssjs文件拷贝到项目的static目录下:

CSS文件:将imgCrop/css/style.css文件复制到myproject/static/css/目录下,并重命名为imagecrop.css
JS文件:将imgCrop/js/目录下的cropbox-min.js、cropbox.js、jquery-1.11.1.min.js复制到myproject/static/js/目录下。

Step2:修改imagecrop.css文件:

.
.
.
.container {
	width: 400px;
	/*将下面这一行注释,并修改后面的一 行*/
	/*margin: 40px auto 0 auto;*/
	margin: 0 auto 0 0;
	position: relative;
	font-family: 微软雅黑;
	font-size: 12px;
}
.
.
.

实操二: 测试ImgCrop插件是否可用

Step1:新增my_image()视图函数。
编辑文件myproject/account/views.py

.
.
.
# 新增下面这个视图函数,在这里是测试imagecrop插件是否可用
def my_image(request):
    return render(request, 'account/imagecrop.html',)

Step2:新建模板文件myproject/templates/account/imagecrop.html

{% load staticfiles %}

<link rel="stylesheet" href="{% static 'css/imagecrop.css' %}" type="text/css" />


<div class="container">
  <div class="imageBox">
    <div class="thumbBox">div>
    <div class="spinner" style="display: none">div>
  div>
  <div class="action">
    
    <div class="new-contentarea tc"> <a href="javascript:void(0)" class="upload-img">
      <label for="upload-file">请先选择图片...label>
      a>
      <input type="file" class="" name="upload-file" id="upload-file" />
    div>
    
    <input type="button" id="btnCrop"  class="Btnsty_peyton" value="OK">
    <input type="button" id="btnZoomIn" class="Btnsty_peyton" value="+"  >
    <input type="button" id="btnZoomOut" class="Btnsty_peyton" value="-" >
  div>
  <div class="cropped">div>
div>

<script type="text/javascript" src="{% static 'js/jquery-1.11.1.min.js' %}">script>
<script type="text/javascript" src="{% static 'js/cropbox.js' %}">script>
<script type="text/javascript">

$(window).load(function() {
	//$('#btnCrop').click();$("#idName").css("cssText","background-color:red!important");

	//$(".imageBox").css("cssText","background-position:88px 88px!important");$(".imageBox").css("cssText","background-size:222px 222px!important");
	var options =
	{
		thumbBox: '.thumbBox',
		spinner: '.spinner',
		imgSrc: ''
	}
	var cropper = $('.imageBox').cropbox(options);
	var img="";
	$('#upload-file').on('change', function(){
		var reader = new FileReader();
		reader.onload = function(e) {
			options.imgSrc = e.target.result;
			cropper = $('.imageBox').cropbox(options);
			getImg();
		}
		reader.readAsDataURL(this.files[0]);
		this.files = [];
		//getImg();
	})
	$('#btnCrop').on('click', function(){
		alert("图片上传喽");
	})
	function getImg(){
		img = cropper.getDataURL();
		$('.cropped').html('');
		$('.cropped').append('+img+'" align="absmiddle" style="width:180px;margin-top:4px;border-radius:180px;box-shadow:0px 0px 12px #7E7E7E;">

180px*180px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:128px;margin-top:4px;border-radius:128px;box-shadow:0px 0px 12px #7E7E7E;">

128px*128px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:64px;margin-top:4px;border-radius:64px;box-shadow:0px 0px 12px #7E7E7E;" >

64px*64px

'
); } $(".imageBox").on("mouseup",function(){ getImg(); }); $('#btnZoomIn').on('click', function(){ cropper.zoomIn(); }) $('#btnZoomOut').on('click', function(){ cropper.zoomOut(); }) });
script> body> html>

Step3:配置路由。myproject/account/urls.py文件增加如下路由:

.
.
.
path('my-image/', views.my_image, name='my_image'),

运行结果:
Python学习笔记:7.3.5 Django快速建站 - AJAX_第1张图片

2.2.3.修改服务端
  • UserInfo模型类:
    photo = models.ImageField(blank=True)
  • 迁移数据
  • 在表单类UserInfoForm中增加photo字段
  • 编写视图函数,接收图片,并保存。

实操三:

Step1 UserInfo模型类中添加 photo字段
编辑文件myproject/account/models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    # 一对一关系
    user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
    phone = models.CharField(max_length=20, null=True)

    def __str__(self):
        return 'user {}'.format(self.user.username)

class UserInfo(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
    company = models.CharField(max_length=100, blank=True)
    profession = models.CharField(max_length=100, blank=True)
    aboutme = models.TextField(blank=True)
    # 新增下面这一行
    photo = models.ImageField(blank=True)

    def __str__(self):
        return "user:{}".format(self.user.username)

说明:
添加的是ImageField(),会要求安装Pillow模块,没安装的运行下面命令安装即可:

pip install Pillow

Step2:迁移数据

python manage.py makemigrations
python manage.py migrate

Step3:在表单类UserInfoForm中增加photo字段

.
.
.
class UserInfoForm(forms.ModelForm):
    class Meta:
        model = UserInfo
        # 下面这和,添加 photo 字段
        fields = ('company', 'profession', 'aboutme', 'photo')

Step4:编写视图函数my_image(),接收图片,并保存。

.
.
.
# 将实操二中的视图函数修改为如下:
@login_required
def my_image(request):
    if request.method == 'POST':
        img = request.POST['img']
        userinfo = UserInfo.objects.get(user=request.user.id)
        userinfo.photo = img
        userinfo.save()
        return HttpResponse('1')
    return render(request, 'account/imagecrop.html',)

说明:
1).上传图片必须是登录用户才可用,因此用@login_required
2).图片是以base64格式保存到数据库中的。

2.2.4.实现AJAX
  • 编辑./account/imagecrop.html,使用ajax上传头像。
  • 编辑./account/myself.html,用来显示头像。

实操四:

step1 编辑myproject/account/imagecrop.html,使用ajax上传头像。

{% load staticfiles %}

<link rel="stylesheet" href="{% static 'css/imagecrop.css' %}" type="text/css" />


<div class="container">
  <div class="imageBox">
    <div class="thumbBox">div>
    <div class="spinner" style="display: none">div>
  div>
  <div class="action">
    
    <div class="new-contentarea tc"> <a href="javascript:void(0)" class="upload-img">
      <label for="upload-file">请先选择图片...label>
      a>
      <input type="file" class="" name="upload-file" id="upload-file" />
    div>
    
    <input type="button" id="btnCrop"  class="Btnsty_peyton" value="OK">
    <input type="button" id="btnZoomIn" class="Btnsty_peyton" value="+"  >
    <input type="button" id="btnZoomOut" class="Btnsty_peyton" value="-" >
  div>
  <div class="cropped">div>
div>

<script type="text/javascript" src="{% static 'js/jquery-1.11.1.min.js' %}">script>
<script type="text/javascript" src="{% static 'js/cropbox.js' %}">script>
<script type="text/javascript">

$(window).load(function() {
	//$('#btnCrop').click();$("#idName").css("cssText","background-color:red!important");

	//$(".imageBox").css("cssText","background-position:88px 88px!important");$(".imageBox").css("cssText","background-size:222px 222px!important");
	var options =
	{
		thumbBox: '.thumbBox',
		spinner: '.spinner',
		imgSrc: ''
	}
	var cropper = $('.imageBox').cropbox(options);
	var img="";
	$('#upload-file').on('change', function(){
		var reader = new FileReader();
		reader.onload = function(e) {
			options.imgSrc = e.target.result;
			cropper = $('.imageBox').cropbox(options);
			getImg();
		}
		reader.readAsDataURL(this.files[0]);
		this.files = [];
		//getImg();
	})
	$('#btnCrop').on('click', function(){
		//alert("图片上传喽");
		// 新增下面的ajax
		$.ajax({
		    url: '{% url "account:my_image" %}',
		    type: 'POST',
		    data: {'img': img},
		    success: function(e) {
		      location.href="{% url 'account:aboutme' %}"
		    }
		}, 'JSON')
	})
	function getImg(){
		img = cropper.getDataURL();
		$('.cropped').html('');
		$('.cropped').append('+img+'" align="absmiddle" style="width:180px;margin-top:4px;border-radius:180px;box-shadow:0px 0px 12px #7E7E7E;">

180px*180px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:128px;margin-top:4px;border-radius:128px;box-shadow:0px 0px 12px #7E7E7E;">

128px*128px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:64px;margin-top:4px;border-radius:64px;box-shadow:0px 0px 12px #7E7E7E;" >

64px*64px

'
); } $(".imageBox").on("mouseup",function(){ getImg(); }); $('#btnZoomIn').on('click', function(){ cropper.zoomIn(); }) $('#btnZoomOut').on('click', function(){ cropper.zoomOut(); }) });
script> body> html>

说明:
1).data:{"img":img}里的"img"对应my_image()视图函数里的request.POST['img']
2).img对应getImg()函数里的img = cropper.getDataURL();

Step2:编辑myproject/account/myself.html,用来显示头像。

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}my information{% endblock %}

{% block content %}
<div class="row text-center vertical-middle-sm">
    <h1>个人信息h1>
    <div class="row">
        <div class="col-md-6">
            <div class="row">
                <div class="col-md-4 text-right"><span>用户名:span>div>
                <div class="col-md-8 text-left">{{ user.username }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>邮箱:span>div>
                <div class="col-md-8 text-left">{{ user.email }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>电话:span>div>
                <div class="col-md-8 text-left">{{ userprofile.phone }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>公司:span>div>
                <div class="col-md-8 text-left">{{ userinfo.company }}div>
            div>
             <div class="row">
                <div class="col-md-4 text-right"><span>职业:span>div>
                <div class="col-md-8 text-left">{{ userinfo.profession }}div>
            div>
             <div class="row">
                <div class="col-md-4 text-right"><span>个人介绍:span>div>
                <div class="col-md-8 text-left">{{ userinfo.aboutme }}div>
            div>
            <a href="{% url 'account:editme' %}">
                <button class="btn btn-primary btn-lg">edit my informationbutton>
            a>
        div>
        
        <div class="col-md-6">
            <div style="margin-right: 100px">
                {% if userinfo.photo %}
                <img src="{{ userinfo.photo | striptags }}" alt="" class="img-circle" id="my_photo">
                {% else %}
                <img src="{% static 'images/djbook.png' %}" alt="">
                {% endif %}
            div>
            <div style="margin-right:100px">
                <button class="btn btn-primary btn-lg" id="upload_image" onclick="upload_image_layer()">上传头像button>
            div>
        div>
    div>
div>
{% endblock %}

说明:
1).注意要加入{% load staticfiles %}这一句,表示要加载静态资源。
2).striptags表示过滤掉userinfo.photo里的html标签

Step3:拷贝csrf.js文件到myproject/static/js/下,并在 myproject/templates/account/imagecrop.html文件中引入csrf.js

.
.
.

<script type="text/javascript" src="{% static 'js/jquery-1.11.1.min.js' %}">script>
<script type="text/javascript" src="{% static 'js/cropbox-min.js' %}">script>

<script type="text/javascript" src="{% static 'js/csrf.js' %}">script>
.
.
.

Step4:下载并引入layer.js

下载地址:http://layer.layui.com/?alone。
将解压后将layer文件夹里的layer.js、mobile、theme文件拷贝到项目下的static/js/目录里。
在文件myproject/templates/account/myself.html里引入layer.js

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}my information{% endblock %}

{% block content %}
<div class="row text-center vertical-middle-sm">
    <h1>个人信息h1>
    <div class="row">
        <div class="col-md-6">
            <div class="row">
                <div class="col-md-4 text-right"><span>用户名:span>div>
                <div class="col-md-8 text-left">{{ user.username }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>邮箱:span>div>
                <div class="col-md-8 text-left">{{ user.email }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>电话:span>div>
                <div class="col-md-8 text-left">{{ userprofile.phone }}div>
            div>
            <div class="row">
                <div class="col-md-4 text-right"><span>公司:span>div>
                <div class="col-md-8 text-left">{{ userinfo.company }}div>
            div>
             <div class="row">
                <div class="col-md-4 text-right"><span>职业:span>div>
                <div class="col-md-8 text-left">{{ userinfo.profession }}div>
            div>
             <div class="row">
                <div class="col-md-4 text-right"><span>个人介绍:span>div>
                <div class="col-md-8 text-left">{{ userinfo.aboutme }}div>
            div>
            <a href="{% url 'account:editme' %}">
                <button class="btn btn-primary btn-lg">edit my informationbutton>
            a>
        div>
        
        <div class="col-md-6">
            <div style="margin-right: 100px">
                {% if userinfo.photo %}
                <img src="{{ userinfo.photo | striptags }}" alt="" class="img-circle" id="my_photo">
                {% else %}
                <img src="{% static 'images/avatar.png' %}" alt="">
                {% endif %}
            div>
            <div style="margin-right:100px">
                <button class="btn btn-primary btn-lg" id="upload_image" onclick="upload_image_layer()">上传头像button>
            div>
        div>
    div>
div>

<script src="{% static 'js/jquery-3.4.1.min.js' %}">script>
<script src="{% static 'js/layer.js' %}">script>
<script>
    function upload_image_layer() {
        layer.open({
            title: '上传头像',
            area: ['600px', '600px'],
            type: 2,
            content: '{% url "account:my_image" %}',
        })
    }
script>
{% endblock %}

说明:
1).引入jquery.jslayer.js
2).增加了弹出层js部分。
3).layer弹出层的使用请参考官网文档:https://www.layui.com/doc/modules/layer.html

此时,当点击”上传头像“时,会有一个弹出层,
Python学习笔记:7.3.5 Django快速建站 - AJAX_第2张图片
不足之处是,点击”ok“后,会在这个弹出层显示个人信息,显然不是我们想要的,进入下一个步骤。
Python学习笔记:7.3.5 Django快速建站 - AJAX_第3张图片
Step5:编辑文件myproject/templates/account/imagecrop.html

{% load staticfiles %}

<link rel="stylesheet" href="{% static 'css/imagecrop.css' %}" type="text/css" />


<div class="container">
  <div class="imageBox">
    <div class="thumbBox">div>
    <div class="spinner" style="display: none">div>
  div>
  <div class="action">
    
    <div class="new-contentarea tc"> <a href="javascript:void(0)" class="upload-img">
      <label for="upload-file">请先选择图片...label>
      a>
      <input type="file" class="" name="upload-file" id="upload-file" />
    div>
    
    <input type="button" id="btnCrop"  class="Btnsty_peyton" value="OK">
    <input type="button" id="btnZoomIn" class="Btnsty_peyton" value="+"  >
    <input type="button" id="btnZoomOut" class="Btnsty_peyton" value="-" >
  div>
  <div class="cropped">div>
div>

<script type="text/javascript" src="{% static 'js/jquery-1.11.1.min.js' %}">script>
<script type="text/javascript" src="{% static 'js/cropbox-min.js' %}">script>
<script type="text/javascript" src="{% static 'js/csrf.js' %}">script>
<script type="text/javascript">

$(window).load(function() {
	//$('#btnCrop').click();$("#idName").css("cssText","background-color:red!important");

	//$(".imageBox").css("cssText","background-position:88px 88px!important");$(".imageBox").css("cssText","background-size:222px 222px!important");
	var options =
	{
		thumbBox: '.thumbBox',
		spinner: '.spinner',
		imgSrc: ''
	}
	var cropper = $('.imageBox').cropbox(options);
	var img="";
	$('#upload-file').on('change', function(){
		var reader = new FileReader();
		reader.onload = function(e) {
			options.imgSrc = e.target.result;
			cropper = $('.imageBox').cropbox(options);
			getImg();
		}
		reader.readAsDataURL(this.files[0]);
		this.files = [];
		//getImg();
	})
	$('#btnCrop').on('click', function(){
		//alert("图片上传喽");
		$.ajax({
		    url: '{% url "account:my_image" %}',
		    type: 'POST',
		    data: {'img': img},
		    success: function(e) {
		      //location.href="{% url 'account:aboutme' %}"
		      if (e == '1') {
		        parent.location.reload()
		      } else {
		        alert('图片上传失败')
		      }
		    }
		}, 'JSON')
	})
	function getImg(){
		img = cropper.getDataURL();
		$('.cropped').html('');
		$('.cropped').append('+img+'" align="absmiddle" style="width:180px;margin-top:4px;border-radius:180px;box-shadow:0px 0px 12px #7E7E7E;">

180px*180px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:128px;margin-top:4px;border-radius:128px;box-shadow:0px 0px 12px #7E7E7E;">

128px*128px

'
); $('.cropped').append('+img+'" align="absmiddle" style="width:64px;margin-top:4px;border-radius:64px;box-shadow:0px 0px 12px #7E7E7E;" >

64px*64px

'
); } $(".imageBox").on("mouseup",function(){ getImg(); }); $('#btnZoomIn').on('click', function(){ cropper.zoomIn(); }) $('#btnZoomOut').on('click', function(){ cropper.zoomOut(); }) });
script> body> html>

说明:
修改了ajax里上传图片成功后里的函数。parent.location.reload()表示重新加载弹出层的父页面,此时弹出层关闭。

2.2.5.继续优化上传
  • 使用插件
    – 根据文档要求部署
    – 编写弹出层

三、课程小结

  • AJAXjs插件能够帮助我们解决很多前端的问题,使我们操作起来更便捷,web开发中的后端和前端,我们会经常使用类似这样的插件来实现某些功能。

你可能感兴趣的:(Python全栈工程师学习笔记)