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

Django表单is_valid未校验short_url唯一性,提交无响应问题排查

Django表单未校验unique字段的问题原因分析

问题描述

在Django开发中,我遇到表单校验问题:models.py中Links模型的short_url字段设置了unique=True,但调用form.is_valid()时并未校验该字段的唯一性。提交重复的short_url值时,页面仅刷新,无法创建新条目,无任何报错或反馈。

相关代码

models.py

from django.db import models
from django.contrib.auth.models import User

class Links(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Пользователь')
    long_url = models.CharField('Длинная ссылка', max_length=300)
    short_url = models.SlugField('Сокращенная ссылка', max_length=50, unique=True)
    title = models.CharField('Название для ссылки', max_length=80)

    def __str__(self):
        return self.title

views.py

from django.shortcuts import render, redirect
from django.views.generic import ListView
from .models import Links
from .forms import AddLinkForm

def links(request):
    return render(request, 'main/main_page.html')

class LinksList(ListView):
    model = Links
    template_name = 'links/links.html'
    ordering = ['-id']

    def get_context_data(self, *, object_list=None, **kwargs):
        ctx = super(LinksList, self).get_context_data(**kwargs)
        user = self.request.user
        links = Links.objects.filter(user=user)
        form = AddLinkForm
        ctx['form'] = form
        ctx['links'] = links
        return ctx

    def post(self, request, *agrs, **kwargs):
        post = request.POST.copy()
        post['user'] = request.user
        request.POST = post

        form = AddLinkForm(request.POST)

        if form.is_valid():
            form.save()

        return redirect('links')

forms.py

from django import forms
from .models import Links

class AddLinkForm(forms.ModelForm):
    long_url = forms.CharField(
        required=True,
        label='Длинная ссылка',
        widget=forms.TextInput(attrs={'placeholder': 'Введите длинную ссылку'})
    )

    short_url = forms.SlugField(
        required=True,
        label='Сокращенная ссылка',
        widget=forms.TextInput(attrs={'placeholder': 'Введите сокращенную ссылку'})
    )

    title = forms.CharField(
        required=True,
        label='Введти название для вашей ссылки',
        widget=forms.TextInput(attrs={'placeholder': 'Введите название здя вашей ссылки'})
    )

    class Meta:
        model = Links
        fields = ['user', 'long_url', 'short_url', 'title']
        widgets = {'user': forms.HiddenInput()}

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('label_suffix', ':')
        super(AddLinkForm, self).__init__(*args, **kwargs)

问题原因

1. 验证失败后直接重定向,丢失错误信息

在LinksList的post方法中,无论表单验证是否通过,都直接执行return redirect('links')。当short_url重复导致表单验证失败时,包含错误信息的表单对象没有被传递到模板,用户看不到任何报错提示,只会看到页面刷新。

2. 手动修改request.POST的方式不符合规范

你通过复制request.POST并设置post['user'] = request.user的方式传递用户信息,这种操作会干扰表单的正常校验流程。Django的ModelForm处理外键字段时,应该在表单验证通过后,通过commit=False创建实例并手动赋值用户,而不是修改请求数据。

3. 未捕获数据库层面的唯一性约束异常

即使表单验证阶段未触发唯一性校验,执行form.save()时数据库会因unique=True约束抛出IntegrityError,但你的代码没有捕获该异常,也没有将错误信息反馈给用户,导致用户无法得知操作失败的原因。


内容的提问来源于stack exchange,提问作者Андрей Королёв

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 09:33:17