Django表单验证问题:日期不可过期且用户日期需唯一
Hey there! Let's tackle those two form validation issues you're facing. I'll break down the fixes step by step so you can get those error messages showing up correctly and prevent duplicate entries.
1. Fixing the missing "past date" error message
The root cause here is in your views.py code. When the form fails validation (like submitting a past date), you're creating a brand new empty form instead of passing back the invalid form with error messages attached. Here's how to fix that:
Update your add view to preserve the invalid form:
def add(request): if request.user.is_authenticated: user = request.user # Use the user instance directly instead of just the ID if request.method == 'POST': # Pass the user to the form (we'll use this for duplicate checks later) form = AddMyModel(request.POST, user=user) if form.is_valid(): date = form.cleaned_data['date'] # No need to fetch User again—request.user is already the instance mymodel = MyModel(user=user, date=date) mymodel.save() return render(request, 'mysite/successfuladd.html', {"login": True}) # If form is invalid, we keep the form with errors else: # For GET requests, pass the user to initialize the form form = AddMyModel(user=user) # Render the template with the form (either empty or with errors) return render(request, 'mysite/add.html', {'form': form, 'login': True}) else: return render(request, 'mysite/homepage.html', {'login': False})
2. Adding duplicate user+date validation
To prevent duplicate entries, we need to check if the current user already has an entry for the submitted date. First, modify your form to accept the user object during initialization, then add that check in the clean_date method:
Update forms.py:
from django import forms from django.utils import timezone from .models import MyModel class AddMyModel(forms.Form): date = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'})) def __init__(self, *args, **kwargs): # Extract the user from kwargs before calling the parent constructor self.user = kwargs.pop('user') super().__init__(*args, **kwargs) def clean_date(self): date = self.cleaned_data['date'] # Check for past date if date < timezone.now().date(): raise forms.ValidationError("Date cannot be in the past") # Check for existing entry with this user and date if MyModel.objects.filter(user=self.user, date=date).exists(): raise forms.ValidationError("The given date is already defined") return date
3. Ensure errors are displayed in your template
Finally, make sure your add.html template renders the error messages for the date field. Here's a simple example of how to do that:
<form method="post"> {% csrf_token %} <div> {{ form.date.label_tag }} {{ form.date }} {% if form.date.errors %} <div style="color: red;"> {% for error in form.date.errors %} <p>{{ error }}</p> {% endfor %} </div> {% endif %} </div> <button type="submit">Submit</button> </form>
Why this works:
- By passing the invalid form back to the template, Django keeps track of the validation errors and makes them available via
form.date.errors. - Adding the user to the form lets us check against the existing entries in the database using the current authenticated user.
- The
clean_datemethod now handles both validation checks, so both error messages will be attached to the date field and displayed in your template.
内容的提问来源于stack exchange,提问作者kolekole

