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的表单元素控件由表单字段来决定。并且可以使用表单来进行服务端验证,把验证内容跟逻辑处理进行分离。

相关推荐
君爱学习3 分钟前
RocketMQ延迟消息是如何实现的?
后端
哈里谢顿19 分钟前
Django REST Framework 中序列化器的Meta详解
django
Falling4221 分钟前
使用 CNB 构建并部署maven项目
后端
阿蒙Amon28 分钟前
【Python小工具】使用 OpenCV 获取视频时长的详细指南
python·opencv·音视频
程序员小假31 分钟前
我们来讲一讲 ConcurrentHashMap
后端
爱上语文39 分钟前
Redis基础(5):Redis的Java客户端
java·开发语言·数据库·redis·后端
萧曵 丶1 小时前
Rust 中的返回类型
开发语言·后端·rust
橘子编程1 小时前
Python-Word文档、PPT、PDF以及Pillow处理图像详解
开发语言·python
蓝婷儿2 小时前
Python 机器学习核心入门与实战进阶 Day 2 - KNN(K-近邻算法)分类实战与调参
python·机器学习·近邻算法