You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django模板中显示Serializer验证错误?

解决DRF注册页面验证错误不显示的问题

一、修正视图层(views.py)的问题

你的post方法存在两个关键问题:

  1. 使用raise_exception=True会直接抛出异常,DRF会返回400响应,而不会将错误保留在序列化器中供模板渲染。
  2. 验证失败时的redirect("register")没有加return,且重定向会丢失序列化器中的错误信息,应该直接渲染模板并传递带错误的序列化器。

修改后的views.py代码:

class RegisterView(generics.CreateAPIView):
    serializer_class = PersonSerializer
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "register.html"

    def get(self, request: Union[Request, HttpRequest]) -> Union[render, redirect]:
        if "username" in request.session:
            return redirect("home")
        serializer = PersonSerializer()
        return render(request, self.template_name, {"serializer": serializer})

    def post(self, request: Union[Request, HttpRequest]) -> Union[redirect, render]:
        serializer = PersonSerializer(data=request.data)
        # 去掉raise_exception=True,手动处理验证结果
        if serializer.is_valid():
            serializer.save()  # 必须调用save()执行create方法创建用户
            return redirect("login")
        # 验证失败,将带错误的序列化器传回模板
        return render(request, self.template_name, {"serializer": serializer})

二、修正序列化器(serializers.py)的问题

  1. 添加confirmpassword字段:因为Person模型中没有这个字段,需要显式在序列化器中定义它,否则request.data中的confirmpassword不会被序列化器处理,validate方法也无法获取到该值。
  2. 将全局错误改为字段关联错误:原来的validate方法抛出的是全局错误,改为字段级错误或字典形式的错误,让模板能对应到具体字段显示错误。

修改后的serializers.py代码:

from rest_framework import serializers
from .models import Person
from typing import Union

class PersonSerializer(serializers.ModelSerializer):
    GENDER_CHOICES = [
        ("male", "Male"),
        ("female", "Female"),
        ("other", "Other"),
    ]
    
    gender = serializers.ChoiceField(choices=GENDER_CHOICES)
    # 显式添加确认密码字段,仅用于写入(不返回)
    confirmpassword = serializers.CharField(write_only=True)

    class Meta:
        model = Person
        fields = "__all__"
        # 密码字段设置为仅写入
        extra_kwargs = {"password": {"write_only": True}}

    def create(self, validated_data):
        # 移除confirmpassword,模型不需要这个字段
        validated_data.pop("confirmpassword")
        gender = validated_data.pop("gender")
        validated_data["gender"] = gender.lower()
        return Person.objects.create(**validated_data)
    
    def validate_username(self, value):
        # 单独验证用户名唯一性
        if Person.objects.filter(username=value).exists():
            raise serializers.ValidationError('Username already exists')
        return value
    
    def validate_phone(self, value):
        # 单独验证手机号格式
        if len(value) != 10:
            raise serializers.ValidationError("Phone number must be 10 digits")
        return value
    
    def validate(self, data):
        # 验证密码与确认密码匹配
        password = data.get("password")
        confirmpassword = data.get("confirmpassword")
        if password != confirmpassword:
            # 将错误关联到confirmpassword字段
            raise serializers.ValidationError({'confirmpassword': 'Passwords do not match'})
        return data

三、模板(register.html)渲染错误并添加CSS样式

在模板中通过serializer.errors获取错误信息,为每个字段显示对应的错误,同时添加CSS样式美化提示。

示例模板代码:

<!DOCTYPE html>
<html>
<head>
    <title>Register</title>
    <style>
        /* 错误信息样式 */
        .error-message {
            color: #dc3545;
            font-size: 0.875rem;
            margin-top: 0.25rem;
        }
        /* 表单字段容器 */
        .form-group {
            margin-bottom: 1rem;
        }
        /* 错误字段的输入框样式 */
        .form-control.error {
            border-color: #dc3545;
            box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
        }
    </style>
</head>
<body>
    <h2>Register</h2>
    <!-- 显示全局错误(如果有) -->
    {% if serializer.non_field_errors %}
        <div class="error-message">
            {{ serializer.non_field_errors.0 }}
        </div>
    {% endif %}
    <form method="post">
        {% csrf_token %}
        {% for field in serializer %}
            <div class="form-group">
                {{ field.label_tag }}
                {{ field }}
                {% if field.errors %}
                    {% for error in field.errors %}
                        <div class="error-message">{{ error }}</div>
                    {% endfor %}
                {% endif %}
            </div>
        {% endfor %}
        <button type="submit">Register</button>
    </form>
</body>
</html>

关键说明

  • 字段级验证函数(如validate_username)抛出的错误会自动关联到对应字段,模板中通过field.errors获取。
  • 密码匹配的错误关联到confirmpassword字段,确保提示显示在确认密码输入框下方。
  • 使用DRF序列化器的字段渲染({{ field }})会自动生成合适的HTML输入元素,同时保留错误状态。

内容的提问来源于stack exchange,提问作者Sahil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:47:32