Python – Django ModelForm, having a foreign key as a hidden field

djangopython

I'm basically building a very trivial form. Let's stick to the books/publisher examples given in the django tutorials and build upon that.

I have a user login to the web app, at which point the first thing they can do is click on a publisher. This publisher then gets saved for their session. Upon that I take them to a create book form. In there I embed the the publisher's id from the database into a hidden field.

Upon the user submitting an HTTP POST, I do something like:

mybookform = BookForm(request.POST)
if mybookform.is_valid():
    abook = mybookform.save(commit=False)
    abook.publisher_id = request.POST['publisher_id']
    mybookform.save()

Yes there's a few naive things done here, such as blindly grabbing the publisher_id and verifying if it's indeed a real publisher id, amongst other security issues. Let's just not pay attention to that for the moment.

My question is, is there a better way of handling this? Although hypothetically this example doesn't make logistical sense, in my particular app the example actually makes sense. The problem is I get a ValueError exception saying publisher_id needs to be a Publisher instance.

Now I can easily retrieve a publisher instance with Publisher.objects.filter(id=..) and use that instead. The question is, is it really necessary? Can I avoid the additional query to the database and somehow update this form instance in a more 'elegant' fashion?

Also, is it possible to somehow embed the publisher in a hidden field so that I do not need to do mybookform.save(commit=False) and just do mybookform = BookForm(request.POST) followed by mybookform.save() immediately?

Best Answer

Retrieving the instance of the publisher does protect against client-side changes that might reference a completely invalid publisher.

To your second question, yes you can include that field as a hidden field by overriding the field in the ModelForm with the approriate form field setting the widget to HiddenInput.

Related Topic