栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Django入门到放弃 学习笔记 09

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Django入门到放弃 学习笔记 09

跟b站武沛齐老师的视频学习
对学习过程进行一些记录以便复习 同时自我督促 :D冲鸭

视频链接: 15天django入门到放弃-哔哩哔哩.

文章目录
  • Form 验证整理
    • ajax提交 例
  • 相关参数(生成HTML标签)
  • 保留上次输入内容
  • 示例
    • 班级管理
    • 学生管理
    • 教师管理
  • 数据无法动态显示
  • 插件及样式定制
  • 常用插件
  • 验证扩展
  • 总结
  • 补充:文件上传

本篇均为 Form 相关内容

Form 验证整理

 - 用户提交数据进行校验
   - Form 提交(刷新,失去上次内容)
     a. LoginForm(Form)
       字段名 = xxxx.xxFields() # 本质验证规则,正则表达式
       字段名 = xxxx.xxFields() # 本质验证规则,正则表达式
       字段名 = xxxx.xxFields() # 本质验证规则,正则表达式
       字段名 = fiedls.RegexField(‘正则表达式’, error_messages={xx})
     b. obj = LoginForm(用户提交的数据)
     c. result = obj.is_valid()
     d. obj.cleaned_data
     e. obj.errors

     - 内部原理
       1. LoginForm 实例化时,
         self.fields={
           ‘user’: 正则表达式
           ‘pwd’: 正则表达式
         }
       2. 循环self.fields
         flag = true
         errors
         cleaned_data
         for k, v in self.fields.items():
           # k是: user, pwd
           # v是: 正则表达式
           # 1. user, 正则表达式
           input_value = request.POST.get(k)
           正则表达式和input_value不匹配
           flag = False
         return flag
   - Ajax 提交(不刷新,上次内容自动保留)
   
   PS:Ajax 提交 > Form 提交

   总结:
     class Foo(Form):
       字段 = 正则表达式
       字段 = 自定义正则表达式

 - 保留上次输入内容

ajax提交 例

views.py:

from django.shortcuts import render, redirect, HttpResponse
from django.forms import Form, fields
import json


class LoginForm(Form):
    username = fields.CharField(required=True)
    password = fields.CharField(min_length=18)


def ajax_login(request):
    ret = {'status': True, 'msg': None}
    obj = LoginForm(request.POST)
    if obj.is_valid():
        print(obj.cleaned_data)
    else:
        print(obj.errors)
        ret['status'] = False
        ret['msg'] = obj.errors
    v = json.dumps(ret)
    return HttpResponse(v)

前端收到的v:{“status”: false, “msg”: {“password”: [“Ensure this value has at least 18 characters (it has 12).”]}}
在每个组件后添加提示的办法:

var tag = document.createElement('span');
tag.innerHTML = value[0];
tag.className = 'c1';
$('#f1').find('input[name="' + index + '"]').after(tag);

为了使每次重新提交时之前的 tag 消失,为它添加 c1 类属性,然后再请求处理开头加上 $('.c1').remove();;
代码如下:




    
    Title


    

用户登录

{% csrf_token %}

用户: {{ obj.errors.username.0 }}

密码: {{ obj.errors.password.0 }}

提交
相关参数(生成HTML标签)
widget=None,                 HTML插件
label=None,                  用于生成Label标签或显示内容
initial=None,                初始值
help_text='',                帮助信息(在标签旁边显示)
disabled=False,              是否可以编辑
label_suffix=None            Label内容后缀
(自动生成 HTML 标签)

required=True,               是否允许为空
error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[],               自定义验证规则
localize=False,              是否支持本地化

示例:
views.py:

class TestForm(Form):
    t1 = fields.CharField(
        required=True,
        label='用户名',
        help_text='helptext',
        initial='initial',
        disabled=True,
        label_suffix=':',
        # 只推荐这个:
        widget=forms.textarea,
    )


def test(request):
    obj = TestForm()
    return render(request, 'test.html', {'obj': obj})

test.html:

    
{% csrf_token %}

{{ obj.t1.label }} {{ obj.t1 }} {{ obj.t1.help_text }}

{{ obj.as_p }}
保留上次输入内容
  1. Ajax 仅用验证功能
  2. Form 验证功能 + 生成 HTML 标签
    obj = TestForm(request.POST)
示例 班级管理

models.py:

class Classes(models.Model):
    title = models.CharField(max_length=32)

views.py:

class ClassForm(Form):
    title = fields.RegexField('1618d+')


def class_list(request):
    cls_list = models.Classes.objects.all()
    return render(request, 'class_list.html', {'cls_list': cls_list})


def add_class(request):
    if request.method == "GET":
        obj = ClassForm()
        return render(request, 'add_class.html', {'obj': obj})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            models.Classes.objects.create(**obj.cleaned_data)
            return redirect('/class_list/')
        else:
            return render(request, 'add_class.html', {'obj': obj})


def edit_class(request, nid):
    if request.method == "GET":
        row = models.Classes.objects.filter(id=nid).first()
        # 让页面显示初始值
        obj = ClassForm(initial={'title': row.title})
        return render(request, 'edit_class.html', {'nid': nid, 'obj': obj})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/class_list/')
        else:
            return render(request, 'edit_class.html', {'nid': nid, 'obj': obj})

class_list.html:




    
    Title


    

班级列表

    {% for row in cls_list %}
  • {{ row.title }} 编辑
  • {% endfor %}

add_list.html:




    
    Title


    

添加班级

{% csrf_token %}

{{ obj.title }} {{ obj.title.errors.0 }}

注意,编辑班级对应的 url 为:re_path(r'^edit_class/(d+)/', views.edit_class),;
edit_class.html:




    
    Title


    

编辑班级

{% csrf_token %}

{{ obj.title }} {{ obj.title.errors.0 }}

学生管理

models.py:

class Student(models.Model):
    name = models .CharField(max_length=32)
    email = models.CharField(max_length=32)
    age = models.IntegerField(max_length=32)
    cls = models.ForeignKey('Classes', on_delete=models.DO_NOTHING)

views.py:

class StudentForm(Form):
    name = fields.CharField(min_length=2, max_length=6)
    email = fields.EmailField()
    age = fields.IntegerField(min_value=18, max_value=25)
    cls_id = fields.IntegerField(
        widget=widgets.Select(choices=models.Classes.objects.values_list('id', 'title'))
    )


def student_list(request):

    stu_list = models.Student.objects.all()
    return render(request, 'student_list.html', {'stu_list': stu_list})


def add_student(request):
    if request.method == "GET":
        obj = StudentForm()
        return render(request, 'add_student.html', {'obj': obj})
    else:
        obj = StudentForm(request.POST)
        if obj.is_valid():
            models.Student.objects.create(**obj.cleaned_data)
            return redirect('/student_list/')
        else:
            return render(request, 'add_student.html', {'obj': obj})


def edit_student(request, nid):
    if request.method == "GET":
        # 此处直接取到一个字典,方便初始化,values要写在first前面,因为first不能对values得到的字典做操作
        row = models.Student.objects.filter(id=nid).values('name', 'email', 'age', 'cls_id').first()
        # 让页面显示初始值
        obj = StudentForm(initial=row)
        return render(request, 'edit_student.html', {'nid': nid, 'obj': obj})
    else:
        obj = StudentForm(request.POST)
        if obj.is_valid():
            models.Student.objects.create(**obj.cleaned_data)
            return redirect('/student_list/')
        else:
            return render(request, 'edit_student.html', {'obj': obj, 'nid': nid})

student_list.html:




    
    Title


    

学生列表

添加
    {% for row in stu_list %}
  • {{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }} 编辑
  • {% endfor %}

add_student.html:




    
    Title


    

添加学生

{% csrf_token %}

用户名:{{ obj.name }}

邮箱:{{ obj.email }}

年龄:{{ obj.age }}

班级:{{ obj.cls_id }}

edit_student.html:




    
    Title


    

编辑学生

{% csrf_token %}

用户名:{{ obj.name }} {{ obj.name.errors.0 }}

邮箱:{{ obj.email }} {{ obj.email.errors.0 }}

年龄:{{ obj.age }} {{ obj.age.errors.0 }}

班级:{{ obj.cls_id }} {{ obj.cls_id.errors.0 }}

教师管理

多选:

xx = fields.CharField(
	widget=widgets.Select(
		choices=models.Classes.objects.values_list('id', 'title'),
		attrs={'multiple': 'multiple'}
	),
)

使用这种方法是不能达到多选的目的的,因为 Select 的实现是用 request.get(''),只能拿到一个数据,应该用 SelectMultiple。
拿到数据格式为:
{'tname': 'xxx', 'xx': "['1', '2']"}
仍然不好处理,改为使用 MultipleChoiceFields:

xx = fields.MultipleChoiceField(
choices=models.Classes.objects.values_list('id', 'title')
)

总结:

  单选:CharFields + Select
     ChoiceFields + choices
  多选:MultipleChoice + choices

编辑老师中,实现初始化:

row = models.Teacher.objects.filter(id=nid).first()
class_ids = row.c2t.values_list('id')

得到数据格式为:
zip 方法:

因此加上:

id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []
obj = TeacherForm(initial={'tname': row.tname, 'xx': id_list})

这样的到的数据形式为:(1, 2)

代码:
models.py:

class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    c2t = models.ManyToManyField('Classes')

views.py:

def teacher_list(request):
    tea_list = models.Teacher.objects.all()
    return render(request, 'teacher_list.html', {'tea_list': tea_list})


def add_teacher(request):
    if request.method == "GET":
        obj = TeacherForm()
        return render(request, 'add_teacher.html', {'obj': obj})
    else:
        obj = TeacherForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            xx = obj.cleaned_data.pop('xx')
            row = models.Teacher.objects.create(**obj.cleaned_data)
            row.c2t.add(*xx)
            return redirect('/teacher_list/')
        else:
            print(obj.errors)
            return render(request, 'add_teacher.html', {'obj': obj})


def edit_teacher(request, nid):
    if request.method == "GET":
        row = models.Teacher.objects.filter(id=nid).first()
        class_ids = row.c2t.values_list('id')
        id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []
        print(id_list)
        obj = TeacherForm(initial={'tname': row.tname, 'xx': id_list})
        return render(request, 'edit_teacher.html', {'obj': obj, 'nid': nid})
    else:
        pass

teacher_list:




    
    Title


教师列表

{% for row in tea_list %} {% endfor %}
ID 姓名 任教班级 操作
{{ row.id }} {{ row.tname }} {% for item in row.c2t.values %} {{ item.title }} {% endfor %} 编辑

add_teacher.html;




    
    Title


{% csrf_token %}

姓名:{{ obj.tname }}

班级:{{ obj.xx }}

edit_teacher.html:




    
    Title


编辑老师

{% csrf_token %} {{ obj.tname }} {{ obj.xx }}
数据无法动态显示

TeacherForm 进行了一次对象实例化,生成一个对象,不再更新。导致 Class 中添加了新的班级,增加教师页面的班级选择并未更新。
解决办法:为 TeacherForm 类增加 __init__ 方法

    def __init__(self, *args, **kwargs):
        super(TeacherForm, self).__init__(*args, **kwargs)
        self.fields['xx'].widget.choices = models.Classes.objects.values_list('id', 'title')
插件及样式定制

在 views.py 中添加样式后传给前端:

class StudentForm(Form):
    name = fields.CharField(min_length=2, max_length=6, widget=widgets.TextInput(attrs={'class': 'form-control'}))
    email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'}))
    age = fields.IntegerField(min_value=18, max_value=25, widget=widgets.TextInput(attrs={'class': 'form-control'}))
    cls_id = fields.IntegerField(
        widget=widgets.Select(choices=models.Classes.objects.values_list('id', 'title'),
                              attrs={'class': 'form-control'})
    )

引用 bootstrap:




    
    Title
    
    


编辑学生

{% csrf_token %}
{{ obj.name }} {{ obj.name.errors.0 }}
{{ obj.email }} {{ obj.email.errors.0 }}
{{ obj.age }} {{ obj.age.errors.0 }}
{{ obj.cls_id }} {{ obj.cls_id.errors.0 }}

出现如下提示,是浏览器自带的验证功能,给 form 加上 novalidate 即可阻止:

常用插件
  • checkBox
  • radio
  • iput
  • textarea
  • File
验证扩展

在原有验证规则基础上添加其他正则,会逐个进行验证:

from django.core.validators import RegexValidator
class MyForm(Form):
    user = fields.CharField(
        validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字'), 
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
        ]
    )
总结
  1. 使用
    class Foo:
      xx = xxxx() # 正则,插件

      def clean_xx():
        …

      def clean():
        pass
  2. 页面展示
    obj = Foo()

    # 灵活
      

        {{ obj.xx }}
        {{ obj.xx }}
        …
      
    # 简单
      {{ obj.as_p }}
      

          {{ obj.as_ul }}
        

      
        {{ obj.as_table }}
      

  3. 后台
    is_valid()
    clean_data
    errors
补充:文件上传

方式一:

import os
from django.core.files.uploadedfile import InMemoryUploadedFile
def f1(request):
    if request.method == "GET":
        return render(request, 'f1.html')
    else:
        file_obj = request.FILES.get('fafafa')
        print(file_obj.name)
        print(file_obj.size)
        f = open(os.path.join('static', file_obj.name), 'wb')
        for chunk in file_obj.chunks():
            f.write(chunk)
        f.close()
        return render(request, 'f1.html')

f1.html:




    
    Title


    
        {% csrf_token %}
        
        
    


方式二:

class F2Form(Form):
    user = fields.CharField()
    fafafa = fields.FileField()


def f2(request):
    if request.method == "GET":
        obj = F2Form()
        return render(request, 'f2.html', {'obj': obj})
    else:
        obj = F2Form(data=request.POST, files=request.FILES)
        if obj.is_valid():
            print(obj.cleaned_data.get('fafafa').name)
            print(obj.cleaned_data.get('fafafa').size)
        return render(request, 'f2.html', {'obj': obj})

f2.html:




    
    Title


    
{% csrf_token %} {{ obj.user }} {{ obj.fafafa }}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/296137.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号