Marcio Cruz
Marcio Cruz

Reputation: 2069

Django's ModelForm with an HiddenInput returns invalid

I'm making a small project to learn Django, and i'm having some problems trying to use hidden fields inside a ModelForm.

Theres the class:

class Post(models.Model):
    title       = models.CharField(max_length = 140)
    message     = models.CharField(max_length = 10000)
    pub_date    = models.DateTimeField()

And my ModelForm:

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'message', 'pub_date',)
        widgets = {
            'message' : Textarea(attrs={'cols':80, 'rows':20}),
            'pub_date' : HiddenInput(),
        }

This is the view:

def edit(request, post_id):
    if request.method == 'POST':
        form = PostForm(request.POST, request.FILES)
        if form.is_valid():
            print 'VALID'
            dados = form.cleaned_data
            post = Post.objects.get(pk=post_id)
            post.title = dados['title']
            post.message = dados['message']
            post.save()
            return HttpResponseRedirect(reverse('blog.views.detail', args=(post.id,)))
        else:
            print 'INVALID'
    form = PostForm(instance=Post.objects.get(pk=post_id))
    return render_to_response('blog/add_post.html', {'form' : form,}, context_instance = RequestContext(request))

This is the HTML generated for the form:

<div style='display:none'>
<input type='hidden' name='csrfmiddlewaretoken' 
value='3b7c0735bf464fb4fd7dcd3011050e1c' />

</div>
<tr>
    <th><label for="id_title">title:</label></th>
    <td><input id="id_title" type="text" name="title" value="asd1111111111" maxlength="140" /></td>
</tr>
<tr>
    <th><label for="id_message">message:</label></th>
    <td><textarea id="id_message" rows="20" cols="80" name="message">asd11111111111</textarea>
    <input type="hidden" name="pub_date" value="2010-12-19 17:08:22.498000" id="id_pub_date" /></td>
</tr>

I use the same template to both create and edit posts. When i'm creating, pub_date is set in another view, and when i'm editing, I can't change pub_date on my template (thus the hidden field). On this example, form.is_valid() always return False. If I remove the 'pub_date' : HiddenInput(), line from my form, it returns True. What am I doing wrong?

Upvotes: 4

Views: 3267

Answers (3)

shadfc
shadfc

Reputation: 6594

Another alternative is to just change the widget type to SplitHiddenDateTimeWidget

Upvotes: 1

The problem is in the conversion from string to datetime object.

The datetime field, if no input_formats argument is specified, takes these formats for string->datetime conversion.

(from the docs: http://docs.djangoproject.com/en/dev/ref/forms/fields/#datetimefield)

'%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
'%Y-%m-%d',              # '2006-10-25'
'%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
'%m/%d/%Y',              # '10/25/2006'
'%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
'%m/%d/%y %H:%M',        # '10/25/06 14:30'
'%m/%d/%y',              # '10/25/06'

So your value of 2010-12-19 17:08:22.498000 won't work.

The default widget for DateTimeField is DateTimeInput widget which formats the datetime to a string correctly, but HiddenInput just takes the datetime object w/ no formatting as you've shown.

If you want to use HiddenInput you need to strftime the datetime object to be in the correct format.

An alternative option if you just want to hide it is to not set the widget as HiddenInput but simply keep the DateTimeInput widget as is and hide that element with the attrs argument.

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'message', 'pub_date',)
        widgets = {
            'message' : Textarea(attrs={'cols':80, 'rows':20}),
            'pub_date' : DateTimeInput(attrs={'style': 'display:none;'}),
        }

Upvotes: 1

Timbadu
Timbadu

Reputation: 1551

Do you want the pub date to be the date of the post? Is so have you tried auto_now in your models?

pub_date    = models.DateTimeField(auto_now=True)

Upvotes: 2

Related Questions