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,提问作者Андрей Королёв
相关产品推荐
相关产品推荐

