I have a form with some Model(Multiple)Choice fields that have so many options that I would like to trim down the available options based on user responses on the front-end, and then populate the select options through AJAX.
I am a little confused as to when Django will query the database in this case, and what are considered the best practices for Django ModelChoice fields that are populated with AJAX data.
Originally, I had been doing things like this:
contact = forms.ModelChoiceField(queryset=aRelatedModel.objects.all())
or a restricted queryset:
contact = forms.ModelChoiceField(queryset=aRelatedModel.objects.filter(somefield = someValue))
So, my question is, when does the DB get queried for ModelChoice options?
The confusion stems from another form I did, where I had a ModelChoiceField with the ability to add new options dynamically. In that case, unless I instantiated the ModelChoiceField after saving the new option, I would get an error. This makes me feel like the database is queried on form instantiation. But, given the lazy nature of Django querysets, it seems like it would also make sense that the DB is not queried until you iterate over said list (ie, when printing the form options).
So, in this kind of case is there a way to avoid potentially needless DB queries? What is the best practice for ModelChoiceFields that will be populated with AJAX data?
I've seen mentions of:
contact = forms.ModelChoiceField(queryset=aRelatedModel.objects.none())
...but never any explicit explanation on why to use this.
Edit:
In that case, I had a form with
field = forms.ModelChoiceField(queryset = relatedModel.objects.all())
Subsequently in the view, I naively did:
myForm = modelForm(request.POST). This produced an error if I instantiated the form before first saving the dynamically added field. After adding the field, and then calling modelForm(request.POST) I no longer had an "invalid choice" error - presumably because the dynamically added field was now included in the modelForm queryset.
I am not sure how that is relevant to the question, however. The question is when a modelForm's queryset is populated with data from the DB.
Related
I have a model with tons of (10-20) fields, some of which are Textarea fields.
All of the textare fields should have a certain size (which differs from the default). I could set them all using the widget dictionary in the Meta class, but then i'd have to set them one by one, which seems unnecessary redundant.
Is there any better way to solve this?
Update:
Since it was suggested in the comments to use database normalization, I'm going to flesh out my case a little bit:
I have an model object which has the main purpose of taking in a lot of user data (i.e. an "application"). The benefit of just writing out every question to the user as one field is that I can easily create a model form for it and display and edit the data in the admin (which is good for my crm people as well).
I could create a dictonary like model for every field of the form but I'm not sure how I would go about actually using a ModelForm for creating it.
On the basis of your data, I can only offer this approach:
from django import forms
textarea_fields = ['field1', 'field2']
form = YourForm()
for field_name in [f for f in form.fields.keys() if f in textarea_fields]:
form.fields[field_name].widget = forms.Textarea()
I've got a django form that contains a join via a foreign key. This is a foreign key to a very large table. On the form, to prevent loading up a massive select that tends to crash browsers, I've got a jQuery autocomplete, which on each keystroke sends off the entered text. This text is then searched in the table and suitable results are returned to be displayed. The id is then passed to a hidden CharField when one is selected. This hidden CharField is the widget for the ForeignKey relation. When I try to save the form, I get an error that I need to be passing a model instance for the related model, which is fair enough. I can't work out how to do this however. I can take that id and do a model.objects.get(pk=id_from_form), but if I replace the POST data with the result of this, I still get an error as I'm just passing the __unicode__ method of the model. I'm sure there's something I'm missing, but I can't see what it is.
Thanks.
Instead of using a CharField to store the id, try using a ModelChoiceField with the widget set as a HiddenInput. The field definition in your form would look something like:
mymodel = forms.ModelChoiceField(widget=forms.HiddenInput, queryset=MyModel.objects.all())
I am a current web2py user, but find I still go back to Django once in a while (where I started). Specifically when working on projects where I want to make use of some specific django apps/plugins/extensions that don't yet exist in web2py.
One thing that I can't live without in web2py, which I am looking for a solution for in Django, is the way to create html forms from a db table and being able to then customize their look and layout in the view, without javascript.
Key things I am looking for:
Generate html form from a db table
Assign custom css classes/ids to each field in the generated html form (js disabled)
Place each form field/element in a pre-made html view via a method call in the view
i.e.
I have a table A. In web2py I can do (in controller):
def display_form():
form = SQLFORM(db.table_A)
#Can I do the following in Django? Assign custom CSS to each form field?
form.element(_name='email')['_class'] = = "custom_css_classes, list"
if form.accepts(request.vars, session):
response.flash = 'form accepted'
elif form.errors:
response.flash = 'form has errors'
else:
response.flash = 'please fill out the form'
return dict(form=form)
Then, in the View I can do:
form.custom.start
form.custom.widget.name
form.custom.widget.email
form.custom.widget.form_field_name
...
<div class="span-5 last"><input type="submit" class="register_btn" value="Sign Up"></input></div>
form.custom.end
The above takes a DB table, creates an HTML form, and then lets me stick each separate form field in any place in the pre-made HTML that I want (using those "custom" method calls on the passed "form" object. Including the custom css classes I assigned to each separate field of the generated html form.
See documentation for details on the above code:
http://web2py.com/book/default/chapter/06?search=define_table
http://web2py.com/book/default/chapter/07?search=sqlform#SQLFORM
http://web2py.com/book/default/chapter/05?search=#Server-side-DOM-and-Parsing
http://web2py.com/book/default/chapter/07?search=form.custom
How do I do the above in Django without dirtying my javascript with layout hacks. Assume javascript is disabled in the browsers where I need my app to run. Furthermore, I would love to make use of Django admin. Pylons solutions also welcome!
Links to articles/tutorials/howtos for this would be greatly appreciated.
Also, please make an equivalent result of the above code using the method you mention in your response...
Use ModelForm and override any field you wanna customize by explicitly declaring them.
If you want to set field attributes like class and id, you need to do something like this:
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
In case you are interested, you may change the order of the fields by specifying a fields sequence in your Meta class:
class Meta:
model = YourModel
fields = ('title', 'content')
You may read the full documentation here:
http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs
If you haven't already, take a look at Django's ModelForm. I am assuming that you have models mapped to the tables in question. Vanilla ModelForm instances will work without JS. However ModelForms are usually defined ahead of time and not constructed on the fly. I suppose they can be created on the fly but that would be a bit tricky.
I have a requirement where one user creates an 'instance' of an object via a ModelForm. Another user of a different group has access to read all of the fields of the form, but has to update only one field. Think of a student who creates an exam object. Then a teach pulls up the exam and just needs to put in a grade, the rest of the exam is read only.
What's the best way to do that? Should I just query for the object, and display each field individually, then create a form (not a ModelForm?) for just the one field?
Should I just query for the object, and display each field individually, then create a form (not a ModelForm?) for just the one field?
This is probably the best way to go about it. Note you can use a ModelForm for the teacher form, see the Django documentation on using a subset of fields on a model form. You will have to display all the other fields manually in your template, but you should probably have a separate template for this view (I would use separate views as well).
You could find some code for a read only field on Django Snippets, but generally it's better to be explicit about what fields you are updating from each view. This is likely to be more trouble than it's worth.
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?
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.
There is no better way to do this.
I would use the get_object_or_404 function for this.
And yes, you can prevent this to be modified by the user by setting the model field to editable=False,