django的表单处理、用户登录、管理功能


1、django项目初始化和数据库初始化:

1.1、项目:

1.1.1、创建项目:

直接在pycharm中创建django项目,然后删掉默认的template文件和将settings中的这一句

改成

1.1.2、创建app:

然后就创建号一个app文件了,名字可随意。

创建完app后记得到settings文件进行注册

1.1.3、创建数据库连接:
记得要先创建对应数据库

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "work",
        "USER": "root",
        "PASSWORD": "",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    }
}
1.1.4、修改编码:

1.2、表:

1.2.1、创建和修改表:
例如
from django.db import models

# Create your models here.
class Admin(models.Model):
    username=models.CharField(verbose_name="用户名",max_length=32)
    password=models.CharField(verbose_name="密码",max_length=64)
在终端轮流执行这两个。注意不可后期添加属性,要么删表重建,要么全部设置默认值
python manage.py makemigrations

python manage.py migrate

2、前端模板:

定义一个模板文件后,在模板文件中

。。。。。。
<div>
    {% block 自定义名1 %}{% endblock %}
</div>
。。。。。。

这样,就可以在别的文件里直接这样写

{% extends '自定义模板文件名' %}
{% block 自定义名1 %}
不同的代码部分
{% endblock %}

PS:“content”这个字符可自行定义

3、ORM:

3.1、表单的初始化(常用):

模板案例
class X(models.Model): 
 
   level_choices=(
        (1,"紧急"),
        (2,"重要"),
        (3,"临时")
    )
    level=models.SmallIntegerField(verbose_name="级别",choices=level_choices,default=1)

    title=models.CharField(verbose_name="标题",max_length=64)
    detail=models.TextField(verbose_name="详细信息")
    price=models.IntegerField(verbose_name="价格")
    account=models.DecimalField(verbose_name="余额",max_length=10,max_digits=10,decimal_places=2,default=0)

    级联删除,当Admin中某用户对象删除后,对应关联的x表中的x对象也全部删除
    user=models.ForeignKey(verbose_name="负责人",to="Admin",to_fields="id"(这个可以不写),on_delete=models.CASCADE)
    
    price = models.FloatField(。。。) 


class Admin(..):  
    ..

    

3.2、查询:

//按照id倒序获取所有行对象
queryset=models.Order.objects.all().order_by('-id')

//删除行对象
models.Order.objects.filter(id=uid).delete()

//获取某种属性
queryset=AllTable.objects.values('types')
或   queryset=AllTable.objects.values('title','cover','rate','directors','actors','year','language','country','types','comments','movieUrl')

4、表单:

重点!!:

<form method="post">
        {% csrf_token %} 一定不要忘了这个

表单中的选择属性可以这样():

在定义数据表时:

 gender_choices=(
        (1,"男"),
        (2,"女"),
    )
    gender=models.SmallIntegerField(verbose_name="性别",choices=gender_choices)#性别



这样就可以在定义这个时:
class UserModelFrom(forms.ModelForm):
    class Meta:
        model=models.UserInfo
        fields=["name","password","age","account","create_time","gender","depart"]
 
    # class Meta:
    #     model=models.Task
    #     fields="__all__"  这直接取所有属性


def user_add(request):
    if request.method=="GET":
        form=UserModelFrom()
        return render(request,'user_add.html',{"form":form})

这样直接把gender传到前端,就能实现表单选择初始化了。

                    <th>{{ i.age }}</th>
                    <th>{{ i.account }}</th>

                    <th>{{ i.create_time|date:"Y-m-d" }}</th>#这是年月日格式化

                    <th>{{ i.get_gender_display }}</th>#这是数据在当前表的情况

                    <td>




另一种情况:
 
    当depart在另一个表里时,由于表单传递的是depart的具体对象,想要获取name比较麻烦。在该表加上那个函数,这样直接调用该对象时,就会返回一个自定义值

class Department(models.Model):
    name=models.CharField(max_length=32)#部门名

    def __str__(self):
        return self.name

<th>{{ i.depart.name }}</th>#这是前端对应代码


PS:之所以要这么搞,是因为整型数存储消耗比字符少

4.1、普通处理:

例如
def user_add(request):
    if request.method=="GET":
        models.UserInfo.之类的
    
    #提交数据
    name=request.POST.get('name')
    password=request.POST.get('password')
。。。。。。。。。

这样写很麻烦,每一个属性都要手动处理,而且还要考虑校验的问题

4.2、Form:

直接在myform进行定制

然后在前端:

4.3、ModelForm(管理功能的表单最常用):

4.3.1、初始样式:

要在对应路由函数前定义:

这是自己定制输入框的麻烦方法
class UserModelFrom(forms.ModelForm):
    class Meta:
        model=models.UserInfo

        fields=["name","password","age","account","create_time","gender","depart"]
        fields是包含xx属性,exclude=['oid']则是除xx外,fields=“__all__”则是所有

        就是这
        widgets={
            "name": forms.TextInput(attrs={"class": "form-control", "placeholder": UserInfo._meta.get_field('name').verbose_name})
        }


#这个是用便捷函数的方法
class UserModelFrom(forms.ModelForm):
    class Meta:
        model=models.UserInfo
        fields=["name","password","age","account","create_time","gender","depart"]
        

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for name,field in self.fields.items():
            field.widget.attrs={"class":"form-control","placeholder":field.label}
def user_add(request):
    if request.method=="GET":
        form=UserModelFrom()
        return render(request,'user_add.html',{"form":form})

这样就可以在路由函数中使用form了。而且可以通过widgets对表单输入框进行定制。

下面是封装继承的方法,这样就可以把BootStrapModelForm(这个类可自定义)作为父类,封装到另一个专门放置类的文件里面进行引用,让后续的表单继承

from django import forms

class BootstrapModelForm(forms.ModelForm):
    def __init__(self,*args,**kwargs):
        super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
        for name,field in self.fields.items():
# 字段中有属性,保留原来的属性,没有属性,才增加。
            if field.widget.attrs:
                field.widget.attrs["class"] ="form-control"
                field.widget.attrs["placeholder"] = field.label
            else:
                field.widget.attrs = {
                    "class": "form-control",
                    "placeholder":field.label
                }

这样就可以使用了

4.3.2、不过如果想要在表单中初始化内容,则需要在数据库表中定义:
例如
class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名",max_length=32)
    password = models.CharField(verbose_name="密码",max_length=64)
    age = models.IntegerField(verbose_name="年龄",null=True, blank=True)

这里的verbose_name="年龄"可以通过form传到前端,然后在前端
这个是用简便函数处理的,所有field.label就是verbose_name。后端只要提供form,就能生成相应表单

               <form method="post">
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group">
                            <label>{{ field.label }}</label>
                            {{ field }}
                            <span>{{ field.errors.0 }}</span>#这是错误原因反馈
                        </div>
                    {% endfor %}
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>

上面的初始化内容只是静态内容,如果我想初始化的是表中原有的数据。比如编辑数据的时候:

PS:重点instance

def user_edit(request,id):
    #这可以获得一个行对象
    row_object = models.UserInfo.objects.filter(id=id).first()

    if request.method=="GET":
        form =UserModelFrom(instance=row_object) #instance=row_object这里用该对象进行填充

        return render(request,'user_edit.html',{'form':form})

    form=UserModelFrom(data=request.POST,instance=row_object)#这里的instance=row_object起到了覆盖当前对象的作用,这样就不会新添一行了。

    if form.is_valid():
        print(form.cleaned_data)
        form.save()
        return redirect('/user/list/')
    return render(request,'user_edit.html',{"form":form})

讲一种几种特殊情况

class PrettyEditForm(forms.ModelForm):
    让mobile不可改
    mobile=forms.CharField(disabled=True,label="手机号")
    class Meta:
        model=models.PrettyNum
        fields=["mobile","price","level","status"]#或者直接在这去掉mobile



class AdminModelForm(forms.ModelForm):
    加一个确认密码的框
    confirm_password=forms.CharField(label="确认密码")
    class Meta:
        model=models.Admin
        fields=["username","password"]
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for name,field in self.fields.items():
            field.widget.attrs={"class":"form-control","placeholder":field.label}

由此可见,如果想对表单进行操作,可以考虑在modelform类里进行操作
4.3.3、表单只输入部分属性时:
@csrf_exempt
def order_add(request):
    form=OrderModelFrom(data=request.POST)
    if form.is_valid():

   oid属性数据可以在这里加上     
        form.instance.oid=“自己想加啥就加啥”
        form.save()
        data_dict={"status":True}
        return JsonResponse(data_dict)
    data_dict={"status":False,'error':form.errors}
    return JsonResponse(data_dict)

4、下面讲讲输入校验:
4.4.1、普通路由方法的校验:
def user_add(request):
    if request.method=="GET":
        form=UserModelFrom()
        return render(request,'user_add.html',{"form":form})


    form=UserModelFrom(data=request.POST)#校验
    if form.is_valid():

    form.cleaned_data是表单验证通过后输入的所有数据,类型为字典

        print(form.cleaned_data)  

        form.save()这是判断无误后快速插入数据库操作

        return redirect('/user/list/')
    return render(request,'user_add.html',{"form":form})
结合上面的 <span>{{ field.errors.0 }}</span>进行使用

如果想要对输入校验进行定义,则

class UserModelFrom(forms.ModelForm):
在这定义例如:
    name=forms.CharField(min_lenth=3,label=“用户名”)
这样就对name这一行的输入框进行了一些定义

    class Meta:
        model=models.UserInfo
        fields=["name","password","age","account","create_time","gender","depart"]
.........

也可以用钩子方法:

例如:
from django.core.exceptions import ValidationError

class PrettyModelForm(forms.ModelForm):
    class Meta:
        model=models.PrettyNum
        fields=["mobile","price","level","status"]

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for name,field in self.fields.items():
            field.widget.attrs={"class":"form-control","placeholder":field.label}

      
     所谓钩子函数,其实就是自定义添加一个form.is_valid()里的判断功能。
    def clean_mobile(self):
        txt_mobile=self.cleaned_data["mobile"]
        exists=models.PrettyNum.objects.filter(mobile=txt_mobile).exists()#防止输入重复
        if exists:
            raise ValidationError("手机号已存在")

        if len(txt_mobile)!=11:#防止长度不符合
            raise ValidationError("格式错误")
        return txt_mobile


def prettynum_add(request):
    if request.method=="GET":
        form=PrettyModelForm()
        return render(request,'prettynum_add.html',{'form':form})
    form=PrettyModelForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data) 
        form.save()
        return redirect('/prettynum/list/')
    return render(request,'prettynum_add.html',{'form':form})


报错信息都包含在form里了,所以如果想添加报错信息,可以这样:form.add_error("password","用户名或密码错误"),这样错误信息就能通过password属性调用了
如:<span style="color: red">{{ form.password.errors.0 }}</span>
4.4.2ajax的输入校验:
如例。
@csrf_exempt
def task_add(request):
    form=TaskModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        data_dict = {"status": True}
        return JsonResponse(data_dict)
    data_dict={"status":False,'error':form.errors}
    return JsonResponse(data_dict)

定义data_dict是为了更好的在前端看到反馈,如:

                success: function (res) { 
                        if (res.status) {
                            alert("添加成功");  成功的弹窗
                        } else {
                          将data_dict的error报错字典信息拆成 name、data两部分
          name用于定位输入框,data作为文本形式返回。具体语法参考jquery笔记。
                            $.each(res.error, function (name,data) {
                                console.log(name,data);
                                $("#id_" + name).next().text(data[0])
                            })   
                        }
                    }



如果需要清空错误信息,可参考:
利用类绑定<span class="error-msg" style="color: red;position: absolute"></span>

        function binBtnAddEvent() {
            $("#btnadd").click(function () {
                $(".error-msg").empty()
                $.ajax({........

这样每次提交数据时,都会对原来的错误进行empty()清空,重新生成错误。

5、分页小组件(自定义组件):

可以直接使用。功能较为全面

例如

导入提前写好的
from app01.utils.page import Pagination



def admin_list(request):
    queryset=models.Admin.objects.all()


    #下面这个是组件的使用方法
    page_object=Pagination(request,queryset)
    context={
        "queryset":page_object.page_queryset,

        "page_string":page_object.html()
    }


    return render(request,'admin.html',context)


前端:
<ul class="pagination">
        {{ page_string }}
    </ul>

6、登录功能:

以下是简易登陆界面模板。可以直接参考

    <style>
        .account {
            width: 400px;
            border: 1px solid #dddddd;
            border-radius: 5px;
            box-shadow: 5px 5px 20px #aaa;
            margin-left: auto;
            margin-right: auto;
            margin-top: 100px;
            padding: 20pX 40pX;
        }

        .account h2 {
            margin-top: 10px;
            text-align: center;
        }
    </style>


<div class="account">
    <h2>用户登录</h2>
    <form>
        <div class="form-group">
            <label >用户名</label>
            <input type="text" class="form-control"  placeholder="用户名"></div>
        <div class="form-group">
            <label >密码</label>
            <input type="password" class="form-control"  placeholder="密码">
        </div>
        <input type="submit" value="登 录" class="btn btn-primary"></form>
</div>

表单部分可以用这两种方法,效果一样的

from django.shortcuts import render,redirect
from django import forms

Form的方法
class LoginForm(forms.Form):
    username=forms.CharField(label="用户名")  
    password=forms.CharField(label="密码")
    
ModelForm的方法   
from app01 import models
class LoginModelForm(forms.ModelForm):
    class Meta:
        model=models.Admin
        fields=['username','password']


可以直接在表单内定义样式,这样直接将表单传给前端,前端就不用自己写表单了

6.1、登录功能时,中间件的使用:

原理,每个网络请求都会需要经过中间件:

定义中间件:

最好新建一个目录文件存放中间件文件

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        
    这个函数里面可以自己定义,如果返回为空,则该网站访问可以进行下去。

例如:
class M1(MiddlewareMixin):
    def process_request(self,request):
        if request.path_info=="/login/":   这里是获取当前访问的url
            return

    获取session中的登录字典,如果有,则说明已登录,没有则跳转到登录界面
    这个东西也可以放在每个页面的视图函数开头进行一波判断,但是很麻烦。
        info_dict=request.session.get("info")  
        if info_dict:
            return
        return redirect('/login/')



    #def process_response(self,request,response):
     #   print("zou")

setting.py中注册使用该中间件:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app01.middieware.login.M1',   <--------这个
]

6.2、session的使用:

例如,在登陆函数中
def login(request):
    if request.method=="GET":
        form = LoginForm()
        return render(request,'login.html',{'form':form})

    form = LoginForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        admin_object=models.Admin.objects.filter(**form.cleaned_data).first()
        if not admin_object:
            form.add_error("password","用户名或密码错误")
            return render(request, 'login.html', {'form': form})

        里将登录表单数据存到session中。注意,request.session["info"]是一个字典
        request.session["info"]={'id':admin_object.id,'name':admin_object.username} 这。
        return redirect("/admin/list")

    return render(request,'login.html',{'form':form})

后面如果用到session里的数据的话:

方法1:
直接在调用后端返回的request对象,这样就可以获取session字典中name值了 
aria-expanded="false">{{ request.session.info.name }}<span class="caret"></span></a>
方法2:

在后端的对应视图函数中,通过 info_dict=request.session["info"]

获取到session字典。再通过将字典info_dict返回给前端即可调用。其实原理和方法1一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值