Django form with multiple - django

I have a ModelForm class which can be used one or more times on a single page. E.g.:
class ProductForm(forms.ModelForm):
class Meta:
model = Product
exclude = ('prod_seq_number')
now when I want to use the form more than once on a single page, e.g.:
prodforms = []
for i in (range(nrofproducts)):
prodforms.append(ProductForm())
I can now pass the list prodforms to the template and the user can enter multiple products on the page. The variable nrofproducts is: 1, 2, 4, 8 or 16
This won't work because I will get form elements with identical names. I need to be able to differentiate between the various form elements. So I need a way to modify the form attributes
for instance by appending the index 'i' from the loop in the view code the 'name' attribute of the form. Any help would be appreciated.
The reason for making a form layout like this is that a user can choose to see 1, 2, 4, 8 or 16 products on a single page and I want a entry form to resemble the layout which he will see when finished.

You really don't want to do this. Simpler way of doing it would be to use Django Formset

Related

list all Input fields generated dynamically on django

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

Creating models and template names based on variables

I'd like to start by saying that I know this is possibly both unconventional and bad practice, but here goes.
I've got a UserProfile model. In the form for this model, a user gets to select what template they want to use on their blog. In doing this, they'll select either 1, 2, or 3 from a drop down menu. This number will be saved to field 'template' within the UserProfile model.
Upon hitting the submit button, I'd like the following to happen:
1) I'd like for a TemplateProfilex to be created where x is equal to the template number they selected.
To give you an idea of what I'd like to happen (even though I know that this won't work), here is the code.
x = user.userprofile.template
Model = TemplateProfile + 'x'
blog = Model.objects.create(user=request.user)
The goal here would be to create TemplateProfile3 for this user if the user selected 3 on the form.
2) Next, once the model is created and the user is redirected to the next view, I'd like to send this user to a template as determined by the value in user.userprofile.template
return render(request, 'accounts/templateX.html', args) where X is the value in user.userprofile.template
If I could do something as described above, it would dramatically simplify my code. The alternative is to do a bunch of if statements in my views. Example:
if user.userprofile.template == 1:
template_profile= TemplateProfile1.objects.create(user=request.user)
return render(request, 'accounts/template1.html', args)
Thanks a ton guys.

Django Form Field for a list of strings

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.

Searching via multiple form fields?

I'm displaying a page with a 4 textboxes, each storing the user entered value into a separate variable.
My Database has 4 columns, each corresponding to one text box's variable.
I want to do this:
The user can enter values in 1,2,3 or all 4 of the textboxes, and I want to trim the search results according to each value that they've entered. Each textbox is optional.
How do I do this? I'm new at Django, and I only know how to search using one search term.
I think you need Q objects. See: https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
From the docs:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
Translates to:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
You can populate the Q query from your cleaned form - you might even want to override clean() and return the queryset that way, so that you could just access the query set from the validated form.

Django formset - show extra fields only when no initial data set?

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