views:

324

answers:

1

Hello, I need to add extra validation to my DateField in Admin to make sure the date given is in the future. I have no experience in such a thing, so here's what I've done. 1) I've created custom form field and added validation to it:

class PastDateField(forms.DateField):
    def clean(self, value):
    """Validates if only date is in the past
    """
        if not value:
            raise forms.ValidationError('Plase enter the date')
        if value > datetime.now():
            raise forms.ValidationError('The date should be in the past, not in future')
        return value

2) Then I've added custom model form:

class CustomNewsItemAdminForm(forms.ModelForm):
    title = forms.CharField(max_length=100)
    body = forms.CharField(widget=forms.Textarea)
    date = PastDateField()
    region = forms.ModelChoiceField(Region.objects)

3) And here's how I've registered admin:

class NewsItemAdmin(admin.ModelAdmin):
    form = CustomNewsItemAdminForm

    def queryset(self, request):
        return NewsItem.objects.all()

admin.site.register(NewsItem, NewsItemAdmin)

The result of this is that my admin form 1) Shows field I haven't specified in custom admin form 2) Lacks JavaScript calendar for the datetime field

It's pretty obvious to me that I'm doing something wrong, but I've found no examples relevant to my needs as I am a noob. What is the better way to add custom validation to datetime field without messing things up?

EDIT: Thanks a lot to Brian Luft and Daniel Roseman for correct answers! To make this post helpful for someone facing the same problem here is the resulting code:

class CustomNewsItemAdminForm(forms.ModelForm):
    class Meta:
        model = NewsItem

    def clean_date(self):
        """Validates if only date is in the past
        """
        date = self.cleaned_data["date"]
        if date is None:
            raise forms.ValidationError('Plase enter the date')
        if date > datetime.now().date():
            raise forms.ValidationError('The date should be in the past, not in future')
        return self.cleaned_data["date"]

class NewsItemAdmin(admin.ModelAdmin):
    form = CustomNewsItemAdminForm

    def queryset(self, request):
        return NewsItem.objects.all()

admin.site.register(NewsItem, NewsItemAdmin)
+2  A: 

Firstly, declaring fields explicitly on a ModelForm - whether in or out of the admin - does not mean that the other fields will not be displayed. You need to define the fields or exclude tuples in the form's inner Meta class. If the other fields are all the default, you can simply declare the one you are overriding.

Secondly, if you want your custom field to use the javascript, you'll need to use the right widget, which is django.contrib.admin.widgets.AdminDateWidget. However, there is a much easier way to do this, which is not define a custom field at all, but instead define a clean_date method on the form itself.

Daniel Roseman