Django Form实现表单使用及应用场景

首先需要定义一个使用场景:

音乐网站的前端部分可以添加上传歌手的单曲,

这个添加页面就使用django form表单来实现。

目录

数据表内容

歌手表及表模型

单曲表及表模型

演示表单使用

设置路由

创建form.py

视图实例化表单类

模板使用表单对象

表单使用进阶

优化表单类

视图表单使用

总结


数据表内容

下方实现功能时,涉及到一些表的数据操作,所以我把表模型内容粘贴出来。

这样有助于整体理解form使用。

歌手表及表模型

在子应用的models.py中的设定歌手表结构,这里由于在后台有一些功能实现,所以内容较多。

不必过多关注歌手表,因为是单曲添加只是涉及一部分歌手表内容,主要集中在使用单曲表使用。

内容如下:

python 复制代码
class BaseModel(models.Model):
    """ 设置基础模型类 """

    addtime = models.DateTimeField(auto_now_add=True)
    updatetime = models.DateTimeField(auto_now=True)

class Singler(BaseModel):
    """ 歌手表模型 """

    class Meta:
        verbose_name = '歌手'
        verbose_name_plural = '歌手'
        # 正序
        ordering = ['first_letter']

    name = models.CharField(
        '姓名',
        max_length=50,
        help_text='请输入歌手名称'
    )
    first_letter = models.CharField(max_length=15, editable=False)
    # 设置上传位置
    portrait = models.ImageField(
        '照片',
        upload_to=upload_save_path,
        help_text='请上传歌手照片'
    )
    birthday = models.DateField(
        '生日',
        default=date.today,
        help_text='请选择歌手生日',
        blank=True
    )
    height = models.IntegerField(
        '身高(cm)',
        help_text='请输入歌手身高(cm)',
        default=0,
        blank=True
    )
    weight = models.IntegerField(
        '体重(kg)',
        help_text='请输入歌手体重(kg)',
        default=0,
        blank=True
    )
    constellation = models.CharField(
        '星座',
        max_length=50,
        help_text='请输入歌手星座'
    )
    english_name = models.CharField(
        '英文名',
        max_length=50,
        help_text='请输入歌手英文名',
        default='-'
    )
    gender = models.IntegerField(
        '性别',
        help_text='请选择歌手性别',
        choices=((0, '女'), (1, '男')),
        default=1
    )
    country_name = models.CharField(
        '国籍',
        max_length=50,
        help_text='请输入歌手国籍',
        default='-'
    )
    # editable=False 后台将不再显示
    singe_num = models.IntegerField(
        default=0,
        editable=False
    )
    album_num = models.IntegerField(
        default=0,
        editable=False
    )
    desc = models.TextField(
        '简介',
        help_text='请输入歌手简介'
    )

    def __str__(self):
        """ 修改返回格式 """

        return self.name

执行过表迁移后,添加部分数据。

表字段和记录内容如下:

单曲表及表模型

在子应用的models.py中的设定单曲表结构,在这里定义了单曲表所有字段,

一会在添加功能时候,需要实现单曲中这些字段资料的添加。

python 复制代码
class Singe(BaseModel):
    """ 单曲表 """

    class Meta:
        verbose_name = '单曲'
        verbose_name_plural = '单曲'

    name = models.CharField(
        '单曲名称',
        max_length=50,
        help_text='请输入单曲名称',
    )
    duration = models.IntegerField(editable=False, default=0)

    playnum = models.IntegerField(default=0, editable=False)

    path = models.FileField(
        '歌曲文件',
        upload_to=upload_save_path,
        help_text='请上传歌曲',
    )
    lyric = models.FileField(
        '歌曲歌词',
        upload_to=upload_save_path,
        help_text='请上传歌曲歌词',
    )

    # 设置与歌手表关联外键 一对多外键设置在多的模型中
    singler = models.ForeignKey(
        "Singler",
        on_delete=models.CASCADE,
        verbose_name='歌手',
        help_text='请选择歌手'
    )

执行过表迁移后,添加部分数据。

表字段和记录内容如下:

演示表单使用

传统的表单生成方式是在模板文件中编写HTML代码实现。一个完整的表单主要由4部分组成:提交地址、请求方式、元素控件和提交按钮。提交地址和请求方式由form标签设置,提交按钮具有一定特殊性,不通过django form表单来实现。其他文本框、下拉框、复选框等可由django form表单的元素控件来实现。可以简化表单的实现过程和提高表单的灵活性。

设置路由

在urls.py中设置路由地址。

python 复制代码
path('test', views.test, name='test'),

创建form.py

在子项目目录下创建form.py,在其中定义表单类testForm。

名称可以使用charField类型来实现,文件用fileField类型实现。

但是下拉菜单必须使用choiceField类型实现;与表模型类设置有所不同。

内容如下:

python 复制代码
from django import forms
from .models import *


class SingeForm(forms.Form):
    name = forms.CharField(max_length=20, label='单曲名称')
    path = forms.FileField(label='单曲文件')
    lyric = forms.FileField(label='歌词文件')
    # 设置下拉菜单
    names = Singler.objects.all()
    # 将数据以列表的形式标识,列表元素为元组的格式
    singers = [(v.id, v.name) for v in names]
    singer = forms.ChoiceField(label='所属歌手', choices=singers)

视图实例化表单类

视图调用表单并传参给模板。

内容如下:

python 复制代码
from .form import *
def test(request):
    """ 演示form使用 """

    v = SingeForm()
    return render(request, 'test/index.html', locals())

模板使用表单对象

在这里需要判断是否有错误返回,没有错误正常显示添加表单。

python 复制代码
<!DOCTYPE html>
<html>
<body>
<h2>添加歌手单曲</h2>
{% if v.errors %}
    <p>操作失败,问题是:{{ v.errors }}</p>
{% else %}
    {# 表单 #}
    <form action="" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <table>
            {{ v }}
        </table>
        <input type="submit" value="保存">
    </form>
    {# 表单 #}
{% endif %}
</body>
</html>

注意:没有填写提交地址,默认提交本路由。

效果:

浏览器访问,展示表单。

表单使用进阶

在表单演示使用基础上,增加对表单参数的验证,数据处理并添加入库。

优化表单类

在原来基础上,增加单曲名称、单曲文件格式、歌词文件格式自定义验证。

自定义必填提示语内容。

内容如下:

python 复制代码
from django import forms
from .models import *
from django.core.exceptions import ValidationError


def check_name(value):
    if len(value.encode('utf-8')) > 60:
        raise ValidationError('单曲名称不可超过20个字!')


def check_singe(value):
    path_name = str(value)
    if not path_name.endswith(".mp3"):
        raise ValidationError('单曲文件格式为mp3文件!')


def check_lyric(value):
    path_name = str(value)
    if not path_name.endswith(".lrc"):
        raise ValidationError('歌词文件格式为lrc文件!')


class SingeForm(forms.Form):
    name = forms.CharField(
        max_length=20,
        label='单曲名称',
        error_messages={'required': '单曲名称不可为空'},
        validators=[check_name])
    path = forms.FileField(
        label='单曲文件',
        error_messages={'required': '请上传单曲文件'},
        validators=[check_singe]
    )
    lyric = forms.FileField(
        label='歌词文件',
        error_messages={'required': '请上传歌词文件'},
        validators=[check_lyric]
    )
    # 设置下拉菜单
    names = Singler.objects.all()
    # 将数据以列表的形式标识,列表元素为元组的格式
    singers = [(v.id, v.name) for v in names]
    singer = forms.ChoiceField(label='所属歌手', choices=singers)

视图表单使用

增加文件上传、歌曲时长计算、单曲关联歌手并增加相应歌手单曲数;

如果验证不通过,返回错误信息。

这里通过请求的方法进行判断,如果是GET就把表单显示到模板中。

如果是POST请求,就需要把请求获得的参数传递到form表单中,来实现表单验证数据。

这里需要注意的是:如果有文件上传需要设置模板中表单的enctype="multipart/form-data";

因为请求的文件需要单独的获取,故还要再把文件参数单独传给表单。否则就会提示没有上传文件。

下面就是文件上传,保存到服务器端,获取上传文件路径,拿歌曲路径获取歌曲时长。

然后模型操作:单曲的新增,关联歌手相应记录;最后更新相应歌手单曲数。

内容如下:

python 复制代码
from .form import *
from django.http import HttpResponse
import eyed3


def test(request):
    """ 演示form使用 """

    if request.method == 'GET':
        v = SingeForm()
        return render(request, 'test/index.html', locals())
    else:
        v = SingeForm(data=request.POST, files=request.FILES)
        if v.is_valid():
            singe_path = save_media(request.FILES['path'])
            # 上传单曲文件
            singe_path = save_media(request.FILES['path'])
            # 上传歌词文件
            lyric_path = save_media(request.FILES['lyric'])
            # 计算单曲时长
            duration = get_duration_mp3(singe_path)
            # 查询歌手
            singer_id = v.cleaned_data['singer']
            singerDb = Singler.objects.filter(id=singer_id).first()
            # 新增单曲
            singeDb = Singe()
            singeDb.name = v.cleaned_data['name']
            singeDb.duration = duration
            singeDb.path = singe_path
            singeDb.lyric = lyric_path
            # 建立关联
            singeDb.singler = singerDb
            singeDb.save()
            # 歌手增加单曲数
            singerDb.singe_num = singerDb.singe_num + 1
            singerDb.save()
            return HttpResponse('操作成功!')
        else:
            # 获取错误信息,并以json格式返回
            error_msg = v.errors.as_json()
            return render(request, 'test/index.html', locals())


def save_media(file):
    """ 保存文件到服务器 """

    path = os.path.join(settings.MEDIA_ROOT, file.name)
    with open(path, 'wb+') as fp:
        for info in file.chunks():
            fp.write(info)
    return path


def get_duration_mp3(file_path):
    """ 获取mp3音频文件时长 """

    info = eyed3.load(file_path)
    return int(info.info.time_secs)

效果:

验证不通过:

验证通过:

总结

Django的表单功能是通过定义表单类,再由类的实例化生成HTML的表单元素控件,这样可以在模板文件中减少HTML的硬编码。每个HTML的表单元素控件由表单字段来决定。并且可以使用表单来进行服务端验证,把验证内容跟逻辑处理进行分离。

相关推荐
南宫理的日知录19 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
coberup29 分钟前
django Forbidden (403)错误解决方法
python·django·403错误
龙哥说跨境1 小时前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
小白学大数据1 小时前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
flashman9111 小时前
python在word中插入图片
python·microsoft·自动化·word
菜鸟的人工智能之路1 小时前
桑基图在医学数据分析中的更复杂应用示例
python·数据分析·健康医疗
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍