Django - 基于forms组件和Ajax实现注册登录 - FileField字段 - Media配置

  

一.基于forms组件的注册页面设计

  点击头像==点击input

  头像预览:

    修改  获取用户选中的文件对象;获取文件对象的路径;修改img标签的src属性,让src=文件对象路径。

  register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{ {# 隐藏file的input标签 #}
            display: none
        }
        #avatar_img{  {# 默认头像右移20px #}
            margin-left: 20px;
        }
        .error_info{
            color: red;
        }

    </style>
</head>
<body>

    <h3>注册页面</h3>

    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3" >
                <form id="form">
                    {% csrf_token %}

                    {% for filed in form %} // for循环这个form就是有user,pwd,re_pwd,email这些字段,进行渲染
                        <div class="form-group">
{#                            <label for="">{{ filed.label }}</label>#}
                            <label for="{{ filed.auto_id }}">{{ filed.label }}</label>
                            {# 由于forms组件渲染的input标签中的id都会自动加上_id,所以在label标签这里的for为了能保持一致,#}
                            {#写上filed.auto_id ,会自动的补上_id#}
                            {{ filed }} // 它渲染出来有input标签,会跟字段的名字一致,只不过这里要发ajax
                        </div>

                    {% endfor %}

                    <div class="form-group">  {# 头像没有放到input里边,把它单独处理,它不需要检验#}
                        <label for="avatar">  {# input中的id和label中的for一致,则点击头像和图片都可以跳转到input上面 #}
                            头像
                            <img width="60" height="60" id="avatar_img" src="/static/blog/imgs/default.png" alt="">
                        </label>

                        <input type="file" id="avatar" >  {# 此时这个标签没有意义了,需要隐藏起来,style="display:None" #}
                    </div>

                    <input type="button" class="btn btn-default reg_btn " value="submit"><span class="error"></span>

                </form>
            </div>
        </div>
    </div>

</body>
</html>

  Myforms.py

# -*- coding:utf-8 -*-

from django import forms
from django.forms import widgets

from blog.models import UserInfo

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError

class UserForm(forms.Form):

    user = forms.CharField(max_length=32,
                           error_messages={"required": "用户名不能为空!"},
                           label="用户名",  # label标签,这样子就可以渲染出中文了
                           widget=widgets.TextInput(attrs={"class": "form-control"})
                           )  # 为这个字段添加类form-control,让页面更好看
    pwd = forms.CharField(max_length=32,
                          label="密码",
                          widget=widgets.PasswordInput(attrs={"class": "form-control"})
                          )
    re_pwd = forms.CharField(max_length=32,
                             label="确认密码",
                             widget=widgets.PasswordInput(attrs={"class": "form-control"})
                             )
    email = forms.EmailField(max_length=32,
                             label="邮箱",
                             widget=widgets.EmailInput(attrs={"class": "form-control"})
                             )

二.注册页面的默认头像

  把img标签写到label里边去,点击头像就相当于点击input标签

  http://127.0.0.1:8000/static/blog/img/default.png,这样子就可以访问到这个默认的注册头像

  很多网站是这样子:把input标签的长宽跟这个头像一致,然后利用css里边定位position=absolute,把这两个标签定位到一个位置上去。再把input标签透明度显示为0,这时候它俩叠到一起了,你点击头像也就点击了input标签。   另外一种思路是:利用label标签的for的值与input标签的id值一致就可以了,点击label相当于点击input标签。

三.注册页面的头像预览功能

  Console---》

$("#avatar")
r.fn.init [input#avatar]0: input#avatarlength: 1__proto__: Object(0)
$("#avatar")[0]
<input type=?"file" id=?"avatar">?
$("#avatar")[0].files
FileList {0: File(593239), length: 1}0: File(593239) {name: "distance.png", lastModified: 1510650980163, lastModifiedDate: Tue Nov 14 2017 17:16:20 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 593239, …}length: 1__proto__: FileList
$("#avatar")[0].files[0]
File(593239) {name: "distance.png", lastModified: 1510650980163, lastModifiedDate: Tue Nov 14 2017 17:16:20 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 593239, …}

  头像预览:

    修改用户选中的文件对象;获取文件对象的路径;修改img的src属性,src=文件对象路径。

<script src="/static/js/jquery-3.3.1.js"></script>

    <script>

        $("#avatar").change(function () {  // change事件,选中文本之后事件就发生了,
            // 头像预览:
                    // 1.获取用户选中的文件对象
                    var file_obj = $(this)[0].files[0];

                    // 2.获取文件对象的路径
                    // 基于文件阅读器 FileReader,new一个实例对象
                    var reader = new FileReader();

                    reader.readAsDataURL(file_obj);// 读完之后没有返回值,而是默认加到你的对象里面
                                                   // FileReaderURL是读取文件的URL
                    // 3.修改img的src属性,src=文件对象的路径
                    // attr给属性赋值
                    // reader.readAsDataURL(file_obj)读的时间很长,而且他们都是异步的,还没有读完,就已经执行下面的替换操作了,会找不到路径

                    // $("#avatar_img").attr("src", reader.result)

                    // 等读完之后在执行下面这句代码
                    reader.onload = function () {
                        $("#avatar_img").attr("src", reader.result)  // 结果在reader.result里边

                    }
        });
</script>

四.基于Ajax提交formdata数据和注册页面显示错误信息

  点击提交(什么都不输入直接submit)的错误信息在这里边:---->>> { user:null,msg:{ } }

<script>
    // 基于ajax提交数据
        $(".reg_btn").click(function () {
            // ajax上传文件类型一定要换成formdata格式
            // 使用formdata,必须加上这两个,
            // contentType:false,
            // processData:false,
            // 否则会报错

            var formdata = new FormData();
{#            formdata.append("user", $("#id_user").val());#}
{#            formdata.append("pwd", $("#id_pwd").val());#}
{#            formdata.append("re_pwd", $("#id_re_pwd").val());#}
{#            formdata.append("email", $("#id_email").val());#}
{#            formdata.append("csrfmiddlewaretoken", $("[name=‘csrfmiddlewaretoken‘]").val());#}

            formdata.append("avatar", $("#avatar")[0].files[0]);

            // 循环往formdata添加数据
{#            console.log($("#form").serializeArray()); // 打印form表单所有的键值对#}
            var request_data = $("#form").serializeArray();
            $.each(request_data, function (index,data) {
                formdata.append(data.name, data.value);
            });

            $.ajax ({
                url:"",
                type:"post",
                contentType:false,
                processData:false,
                data:formdata,  // 把上边的formdata构建出来以后,加到这里边来
                success:function (data) {
                    //console.log(data)
                    if (data.user){
                        // 注册成功,跳转到登录页面
                        location.href = "/login/"
                    }
                    else { // 注册失败
                        // 由于每次展示的时候会将错误的信息保存在span中,需要清空,否则会出现问题
                        $("span.error_info").text("");
                        $(".form-group").removeClass("has-error");  //展示之前,移除类has-error
                        // 循环展示此次提交的错误信息
                        $.each(data.msg, function (field, error_list){
                            // 判断是不是个全局的
                            if (field=="__all__"){
                                $("#id_re_pwd").next().text(error_list[0]).parent().addClass("has-error"); // 链式操作
                            }
                            // 显示错误信息:next()是找到下一个标签
                            $("#id_"+field).next().text(error_list[0]);
                            // 显示红色边框:找到父标签,然后添加一个bootstrap的类has-error
                            $("#id_"+field).parent().addClass("has-error");
                    })
                    }

                }

            })
        })
</script>

  views.py

def register(request):

    # if request.method == "POST": # 在这里二者都可以
    if request.is_ajax(): # 点击那个按钮,既是Ajax请求,又是post请求
        print(request.POST)
        form = UserForm(request.POST)  # 通过UserForm得到用户输入的数据进行校验

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")

            # 生成一条用户记录
           else:
            print(form.cleaned_data)  # 干净数据都在这里边
            print(form.errors)  # 错误数据都在这里边
            response["msg"] = form.errors   # 失败之后把所有的错误信息放到msg里边

        return JsonResponse(response)

    form = UserForm()
    print(form)

    return render(request, "register.html", {"form": form})

五.forms组件的局部钩子与全局钩子的应用

  Myforms.py

# 加局部钩子,验证用户是否注册
    def clean_user(self):
        val = self.cleaned_data.get("user")  # 取到已经在上面通过基础的格式验证的user

        user = UserInfo.objects.filter(username=val).first()  # 在数据库中过滤是否有一致的用户名

        if not user:
            return val
        else:
            raise ValidationError("该用户已注册!")

    # 加全局钩子,验证两次密码是否一致,全局错误信息是放在__all__中

    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        re_pwd = self.cleaned_data.get("re_pwd")

        if pwd and re_pwd:  # 当两次密码输入都有值的时候才会对两者进行比较
            if pwd == re_pwd:
                return self.cleaned_data
            else:
                raise ValidationError("两次密码输入不一致!")
        else:
            return self.cleaned_data

  全局错误可以在视图里边取出来,跟之前form表单提交错误信息不一样,之前是把错误信息放到视图里边,放到模板里边去。这里可以直接在register里边

错误信息在errors里边,里边有个键叫__all__,对应列表error_list的信息,发给ajax了,ajax拿到数据做下判断---->>>

 if (field == "__all__"){   //处理全局错误信息;下面找到它的标签,父标签给它加上
        $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error"); //给它放到re_pwd确认密码的下面 
                        }

六.FileField(可以上传任何文件)与ImageFiled(只能上传图片)

 class UserInfo(AbstractUser):  # 使用用户认证组件需要使用auth_user表,扩展这个表需要继承AbstractUser,User继承的就是AbstractUser
                """
                用户信息
                用户信息表和博客信息表是一对一的关系
                """
                nid = models.AutoField(primary_key=True)
                telephone = models.CharField(max_length=11, null=True, unique=True)
                avatar = models.FileField(upload_to=‘avatars/‘, default="/avatars/default.png")  # 存本地用户图像字段

            avatar_obj = request.FILES.get("avatar")
            UserInfo.objects.create_user(username=user,password=pwd, email=email, avatar=avatar_obj)  # 这里avatar一定要接收一个文件对象

            Django实现:
                会将文件对象下载到项目的根目录中avatars文件夹中(如果没有avatars文件夹,Django会自动创建),
            user_obj的avatar存的是文件的相对路径

  

  views.py

def register(request):

    # if request.method == "POST": # 在这里二者都可以
    if request.is_ajax():
        print(request.POST)
        form = UserForm(request.POST)  # 通过UserForm都到用户输入的数据

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")

            # 生成一条用户记录
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email= form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            UserInfo.objects.create_user(username=user,password=pwd, email=email, avatar=avatar_obj)
else:
            print(form.cleaned_data)
            print(form.errors)
            response["msg"] = form.errors

        return JsonResponse(response)

    form = UserForm()
    print(form)

    return render(request, "register.html", {"form": form})

七. Media配置之MEDIA_ROOT

Django有两种静态文件:

  /static/   :js,css,img

  /media/   :用户上传文件;  用户默认头像图片应该在media/avatar里边存一份。

class UserInfo(AbstractUser):     ‘‘‘用户信息‘‘‘    nid = models.AutoField(primary_key=True)    telephone = models.CharField(max_length=11, null=True, unique=True)    avatar = models.FileField(upload_to=‘avatars/‘, default="/avatars/default.png")
avatar_obj = request.FILES.get("avatar")user_obj = UserInfo.objects.create_user(username = user, password = pwd, email = email, avatar = avatar_obj)

用户一旦配置了

MEDIA_ROOT = os.path.join(BASE_DIR, "media") 这个路径(在settings里边)
Django会实现:  会将文件对象下载到MEDIA_ROOT中avatars文件夹中(如果没有avatar文件夹,Django会自动创建),user_obj的avatar存的是文件的相对路径。

  settings.py

STATIC_URL = ‘/static/‘

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static")
]

MEDIA_ROOT = os.path.join(BASE_DIR, "media")

八. Media配置之MEDIA_URL

  访问http://127.0.0.1:8000/static/blog/img/default.png是可以直接访问到的,如果是http://127.0.0.1:8000/blog/views.py/是访问不到的,不能把你的源代码暴露出来啊,static里边的无所谓,而static是Django给你配置好的,应该让用户看到。同样的media里边应该也让用户看到。  浏览器如何能直接访问到media中的数据呢?

  settings.py

MEDIA_URL = ‘/media/‘
#与用户上传相关的配置
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = ‘/media/‘

  urls.py

#media配置re_path(r"media/(?P<path>.*)$", serve, {"document_root":settings.MEDIA_ROOT})

浏览器访问http://127.0.0.1:8000/media/avatars/11.jpg可以直接访问media里边的文件了

注意规范问题:

优化代码问题:

  views.py

def register(request):

    # if request.method == "POST": # 在这里二者都可以
    if request.is_ajax():
        print(request.POST)
        form = UserForm(request.POST)  # 通过UserForm都到用户输入的数据

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")

            # 生成一条用户记录
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email= form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")

            # 如果用户没有上传图像怎么办?
            # 没有会有个默认的图像,但是下面这段代码已经上传了一个空的avatar_obj,不会走到默认
            # 所以需要加一个判断
            # UserInfo.objects.create_user(username=user,password=pwd, email=email, avatar=avatar_obj)

            # 重复代码太多,优化
            # if avatar_obj:
            #     UserInfo.objects.create_user(username=user,password=pwd, email=email, avatar=avatar_obj)
            # else:
            #     UserInfo.objects.create_user(username=user, password=pwd, email=email)

            # def create_user(self, username, email=None, password=None, **extra_fields):
            # create_user中有个参数**extra_fields,所以可以下面这样来优化
            extra = {}

            if avatar_obj:
                extra[‘avatar‘] = avatar_obj

            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)

        else:
            print(form.cleaned_data)
            print(form.errors)
            response["msg"] = form.errors

        return JsonResponse(response)

    form = UserForm()
    print(form)

    return render(request, "register.html", {"form": form})

原文地址:https://www.cnblogs.com/mumupa0824/p/10441083.html

时间: 2024-10-08 01:32:38

Django - 基于forms组件和Ajax实现注册登录 - FileField字段 - Media配置的相关文章

Django之forms组件

一.校验数据功能 我们在写注册页面时,之前只是提交了数据,然后就保存了数据,后端根本就没有对数据进行校验,比如价格写的不是纯数字也让保存,这肯定是不行的,在前端是可以校验的,但我们不能只依靠前端验证,万一前端不校验,那整个过程就没校验了,所以,不管前端有没有校验,我们后端都应该进行验证. 现在注册页面要向我提交三个数据,用户名.密码.邮箱,当它提交过来后,首先我要对数据进行校验,根据数据的校验结果然后再决定保存还是给前端返回错误信息. views.py from django import fo

Django之forms组件使用

注册功能 1.渲染前端标签获取用户输入 >>> 渲染标签 2.获取用户输入传递到后端校验 >>> 校验数据 3.校验未通过展示错误信息 >>> 展示信息 校验数据(前后端都可以校验) 校验前端后端都可以做,但是前端可以不做,后端必须得做!!! django form组件 1.渲染标签 2.校验数据 3.展示信息 校验数据 第一步需要在views中写一个form类 from django import forms class MyForm(forms.F

django(forms组件、cookies与session)

一.forms组件 1.功能 - 渲染页面 - 校验数据 - 展示信息 需要先写一个类,该类类似于models中的表类 from django import forms class MyRegForm(forms.Form): # 用户名最少3位最多8位 username = forms.CharField(max_length=8,min_length=3) password = forms.CharField(max_length=8,min_length=3) # email字段必须填写符

Django的form组件应用登陆或者注册

from django import forms from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.exceptions import ValidationError from blog.models import * class RegisterForm(Form): # 自定义form组件 username = fiel

CSIC_716_20200113【Django入门---forms组件、session和cookie、登录认证装饰器】

forms组件 forms组件的功能:1.渲染前端页面,不用在前端手写forms表单了,不过只会渲染用户输入(输入.选择.下拉.文件)的标签,不渲染按钮以及form表单标签,.2.后端能进行非常规范的数据合法性校验3.展示校验之后的合法性信息. 使用方法:1.定义一个自定义forms类 form组件的前端渲染方式 效果差不多 哈哈哈哈 顶 原文地址:https://www.cnblogs.com/csic716/p/12189236.html

一个基于Unix套接字的注册登录系统

2016/5/5 今天,我参考<Unix网络编程-卷1>第5章的TCP回射客户/服务器程序写了一个简单的注册登录系统,其功能如下:(1)注册.客户端向服务器发送个人信息请求注册,服务器查询MySQL数据库以检查该客户是否已存在,若是则禁止注册,并返回“用户已存在,注册失败”的错误信息,否则将新用户信息添加到MySQL数据库,并返回“注册成功”的信息.(2)登录.客户端向服务器发送个人账号和密码等两项信息,服务器查询MySQL数据库以检查账号是否存在.账号和密码是否匹配,若不存在或不匹配则禁止登

django 基于 form 验证 确认密码的注册

class RegisterForm(Form): # user_id=fields.IntegerField() username=fields.CharField( max_length=12, min_length=4, required=True, error_messages={'required':'用户名不能为空','invalid':'输入不合规'}, # widget = widgets.TextInput(attrs={'class': 'form-control loon

Django forms组件【对form舒心l了】

目录 Django forms组件 bound and unbound form instance forms渲染有关 隐藏一个字段,不渲染它 form 校验 form类 ModelForm 利用ModelForm关键就在于model's field mapping to form's field ModelForm.save() 详解 class Meta !!!重写覆盖默认的modelField字段(即自定义一些modelform属性) form有关多选择Field的使用 form's fi

Django框架之Forms组件(基于注册功能)

1.注册功能分析 注册功能 1.渲染前端标签获取用户输入 >>> 渲染标签 2.获取用户输入传递到后端校验 >>> 校验数据 3.校验未通过展示错误信息 >>> 展示信息 2.使用 forms 组件实现注册功能 1.校验数据 校验规则:form组件校验数据的规则从上往下依次取值校验    校验通过的放到cleaned_data    校验失败的放到errors from django import forms class MyForm(forms.Fo