How to handle form submission with unknown number of elements? - flask

What is the best way to handle a page with multiple forms and an unknown number of elements in one of the forms?
Lets suppose I have 3 models, Book, Recipe and Ingredient and these need to be displayed on the same web page. Each Book can also hold any number of Recipes and each Recipe can hold any number of Ingredients. Each of these models will also have a form that inherits from ModelForm.
Once the form is displayed to the user, she is free to dynamically add as many Recipes or Ingredients a she needs. This is to be done via JS with no Ajax.
What is the best way to handle this when validating forms? Validating the form for Book is easy but how do I handle the unknown number of Recipes and Ingredients?

The solution is to use prefixes and numbers. So a form will have the prefix 'recipe_1_' and each ingredient in the recipe will have the prefix 'ingredient_1_'.
For the second recipe and second set of ingredients just up the integer.
When submitting the form it's necessary to get the values from request.form and use them to create a form one by one, usually by looping through the content of request.form and using the prefix to decide which Form to use.

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

Database mutable field

I have to store data, a part of them is predefined but the user can chose to custom it.
What is the best way to store these data in the database?
2 fields, 1 will be an integer field for predefined option and the second will be a string for the custom user input
1 string field, which will contains a json like {predefined: 2, custom: ''}
1 string field which will contains custom string or predefined option id (converted during the request process)
1 string field which will contains the fulltext option even if it is a predefined (some of these predefined options can be long text)
I tried the 1) but double the number of fields for each "custom ready" data doesn't seem to be perfect...
Any idea ?
Considering you might need the following (it's not very clear from your question):
a form where there is an input field for the customizable part of the string
an easy way to refer to the complete string
a way to administer/manage/validate the non-customizable string
=> use two fields:
class TheModel(Model):
# if you have a certain constant number of choices, use ChoiceField
# otherwise use a ForeingKey and create a different model for those
non_customizable_prefix = ChoiceField(null=False, blank=False, ...)
# unique? validators? max/min length? null/blank?
customizable_part = CharField(...)
#property
def complete_string(self):
return '{}{}'.format(self. non_customizable_prefix, self. customizable_part)
This model will provide you with two separate input fields in Django forms or the Django admin, offering easy ways to make the non_customizable_prefix read only or only modifiable with certain privileges.

django form with multiple choice field with potentially infinite choices

I have a model with a many-to-many field that will expand as the user adds more entries for the model. In the form template if I use the conventional {{ form.field }} I get a multiple choice select as is expected, but the problem that will quickly become apparent is when there are 10, 100, 1000 or more choices. What I'd like to provide in the form is a search field where the user can search through all available entries and via AJAX return entries matching their search criteria where they can then select the individual entry choices to be saved in the database.
I'm assuming I will have to manually render the multiple choice form field, but after hours of research I cannot find an example of this anywhere online. Is there an example that exists and I just haven't been able to find? How is one supposed to manually create a form with a multiple choice field in Django? Or am I going about this all wrong?

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.

Django Models - Prepare the data for the database

I have a form that askes for a phone number. I need to make sure that only digits [0-9] get saved in the database.
In the Django documentation it says:
What happens when you save?
3) Prepare the data for the database. Each field is asked to provide its current value in a data type that can be written to the database.
How does this happen? Or more specifically, how can I make sure this is cleaned? I know that I can just override the models save method, but it seems like there is a better way and I'm just not sure how to do it.
I guess I could write a custom field for it, but that seems like overkill here.
Also, I realize that I can put the validation on the form, but it really feels like stripping out the characters belongs on the model.
Your question specifically about point 3 is a little different from "cleaning" in the way django uses the term.
3) Prepare the data for the database. Each field is asked to provide its current value in a data type that can be written to the database.
Point 3 is about converting the python object values to one suitable for a database. Specifically, this is done in Field.get_prep_value and Field.get_db_prep_value
https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#django.db.models.Field.get_prep_value
It's the opposite of to_python which takes a DB value and converts it to a python object.
As for ensuring only digits 0-9 get stored, that would be done in a Fields clean method (subclass IntegerField), form clean method, form clean_FIELDNAME method, or model clean.
You can add a custom Form Cleaning method to your objects model - take a look at this article https://docs.djangoproject.com/en/dev/ref/forms/validation/#form-field-default-cleaning
Look at "Cleaning a specific field attribute"
use django model form + custom form field cleaning
Below is a quick example of what you might be looking for, where MyModel is the model containing the phone number field, which I named it tel here.
import re
class MyForm(ModelForm):
class Meta:
model = MyModel
def clean_tel(self):
tel = self.cleaned_data.get('tel', '') # this is from user input
# use regular expression to check if tel contains only digits; you might wanna enhance the regular expression to restrict the tel number to have certain number of digits.
result = re.match(r'\d+', tel)
if result:
return tel # tel is clean so return it
else:
raise ValidationError("Phone number contains invalid character.")