Django Forms - Fields containing arrays - django

I have a couple fields within a form that I'd like to be an array of values. How can I achieve something like
categories['sale']['price']
categories['sale']['currency']
categories['sale']['frequency']
and
image[0]
image[1]
image[2]
These fields containing array would be part of a form containing regular fields. If possible, how does one deal with validation?
Bonus question: If I had dynamic fields by themselves, I'd use a Formset?

Related

How to apply nulls_last ordering to an extra select field in Django?

I'm trying to apply order_by() with nulls_last=True to a queryset:
MyModel.obects.all().order_by(*[models.F('field').desc(nulls_last=True)])
This works fine for regular fields, but it throws an error when I try to order by an extra field in the same manner:
queryset = MyModel.obects.extra(**{'select': {'extra_field': 'custom_sql'}}).all()
queryset = queryset.order_by(*[models.F('extra_field').desc(nulls_last=True)])
The problem is it is unable to find extra_field column when using models.F(). If I simply use order_by('extra_field') as a string it works because Django is doing some extra preprocessing and handles extra fields differently. After digging through the sources I was able to make it work as:
queryset = MyModel.obects.extra(**{'select': {'extra_field': 'custom_sql'}}).all()
queryset = queryset.order_by(*[models.expressions.Ref('extra_field', models.expressions.RawSQL('custom_sql', [])).desc(nulls_last=True)])
The downside of this solution is that I have to treat regular fields and extra fields differently, and I have to repeat the custom_query inside order_by.
I am trying to build a universal function that would simply take a list of fields as stings (how Django would take) and wrap them with nulls_last.
The question is: Given only a field name as a string and a queryset, is there a universal way to apply nulls_last to it without specifying if this is a native field or an extra, and without passing a custom query for an extra field? I am trying to make the function signature to be something like:
def apply_order_by_nulls_last(queryset, field:str):
#detect field type and convert it to OrderBy expression with nulls_last
...
return queryset.order_by(...)

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

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 Formset Override As Table To Show As Grid

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.

How can you process an input element from a form before saving it to a model with django?

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.