分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 运营维护

博客园-注册(form组件,ajax提交数据,头像上传,media)

发布时间:2023-09-06 01:41责任编辑:傅花花关键词:组件

form类创建

使用form组件需要我们自己创建一个类

import refrom django import formsfrom django.forms import widgetsfrom django.core.exceptions import ValidationErrorfrom blog import models# Create your views here.class RegForm(forms.Form): ???user = forms.CharField( ???????max_length=20, ???????min_length=6, ???????error_messages={ ???????????"required": "用户名不能为空", ???????????"max_length": "用户名不能超过20位", ???????????"min_length": "用户名不能少于6位" ???????}, ???????widget=widgets.TextInput(attrs={"class": "form-control"}) ???) ???nickname = forms.CharField( ???????max_length=20, ???????min_length=3, ???????error_messages={ ???????????"required": "用户名不能为空", ???????????"max_length": "用户名不能超过20位", ???????????"min_length": "用户名不能少于3位" ???????}, ???????widget=widgets.TextInput(attrs={"class": "form-control"}) ???) ???pwd = forms.CharField( ???????min_length=6, ???????widget=widgets.PasswordInput(attrs={"class": "form-control"}), ???????error_messages={ ???????????"required": "密码不能为空", ???????????"min_length": "密码不能少于6位" ???????} ???) ???repeat_pwd = forms.CharField( ???????widget=widgets.PasswordInput(attrs={"class": "form-control"}), ???????error_messages={ ???????????"required": "确认密码不能为空" ???????} ???) ???email = forms.EmailField( ???????error_messages={ ???????????"invalid": "格式错误", ???????????"required": "邮箱不能为空" ???????}, ???????widget=widgets.EmailInput(attrs={"class": "form-control"}) ???) ???tel = forms.IntegerField( ???????error_messages={ ???????????"required": "手机号不能为空" ???????}, ???????widget=widgets.NumberInput(attrs={"class": "form-control"}) ???) ???def clean_user(self): ???????user = self.cleaned_data.get("user") ???????if models.UserInfo.objects.filter(username=user).exists(): ???????????raise ValidationError("用户名已存在") ???????else: ???????????return user ???????def clean_nickname(self): ???????nickname = self.cleaned_data.get("nickname") ???????if models.UserInfo.objects.filter(nickname=nickname).exists(): ???????????raise ValidationError("昵称已存在") ???????else: ???????????return nickname ???def clean_tel(self): ???????tel = self.cleaned_data.get("tel") ???????if re.search("^1[3458]\d{9}$", str(tel)): ???????????return tel ???????else: ???????????raise ValidationError("手机号格式错误") ???def clean(self): ???????pwd = self.cleaned_data.get("pwd") ???????repeat_pwd = self.cleaned_data.get("repeat_pwd") ???????if pwd == repeat_pwd: ???????????return self.cleaned_data ???????else: ???????????raise ValidationError("密码不一致")

在这个类中我们定义好每一个字段的类型及一些判断条件

前端页面渲染

{% load static %}<!DOCTYPE html><html lang="zh-CN"><head> ???<meta charset="UTF-8"> ???<meta http-equiv="x-ua-compatible" content="IE=edge"> ???<meta name="viewport" content="width=device-width, initial-scale=1"> ???<title>注册页面</title> ???<link rel="stylesheet" href="{% static ‘bootstrap-3.3.7/css/bootstrap.min.css‘ %}"> ???<script src="{% static ‘jquery-3.2.1.min.js‘ %}"></script> ???<script src="{% static ‘bootstrap-3.3.7/js/bootstrap.min.js‘ %}"></script> ???<style> ???????body{ ???????????background-color: #eeeeee; ???????} ???????.d1{ ???????????margin-top: 100px; ???????} ???????span{ ???????????color: red; ???????} ???????.form-group{ ???????????margin-bottom: 20px; ???????} ???</style></head><body><div class="container d1"> ???<div class="row"> ???????<div class="col-sm-3 col-sm-offset-3"> ???????????<h3>注册</h3> ???????</div> ???</div></div><div class="container"> ???<div class="row"> ???????<div class="col-sm-offset-1 col-sm-10"> ???????????<form class="form-horizontal"> ???????????????{% csrf_token %} ???????????????<div class="form-group"> ???????????????????<label for="id_user" class="col-sm-2 control-label">用户名</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.user }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ??????????????????<div class="form-group"> ???????????????????<label for="id_nickname" class="col-sm-2 control-label">昵称</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.nickname }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<label for="id_pwd" class="col-sm-2 control-label">密码</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.pwd }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<label for="id_repeat_pwd" class="col-sm-2 control-label">确认密码</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.repeat_pwd }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<label for="id_email" class="col-sm-2 control-label">邮箱</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.email }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<label for="id_tel" class="col-sm-2 control-label">手机号</label> ???????????????????<div class="col-sm-8"> ???????????????????????{{ form_obj.tel }} ???????????????????????<span class="pull-right">&nbsp;</span> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<label for="avatar" class="col-sm-2 control-label">头像</label> ???????????????????<div class="col-sm-8"> ???????????????????????<label for="avatar"><img src="" ?width="60" height="60" id="avatar_img"></label> ???????????????????????<input type="file" style="display: none;" id="avatar"> ???????????????????</div> ???????????????</div> ???????????????<div class="form-group"> ???????????????????<div class="col-sm-offset-2 col-sm-5"> ???????????????????????<input type="button" class="btn btn-primary btn-block" value="注册"> ???????????????????</div> ???????????????</div> ???????????</form> ???????</div> ???</div></div>

通过form组件定义的类实例化一个对象,使用这个对象对前端页面进行渲染

头像选择

在前端页面中我们可以看到有一个头像的选项,一般情况下用户点击头像的默认框就可以选择自己要上传的头像

为了实现这个功能,我们先写一个隐藏的input框(type=file),再利用label标签与他绑定关系,将img标签写入label标签内

这样便实现了点击img图片也能上传头像的功能

<div class="form-group"> ???<label for="avatar" class="col-sm-2 control-label">头像</label> ???<div class="col-sm-8"> ???????<label for="avatar"><img src="" ?width="60" height="60" id="avatar_img"></label> ???????<input type="file" style="display: none;" id="avatar"> ???</div></div>

头像预览功能

头像预览功能与后端没有什么关系,可以通过前端获取用户选择的图片的路径,然后直接将img标签的src属性改为用户选择图片的路径,实现图片的预览功能

// 头像预览 ???$("#avatar").change(function () { ???????var choose_file = $(this)[0].files[0]; ???????// 实例化一个阅读器对象 ???????var reader = new FileReader(); ???????// 读取文件的路径,没有返回值,结果在reader.result里 ???????reader.readAsDataURL(choose_file); ???????// 读取需要时间,读完后再修改图片路径 ???????reader.onload=function () { ???????????$("#avatar_img").attr("src",this.result) ???????} ???});

这里我们用到了一个取用户选择的文件对象的方法,先使用$("#avatar")取到上传文件的input标签的jquery对象,通过$("#avatar")[0]取到该标签的DOM对象

再通过DOM对象的files方法拿到上传文件的数组,最后通过索引获取上传的文件对象,即为$("#avatar")[0].files[0]

得到这个对象后,为了获取该文件的路径,我们使用阅读器的功能

先实例化一个阅读器对象var reader = new FileReader(),在利用阅读器对象的readAsDATAURL方法读取文件的路径

由于读取文件路径需要时间,所以我们对该阅读器对象绑定了一个onload方法,待读取完成后,再将img标签的src属性更改为文件的路径

这样便实现了头像预览的功能

ajax传文件

 由于需要传文件,如果用form表单传,需要设置enctype="multipart/form-data"

我们这里使用ajax发送数据,需要用到FormData

$(":button").click(function () { ???????// 实例一个对象,用它来封装数据 ???????var formdata = new FormData(); ???????formdata.append("user",$("#id_user").val()); ???????formdata.append("nickname",$("#id_nickname").val()); ???????formdata.append("pwd",$("#id_pwd").val()); ???????formdata.append("repeat_pwd",$("#id_repeat_pwd").val()); ???????formdata.append("email",$("#id_email").val()); ???????formdata.append("tel",$("#id_tel").val()); ???????formdata.append("csrfmiddlewaretoken",$("[name=‘csrfmiddlewaretoken‘]").val()); ???????formdata.append("avatar",$("#avatar")[0].files[0]); ???????$.ajax({ ???????????url: "/register/", ???????????type: "post", ???????????data: formdata, ???????????contentType: false, ???????????processData: false, ???????????success: function (data) { ???????????????var data = JSON.parse(data); ???????????????if (data.reg){ ???????????????????location.href="/login/" ???????????????}else{ ???????????????????// 清空上次错误信息 ???????????????????$("form span").html("&nbsp;"); ???????????????????$(".form-group").removeClass("has-error"); ???????????????????var errors = data.error_msg; ???????????????????for (var i in errors){ ???????????????????????if (i === "__all__"){ ???????????????????????????// 边框变红 ???????????????????????????$("#id_repeat_pwd").parent().parent().addClass("has-error"); ???????????????????????????$("#id_repeat_pwd").next().text(errors[i][0]) ???????????????????????}else{ ???????????????????????????$("#id_"+i).parent().parent().addClass("has-error"); ???????????????????????????$("#id_"+i).next().text(errors[i][0]) ???????????????????????} ???????????????????} ???????????????} ???????????????// 还可以使用each循环{# ???????????????$.each(errors, function (field,error) {#}{# ???????????????????$("#id_"+field).next().text(error[0])#}{# ???????????????})#} ???????????} ???????}) ???})

注意,这里要加contentType: false, processData: false,否则会出错

拿到后端传回的数据后

先将后端传回的数据进行范序列化,再通过传回数据的键值对进行判断

如果数据没问题,则进行跳转

如果数据有问题,需要将错误信息显示到页面上

由于后端传回的错误信息的键值对的键对应的都是form类中的字段,而通过form类实例化的对象渲染出的页面的input标签的id为id_字段,可以通过字符串拼接的方式,得到每个input框的id

从而取到每个input框的jquery对象,再将相应的错误信息显示到每个input框后面即可

后端数据处理

def register(request): ???reg_info = {"reg": True, "error_msg": ""} ???if request.method == "POST": ???????form_obj = RegForm(request.POST) ???????if form_obj.is_valid(): ???????????user = form_obj.cleaned_data.get("user") ???????????nickname = form_obj.cleaned_data.get("nickname") ???????????pwd = form_obj.cleaned_data.get("pwd") ???????????email = form_obj.cleaned_data.get("email") ???????????tel = form_obj.cleaned_data.get("tel") ???????????avatar_obj = request.FILES.get("avatar") ?# 图片对象 ???????????models.UserInfo.objects.create_user(username=user, password=pwd, email=email, telephone=tel, nickname=nickname, avatar=avatar_obj) ?# 添加avatar字段时会自动下载文件,放到upload_to后的路径里 ???????else: ???????????reg_info["error_msg"] = form_obj.errors ???????????reg_info["reg"] = False ???????return HttpResponse(json.dumps(reg_info)) ???form_obj = RegForm() ???return render(request, "register.html", locals())

通过前端传来的数据,实例化一个form_obj对象,在通过这个对象的is_vaild()方法对数据进行校验,如果数据没问题,则从form_obj.cleaned_data中取出数据,使用UserInfo.objects.create_user方法添加数据

这里需要注意的是,avatar字段,这里我们直接使用的是avatar=avatar_obj这个文件对象,其实在数据库中该字段还是会存放这个文件的路径,并将用户上传的文件放到相应的路径下

media

在之前的配置中,我们在settings文件中配置过静态文件的存放目录和别名,用来专门存放一些静态文件

而在django中,也会将用户上传的文件统一放到一个地方(类似static配置)

class UserInfo(AbstractUser): ???""" ???用户信息 ???""" ???nid = models.AutoField(primary_key=True) ???nickname = models.CharField(verbose_name=‘昵称‘, max_length=32) ???telephone = models.CharField(max_length=11, null=True, unique=True) ???avatar = models.FileField(upload_to=‘avatar_dir/‘, default="/avatar/default.png") ???create_time = models.DateTimeField(verbose_name=‘创建时间‘, auto_now_add=True) ???blog = models.OneToOneField(to=‘Blog‘, to_field=‘nid‘, null=True)

针对FileField,Imagefield字段:
avatar = models.FileField(upload_to = ‘avatars/‘,default="/avatar/default.png")
默认会将FileField字段中的upload_to参数对应的值avatars文件下载到项目的根目录下
if 在settings配置了一句:
MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media")
将FileField字段中的upload_to参数对应的值avatars下载到MEDIA_ROOT路径下

MEDIA_URL = "/media/" ?# 别名MEDIA_ROOT = os.path.join(BASE_DIR, "blog", "media")

这里的配置与static静态文件的配置类型,只不过static配置了下面的内容后

STATIC_URL = ‘/static/‘STATICFILES_DIRS = [ ???os.path.join(BASE_DIR, "static")]

用户可以直接通过/static/接文件的路径访问到静态文件,这是因为django在这里自动帮你配置了url

而media这里django并未帮你配置,所以我们需要自己在url里配置

from django.conf.urls import urlfrom django.contrib import adminfrom blog import viewsfrom django.views.static import servefrom s8_cnblog import settingsurlpatterns = [ ???url(r‘^admin/‘, admin.site.urls), ???url(r‘^login/‘, views.log_in), ???url(r‘^get_valid_img/‘, views.get_valid_img), ???url(r‘^index/‘, views.index), ???url(r‘^logout/‘, views.logout), ???url(r‘^register/‘, views.register), ???# media 配置 ???url(r‘^media/(?P<path>.*)$‘, serve, {‘document_root‘: settings.MEDIA_ROOT}),]

这样我们便可以通过/media/接具体的路径找到用户上传的文件了

博客园-注册(form组件,ajax提交数据,头像上传,media)

原文地址:https://www.cnblogs.com/QQ279366/p/8424227.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved