I need a Django Form Field which will take a list of strings.
I'll iterate over this list and create a new model object for each string.
I can't do a Model Multiple Choice Field, because the model objects aren't created until after form submission, and I can't do a Multiple Choice Field, because I need to accept arbitrary strings, not just a series of pre-defined options.
Anyone know how to do this?
Just use a regular text field delimited by commas. After you handle the form submission in the view do a comma string split based on that field. Then iterate over each one creating and saving a new model. Shouldn't be too hard.
In my case to process list of strings I used forms.JSONField(decoder="array") in my forms.py in form class
I came up with a solution -- a little hacky but it works for now.
After grabbing the form data, I stash the list in a variable:
event_locations = form_data.get('event_locations', None)
Then I remove it from form_data, so the Django Form never gets the list:
if event_locations:
del form_data['event_locations']
I instantiate my form with form_data, and handle the list separately:
f = NewEventForm(form_data)
...
for loc in event_locations:
#create new models here
I realize this doesn't directly solve the question I asked, because we still don't have a Django Form Field taking a list, but it's a way to pass in a list to a view that takes a form and be able to handle it.
Related
I have a problem that I want to solve when I add many Input dynamic for example five input
How do I know to list all Input fields generated dynamically on django knowing that I get one field by name only
date=form.cleaned_data.get('date')
The problem is illustrated in the following form:
If you are using django forms, you can use the prefix to distinguish them.
For example, if you have 5 equal forms:
for i in xrange(5):
form = FormExample(data=data, prefix=i)
date=form.cleaned_data.get('date')
As an alternative you can use formsets, you can learn more about them in here
I'm using a formset to collect multiple forms worth of data on one page but something I realized is that the .as_table display for a formset is slightly suboptimal for what I'm trying to do, rather than print each form element as a new table row I was thinking of printing each form itself as an individual row and having a table header with the field names since I know my formset would have the same fields for each form instance. In this way you get a grid of data that a use can fill in. I've done it manually through the template where the form is printed but I was wondering if there was any way I could override formset.as_table to print it in that form rather than in the way it's presently done. Is this possible, has it already been done somewhere or if not how would you suggest I go about it?
You can always create your own Formset (and possibly Form) subclass that overrides the as_table method to output the forms any way you want.
My suggestion, though, is to consider using django-crispy-forms and good CSS definitions.
Override as_table in the class you use for the formset (not the class that uses the formset). Super() the as_table into a variable. Convert that to a string, then repr. Replace "\n" with an empty string. Remove the quote marks at the beginning and end of the repr. Convert that to a string. Call the mark_safe method of the django framework to the resulting string, and return that.
I have a text input that is a comma separated list of items. These items are in a many-to-many relationship with another model. I want to process that string of items and split them up by the delimited comma so that I have a list of them to save to the database. Is there a way to do this in Django?
Sure it's possible. You can create custom field that will follow needed behavior https://docs.djangoproject.com/en/dev/howto/custom-model-fields/. Also you can overwrite save() methods for you model or form and do all logic where.
Cleaning and Validating Fields that Depend On Each Other contains an example of how to override either the clean_<fieldname> or to_python methods in a modelForm to turn a comma-separated string of email addresses in an array.
I have a page that displays multiple Formsets, each of which has a prefix. The formsets are created using formset_factory the default options, including extra=1. Rows can be added or deleted with JavaScript.
If the user is adding new data, one blank row shows up. Perfect.
If the user has added data but form validation failed, in which case the formset is populated with POST data using MyFormset(data, prefix='o1-formsetname') etc., only the data that they have entered shows up. Again, perfect. (the o1 etc. are dynamically generated, each o corresponds to an "option", and each "option" may have multiple formsets).
However if the user is editing existing data, in which case the view populates the formset using MyFormset(initial=somedata, prefix='o1-formsetname') where somedata is a list of dicts of data that came from a model in the database, an extra blank row is inserted after this data. I don't want a blank row to appear unless the user explicitly adds one using the JavaScript.
Is there any simple way to prevent the formset from showing an extra row if the initial data is set? The reason I'm using initial in the third example is that if I just passed the data in using MyFormset(somedata, prefix='o1-formsetname') I'd have to do an extra step of reformatting all the data into a POSTdata style dict including prefixes for each field, for example o1-formsetname-1-price: x etc., as well as calculating the management form data, which adds a whole load of complication.
One solution could be to intercept the formset before it's sent to the template and manually remove the row, but the extra_forms attribute doesn't seem to be writeable and setting extra to 0 doesn't make any difference. I could also have the JavaScript detect this case and remove the row. However I can't help but think I'm missing something obvious since the behaviour I want is what would seem to be sensible expected behaviour to me.
Thanks.
Use the max_num keyword argument to formset_factory:
MyFormset = formset_factory([...], extra=1, max_num=1)
For more details, check out limiting the maximum number of forms.
One hitch: presumably you want to be able to process more than one blank form. This isn't too hard; just make sure that you don't use the max_num keyword argument in the POST processing side.
I've come up with a solution that works with Django 1.1. I created a subclass of BaseFormSet that overrides the total_form_count method such that, if initial forms exist, the total does not include extra forms. Bit of a hack perhaps, and maybe there's a better solution that I couldn't find, but it works.
class SensibleFormset(BaseFormSet):
def total_form_count(self):
"""Returns the total number of forms in this FormSet."""
if self.data or self.files:
return self.management_form.cleaned_data[TOTAL_FORM_COUNT]
else:
if self.initial_form_count() > 0:
total_forms = self.initial_form_count()
else:
total_forms = self.initial_form_count() + self.extra
if total_forms > self.max_num > 0:
total_forms = self.max_num
return total_forms
I have a form with multiple input fields, but only want to use one input from the form. What is the proper way to check field validity and get cleaned data for the one field?
thanks !
The proper way would probably be to add it to it's own form ;)
But... you can do it like this:
form = SomeForm(request.POST)
field = form.fields['your_field']
data = field.widget.value_from_datadict(form.data, form.files, form.add_prefix('your_field'))
cleaned_data = field.clean(data)