昨日内容回顾
BBS
项目流程
需求分析
项目设计(架构设计,框架选择,数据库...报价)
分任务开发(小组成员开发)
测试(测试)
交付上线(运行)
用户表(AbstractUser) settings文件一定要告诉django AUTH_USER_MODEL = 'app01.UserInfo'
phone
avatar
create_time
blog 一对一个人站点
个人站点(Blog)
site_name
site_title
site_theme
分类表
name
blog 一对多个人站点
标签表
name
blog 一对多个人站点
文章表
title
desc
content
create_time
# 数据库优化
comment_num
up_num
down_num
blog 一对多个人站点
category 一对多分类表
tag 多对多标签表
点赞点踩表
user 一对多用户
article 一对多文章
is_up 0/1
评论表
user 一对多用户
article 一对多文章
comment
parent to='self',null=True
1.写forms组件
username
password
confirm_password
# 局部钩子 校验用户名是否存在
# 全局钩子 校验密码是否一致
2.搭建注册页面
1.利用forms组件渲染前端页面,手动添加获取用户头像的input框
2.将img标签放入label中,将input框隐藏
3.利用文件阅读器动态展示用户上传的头像
注意:需要等待文件阅读器读取完毕之后再赋值给src属性,利用onload
4.ajax发送post请求
利用内置对象FormData传递数据
利用form标签序列化数组
手动获取文件对象$('[input="file"]')[0].files[0]
formdata发数据需要手动修改两个参数
processData:false
contentType:false
后端
利用cleaned_data是一个大字典特性,将confirm_password键值去掉
手动获取用户头像,判断用户是否上传头像,再决定要不要放入cleaned_data字典中
利用**{}将字典打散成关键字参数的形式
ps:在用ajax做前后端交互的时候通常后端都会实现定义一个字典作为数据交互的媒介
ps:img标签src属性可以放文件路径,也可以放文件二进制数据,还可以放url!
今日内容
登录
图片验证码
主页搭建
图片相关功能模块
pip3 install pillow
django settings文件逻辑
用户配置了就用用户的
用户没有配置就用默认的
博客园给用户用的,肯定要一张表是记录用户信息的,每一个用户都有属于自己的站点,所以有个人站点表,个人站点表有文章的标签和文章的分类,
所以有文章标签表和文章分类表,你给多少篇文章添加了标签,一个分类下有多少篇文章,方便找寻,你创建一个标签就会有一个标签的名字在那,
那就相当于有个东西帮你记住了,那就是一张表
每个人创建的标签的名字可以一样也可以不一样,分类和标签放着一篇篇文章,文章表里又有点赞点踩数,一个用户只能给一篇文章点赞点踩一次,
后端记录着数据来判断你是否点赞点踩过,所以要有张点赞点菜表来记录,记录哪个用户给哪篇文章点赞点菜过,评论:评论人,评论内容,
评论的文章,这个东西也是存在一张表里,那时候渲染文章的时候也是把你相关的评论渲染出来,
用户表继承auth模块,登录注册,注销,修改密码等等都已经封装好了
每一篇文章,你在渲染的时候,需要帮文章的点赞数点菜数,评论都拿出来,虽然再另一个表中,但是这么多篇文章,
每篇文章都要去跨表查询的话,增加数据库的压力,可以有一些普通的字段存着,
到时候这些字段只需要保证跟另一张表的数据同步删除和同步更新就好了,我就不需要跨表了,只需要查看我的字段,
到时候在面试的时候是可以说的,表设计的时候有那么几个字段,虽然再另外一张表存在但是查询频率比较高,
然后我在我这张表中单独开了三个字段跟它对应着,到时候在做数据库的时候呢,我需要保持这两张的数据同步更新和同步删除
文章表有没有什么外键关系,还是先想个人站点,首先侧屏栏有分类和标签,右边就是一篇篇的文章就是多个文章,多个文章
在个人站点下,一个站点下可以有多个文章,你写的文章只能在你的站点下,分类和标签括号的数字表示每一个分类的文章数和每个标签下的文章数
一个分类下可以有多篇文章,一篇文章只属于一个分类,一对多文章跟标签就是多对多,三种创建多对多的关系,
半自动创建,
点赞点菜:这篇文章有哪个用户点了赞点了踩,所以应该去拿个本子去找,哪篇文章,给哪些用户点了赞点了踩
确认字段,这些字段到底是普通字段还是外键字段,点赞点踩表就是所有的用户和所有的文章的点赞点菜的关系
说我用户1可以给文章1点赞点菜也可以给文章2点赞点菜 ,点赞点菜的一条数据能否对应用户多条数据呀 ,不可以 。
用户的数据可以对应点赞点踩多条数据,点赞点踩表的一条数据能否对应我文章的多条数据,
明显不可以,一篇文章能对应点赞点菜的多条数据
首先获取用户的输入,来注册说明是这个网站的新用户,注册就有自己的规则,说用户名不能超过多少位等待,
所以会有校验性的东西,限制用户输入
froms组件(渲染前端页面,校验信息,返回错误信息)
1 from django.shortcuts import render, HttpResponse,redirect 2 from app01 import myforms 3 from app01 import models 4 from django.http import JsonResponse 5 6 from PIL import Image,ImageFont,ImageDraw 7 import random 8 from io import BytesIO 9 from django.contrib import auth 10 # Create your views here. 11 def register(request): 12 back_dic = {'code': 100, 'msg': ''} 13 form_obj = myforms.MyForm() 14 if request.method == 'POST': 15 form_obj = myforms.MyForm(request.POST) 16 if form_obj.is_valid(): 17 data = form_obj.cleaned_data 18 # 将confirm_password去掉 19 data.pop('confirm_password') 20 # 获取用户上传的文件对象 21 file_obj = request.FILES.get('myfile') 22 # 判断用户是否上传了自己的头像 23 if file_obj: 24 # 往data添加一组键值 25 data['avatar'] = file_obj 26 models.UserInfo.objects.create_user(**data) 27 back_dic['msg'] = '注册成功' 28 back_dic['url'] = '/login/' 29 else: 30 back_dic['code'] = 101 31 back_dic['msg'] = form_obj.errors 32 return JsonResponse(back_dic) 33 return render(request, 'register.html', locals()) 34 35 36 def login(request): 37 back_dic = {'code':100, 'msg':''} 38 if request.method == 'POST': 39 username = request.POST.get('username') 40 password = request.POST.get('password') 41 code = request.POST.get('code') 42 if request.session.get('code').upper() == code.upper(): 43 user_obj = auth.authenticate(username=username, password=password) 44 if user_obj: 45 auth.login(request,user_obj) 46 back_dic['msg'] = '登录成功' 47 back_dic['url'] = '/home/' 48 else: 49 back_dic['code'] = 102 50 back_dic['msg'] ='用户名或密码错误' 51 else: 52 back_dic['code'] = 103 53 back_dic['msg'] ='验证码错误' 54 return JsonResponse(back_dic) 55 return render(request, 'login.html') 56 57 58 def get_random(): 59 return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) 60 61 62 def get_code(request): 63 img_obj = Image.new('RGB', (310, 35), get_random()) 64 img_draw = ImageDraw.Draw(img_obj) 65 img_font = ImageFont.truetype('static/font/mo.ttf', 35) 66 code = '' 67 for i in range(5): 68 random_int = str(random.randint(0, 9)) 69 random_lower = chr(random.randint(97, 122)) 70 random_upper = chr(random.randint(65, 90)) 71 temp_code = random.choice([random_int, random_lower, random_upper]) 72 img_draw.text((60 + i * 45, 0), temp_code, get_random(), img_font) 73 code += temp_code 74 print(code) 75 request.session['code'] = code 76 io_obj = BytesIO() 77 img_obj.save(io_obj, 'png') 78 return HttpResponse(io_obj.getvalue()) 79 80 81 def home(request): 82 return HttpResponse('home') 83 84 def logout(request): 85 auth.logout(request) 86 return redirect('/home/') 87 88 def set_password(request): 89 old_password = request.POST.get('old_password') 90 new_password = request.POST.get('new_password') 91 confirm_password = request.POST.get('confirm_password') 92 res = request.user.check_password(old_password) 93 if res: 94 if new_password == confirm_password: 95 request.user.set_password(new_password) 96 request.save() 97 return redirect('/login/') 98 return render(request,'set_password.html')
1 from django.db import models 2 from django.contrib.auth.models import AbstractUser 3 # Create your models here. 4 class UserInfo(AbstractUser): 5 phone = models.BigIntegerField(null=True) 6 create_time = models.DateField(auto_now_add=True) 7 # 该字段会将接受到文件自动存放到avatar文件夹下,只存该文件的路径 比如:avatar/111.png 8 avatar = models.FileField(upload_to='avatar/',default='avatar/default.png') 9 blog = models.OneToOneField(to='Blog',null=True) 10 11 12 13 class Blog(models.Model): 14 site_name = models.CharField(max_length=32) 15 site_title = models.CharField(max_length=64) 16 # 个人站点的样式文件 存该样式文件的路径 17 theme = models.CharField(max_length=64) 18 19 20 class Category(models.Model): 21 name = models.CharField(max_length=64) 22 blog = models.ForeignKey(to='Blog',null=True) 23 24 class Tag(models.Model): 25 name = models.CharField(max_length=32) 26 blog = models.ForeignKey(to='Blog',null=True) 27 28 29 class Article(models.Model): 30 title = models.CharField(max_length=64) 31 desc = models.CharField(max_length=255) 32 # 存大段文本 33 content = models.TextField() 34 create_time = models.DateField(auto_now_add=True) 35 # 查询优化 36 # 评论数 37 comment_num = models.IntegerField() 38 # 点赞数 39 up_num = models.IntegerField() 40 # 点踩数 41 down_num = models.IntegerField() 42 43 blog = models.ForeignKey(to='Blog',null=True) 44 category = models.ForeignKey(to='Category',null=True) 45 tags = models.ManyToManyField(to='Tag',through='Article2Tags',through_fields=('article','tag')) 46 47 class Article2Tags(models.Model): 48 article = models.ForeignKey(to='Article') 49 tag = models.ForeignKey(to='Tag') 50 51 52 53 class UpAndDown(models.Model): 54 user = models.ForeignKey(to='UserInfo') 55 article = models.ForeignKey(to='Article') 56 # 存0/1 57 is_up = models.BooleanField() 58 59 60 class Comment(models.Model): 61 user = models.ForeignKey(to='UserInfo') 62 article = models.ForeignKey(to='Article') 63 content = models.CharField(max_length=255) 64 create_time = models.DateField(auto_now_add=True) 65 parent = models.ForeignKey(to='self',null=True)
1 from django import forms 2 from django.forms import widgets 3 from app01 import models 4 class MyForm(forms.Form): 5 username = forms.CharField(max_length=8,min_length=3,label='用户名',error_messages={ 6 'required':'用户名不能为空', 7 'max_length':'用户名最大8位', 8 'min_length':'用户名最小3位', 9 },widget=widgets.TextInput(attrs={'class':'form-control'})) 10 password = forms.CharField(max_length=8, min_length=3, label='密码',error_messages={ 11 'required': '密码不能为空', 12 'max_length': '密码最大8位', 13 'min_length': '密码最小3位', 14 }, widget=widgets.PasswordInput(attrs={'class': 'form-control'})) 15 confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码',error_messages={ 16 'required': '确认密码不能为空', 17 'max_length': '确认密码最大8位', 18 'min_length': '确认密码最小3位', 19 }, widget=widgets.PasswordInput(attrs={'class': 'form-control'})) 20 email = forms.EmailField(label='邮箱', error_messages={ 21 'required': '邮箱不能为空', 22 'invalid': '邮箱格式错误', 23 }, widget=widgets.EmailInput(attrs={'class': 'form-control'})) 24 # 局部钩子校验用户名是否存在 25 def clean_username(self): 26 username = self.cleaned_data.get('username') 27 user_obj = models.UserInfo.objects.filter(username=username).first() 28 if user_obj: 29 self.add_error('username','用户名已存在') 30 return username 31 32 33 # 全局钩子 校验密码是否一致 34 def clean(self): 35 password = self.cleaned_data.get('password') 36 confirm_password = self.cleaned_data.get('confirm_password') 37 if not password == confirm_password: 38 self.add_error('confirm_password','两次密码不一致') 39 return self.cleaned_data
1 """ 2 Django settings for BBS project. 3 4 Generated by 'django-admin startproject' using Django 1.11.11. 5 6 For more information on this file, see 7 https://docs.djangoproject.com/en/1.11/topics/settings/ 8 9 For the full list of settings and their values, see 10 https://docs.djangoproject.com/en/1.11/ref/settings/ 11 """ 12 13 import os 14 15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 18 19 # Quick-start development settings - unsuitable for production 20 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 21 22 # SECURITY WARNING: keep the secret key used in production secret! 23 SECRET_KEY = 'j#j2)@qwelexuq0two4vs3oc+2nulfvyj^y3f3rp#ob7whj@8_' 24 25 # SECURITY WARNING: don't run with debug turned on in production! 26 DEBUG = True 27 28 ALLOWED_HOSTS = [] 29 30 31 # Application definition 32 33 INSTALLED_APPS = [ 34 'django.contrib.admin', 35 'django.contrib.auth', 36 'django.contrib.contenttypes', 37 'django.contrib.sessions', 38 'django.contrib.messages', 39 'django.contrib.staticfiles', 40 'app01.apps.App01Config', 41 ] 42 43 MIDDLEWARE = [ 44 'django.middleware.security.SecurityMiddleware', 45 'django.contrib.sessions.middleware.SessionMiddleware', 46 'django.middleware.common.CommonMiddleware', 47 'django.middleware.csrf.CsrfViewMiddleware', 48 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 'django.contrib.messages.middleware.MessageMiddleware', 50 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 ] 52 53 ROOT_URLCONF = 'BBS.urls' 54 55 TEMPLATES = [ 56 { 57 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 'DIRS': [os.path.join(BASE_DIR, 'templates')] 59 , 60 'APP_DIRS': True, 61 'OPTIONS': { 62 'context_processors': [ 63 'django.template.context_processors.debug', 64 'django.template.context_processors.request', 65 'django.contrib.auth.context_processors.auth', 66 'django.contrib.messages.context_processors.messages', 67 ], 68 }, 69 }, 70 ] 71 72 WSGI_APPLICATION = 'BBS.wsgi.application' 73 74 75 # Database 76 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 77 78 DATABASES = { 79 'default': { 80 'ENGINE': 'django.db.backends.mysql', 81 'NAME': 'bbs', 82 'HOST':'127.0.0.1', 83 'PORT':3306, 84 'USER':'root', 85 'PASSWORD':'123', 86 87 } 88 } 89 90 91 # Password validation 92 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 93 94 AUTH_PASSWORD_VALIDATORS = [ 95 { 96 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 }, 98 { 99 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 }, 101 { 102 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 }, 104 { 105 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 }, 107 ] 108 109 110 # Internationalization 111 # https://docs.djangoproject.com/en/1.11/topics/i18n/ 112 113 LANGUAGE_CODE = 'en-us' 114 115 TIME_ZONE = 'UTC' 116 117 USE_I18N = True 118 119 USE_L10N = True 120 121 USE_TZ = True 122 123 124 # Static files (CSS, JavaScript, Images) 125 # https://docs.djangoproject.com/en/1.11/howto/static-files/ 126 127 STATIC_URL = '/static/' 128 129 STATICFILES_DIRS= [ 130 os.path.join(BASE_DIR, 'static') 131 132 ] 133 134 #指定自己的auth用户表 135 AUTH_USER_MODEL = 'app01.UserInfo'
1 """BBS URL Configuration 2 3 The `urlpatterns` list routes URLs to views. For more information please see: 4 https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 Examples: 6 Function views 7 1. Add an import: from my_app import views 8 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 Class-based views 10 1. Add an import: from other_app.views import Home 11 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 Including another URLconf 13 1. Import the include() function: from django.conf.urls import url, include 14 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 """ 16 from django.conf.urls import url 17 from django.contrib import admin 18 from app01 import views 19 20 urlpatterns = [ 21 url(r'^admin/', admin.site.urls), 22 url(r'^register/', views.register), 23 url(r'^login/',views.login), 24 url(r'^get_code/',views.get_code), 25 url(r'home/',views.home), 26 url(r'logout/', views.logout), 27 url(r'set_password',views.set_password) 28 ]
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> 10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet"> 12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script> 13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet"> 15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script> 16 </head> 17 <body> 18 <nav class="navbar navbar-default"> 19 <div class="container-fluid"> 20 <!-- Brand and toggle get grouped for better mobile display --> 21 <div class="navbar-header"> 22 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> 23 <span class="sr-only">Toggle navigation</span> 24 <span class="icon-bar"></span> 25 <span class="icon-bar"></span> 26 <span class="icon-bar"></span> 27 </button> 28 <a class="navbar-brand" href="#">BBS</a> 29 </div> 30 31 <!-- Collect the nav links, forms, and other content for toggling --> 32 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> 33 <ul class="nav navbar-nav"> 34 <li class="active"><a href="#">文章<span class="sr-only">(current)</span></a></li> 35 <li><a href="#">随笔</a></li> 36 37 </ul> 38 {% if request.user.is_authenticated %} 39 <ul class="nav navbar-nav navbar-right"> 40 <li><a href="#">{{ request.user.username }}</a></li> 41 <li class="dropdown"> 42 <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作<span class="caret"></span></a> 43 <ul class="dropdown-menu"> 44 <li><a href="/set_password">修改密码</a></li> 45 <li><a href="#">修改头像</a></li> 46 <li role="separator" class="divider"></li> 47 <li><a href="/logout/">注销</a></li> 48 </ul> 49 </li> 50 {% else %} 51 <li><a href="/register/">注册</a></li> 52 <li><a href="/login/">登录</a></li> 53 {% endif %} 54 55 </ul> 56 </div><!-- /.navbar-collapse --> 57 </div><!-- /.container-fluid --> 58 </nav> 59 60 61 </body> 62 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> 10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet"> 12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script> 13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet"> 15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script> 16 </head> 17 <body> 18 <div class="container-fluid"> 19 <div class="row"> 20 <div class="col-md-6 col-md-offset-3"> 21 <h2 class="text-center">登录</h2> 22 {% csrf_token %} 23 <div class="form-group"> 24 <label for="id_username">用户名</label> 25 <input type="text" name="username" id="id_username" class="form-control"> 26 </div> 27 <div class="form-group"> 28 <label for="id_password">密码</label> 29 <input type="text" name="password" id="id_password" class="form-control"> 30 </div> 31 <div class="form-group"> 32 <label for="id_code">验证码</label> 33 <div class="row"> 34 <div class="col-md-6"> 35 <input type="text" name="code" id="id_code" class="form-control"> 36 </div> 37 <div class="col-md-6"> 38 <img src="/get_code/" alt="" width="310" height="35" id="id_img"> 39 </div> 40 </div> 41 </div> 42 <button class="btn btn-success" id="id_button">登录</button> 43 <span class="errors" style="color:red" id="id_error"></span> 44 </div> 45 </div> 46 </div> 47 <script> 48 $('#id_img').click(function(){ 49 let oldPath = $(this).attr('src'); 50 $(this).attr('src',oldPath +='?') 51 }); 52 $('#id_button').click(function () { 53 $.ajax( 54 { 55 url:'', 56 type:'post', 57 data:{ 58 'username':$('#id_username').val(), 59 'password':$('#id_password').val(), 60 'code':$('#id_code').val(), 61 'csrfmiddlewaretoken':'{{ csrf_token }}', 62 }, 63 success:function (data) { 64 if (data.code == 100){ 65 location.href = data.url 66 }else{ 67 $('#id_error').html(data.msg) 68 } 69 70 } 71 } 72 ) 73 }) 74 75 </script> 76 77 </body> 78 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> 10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet"> 12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script> 13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet"> 15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script> 16 </head> 17 <body> 18 <div class="container-fluid"> 19 <div class="row"> 20 <div class="col-md-6 col-md-offset-3"> 21 <h2 class="text-center">注册</h2> 22 <hr> 23 <form action="" id="myform"> 24 {% csrf_token %} 25 {% for form in form_obj %} 26 <div class="form-group"> 27 <span class="errors"></span> 28 <label for="{{ form.auto_id }}">{{ form.label }}</label> 29 {{ form }} 30 </div> 31 {% endfor %} 32 </form> 33 <div class="form-group"> 34 <label for="id_myfile" >头像 35 <img src="/static/img/default.jpg" alt="" width="80" style="margin-left: 20px" id="id_img"></label> 36 <input type="file" name="myfile" id="id_myfile" style="display: none"> 37 </div> 38 <button class="btn btn-primary pull-right" id="id_submit" value="提交">注册</button> 39 </div> 40 </div> 41 </div> 42 <script> 43 $('#id_myfile').change(function(){ 44 var myfileObj = $(this)[0].files[0]; 45 var fileReader = new FileReader(); 46 fileReader.readAsDataURL(myfileObj); 47 fileReader.onload = function(){ 48 $('#id_img').attr('src',fileReader.result); 49 } 50 }); 51 $('#id_submit').click(function () { 52 var formData = new FormData(); 53 $.each($('#myform').serializeArray(),function(index,obj){ 54 formData.append(obj.name,obj.value) 55 }) 56 }); 57 formData.append('myfile' ,$('#id_myfile')[0].files[0]); 58 $.ajax({ 59 url:'', 60 type:'post', 61 data:formData, 62 processData:false, 63 contentType:false, 64 success:function(data){ 65 console.log(data) 66 } 67 }) 68 </script> 69 70 71 </body> 72 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> 10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet"> 12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script> 13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet"> 15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script> 16 </head> 17 <body> 18 <div class="container-fluid"> 19 <div class="row"> 20 <div class="col-md-6 col-md-offset-3"> 21 <h2 class="text-center">修改密码</h2> 22 <from action="" method="post"> 23 {% csrf_token %} 24 <div class="form-group"> 25 <label for="id_username">用户名</label> 26 <input type="text" name="username" id="id_username" class="form-control" disabled value="'{{ request.user.username }}"> 27 28 </div> 29 <div class="form-group"> 30 <label for="id_old_password">旧密码</label> 31 <input type="password" name="new_password" id="id_old_password" class="form-control"> 32 33 </div> 34 <div class="form-group"> 35 <label for="id_new_password">新密码</label> 36 <input type="password" name="new_password" id="id_new_password" class="form-control"> 37 </div> 38 <div class="form=group"> 39 <label for="id_confirm_password">确认密码</label> 40 <input type="password" name="confirm_password" id="id_confirm_password" class="form-control"> 41 </div> 42 <button class="btn btn-success" id="id_button">修改密码</button> 43 <span class="errors" style="color:red" id="id_error"></span> 44 </from> 45 </div> 46 </div> 47 </div> 48 </body> 49 </html>