form index in inlineformset - python

I have a formset created using inlineformset_factory. It doesn't matter what it looks like to answer this question. In the template I am looping through it with for form in forms.formset:
I want to be able to display the form index of the form in my template. By form index, I mean the number associated with that form in all of the formfields. Is there a variable that does this? I tried form.index and form.form_id and form.id is a field.

No, objects in a collection don't generally have access to their index or key.
However if you're outputting the formset in a template, you're presumably looping through the forms. So you can use {% forloop.counter %} to get the index of the iteration.

Although it is not pretty, based on the formset source and the comment by #yuji-tomita-tomita above, you could do something like this in your template:
{{ form.prefix|cut:formset.prefix|cut:'-' }}
This just takes the form prefix string, which includes the form index, then removes the irrelevant parts. In the view you could simply do e.g. form.prefix.split('-')[1].

Related

Save output objects from django-filter to a CSV

I am have have a simple model in Django and I am using django-filters in one of my pages to have the simple functionality of having a form to search throug the models & then output a list of models and attributes.
What I need help with is how to get the set (of models data) that is selected in the django-filters form to be saved as CSV when I click 'Submit' on the form. I would also like to add a form box for how the file can be named.
models.py
class Person(..)
name = models.CharField(..)
type = models.CharField(choices=TYPECHOICES)
...
filters.py
class PersonFilter(django_filters.FilterSet):
type = django_filters.MultipleChoiceFilter(name='type', choices=TYPECHOICES)
views.py:
def query(request):
f = PersonFilter=request.GET, queryset=Person.objects.all())
return render_to_response('query.html', {'filter': f})
finally in my template I have:
{{ filter.form.as_p}}
and
{% for obj in filter %}
{% endfor %}
to put up the form & results.
Thanks
Edit:
When I do this in views, why do I iterate over ALL my objects instead of just the set specified by the form:
for obj in f:
print obj.name
This is really strange. Since in the template when I iterate over filter I only see the filtered set as per the form.
See this post: Is it possible to access static files within views.py? on how to access static files in a view. And then it would be best IMHO if the Person object would have a method like to_csv or something.
So you could just call it for every object and simply write it to the csv file.
But I'm not sure if this is really the way you want to go.
You should think about creating the graph directly from the list of objects returned by the query, since you already have your query saved.

Django search - populate template with search results

I'm completely newbie in Django-phython.
I'm trying to populate the results of a search inside an html form input tag. with the register that the search returns.
I have a view that renders an html code, passing a dictionary. And I would like to display that dictionary, containing the search results, inside the html form fields that corresponds to that dictionary.
The question is if it's possible to do such a thing.
You will get all the information at django template documentation
Specifically, if you want to iterate through the dictionary in your template, you need the for loop.
From the documentation:
This can also be useful if you need to access the items in a
dictionary. For example, if your context contained a dictionary data,
the following would display the keys and values of the dictionary:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
You'll have to use ajax and a typehead pulgin for that.

Paginated based on the alphabet (A-Z)

I have a simple contacts application where I want to paginate the contact list based on first name alphabet.
Here is my views.py
def contacts(request):
contact_list = Contact.objects.filter(user=request.user).order_by('first_name')
return render(request, 'contact/contact.html', {'contact_list': contact_list})
Here is my template
<ul>
{% for contact in contact_list %}
<li>{{ contact.first_name }}</li>
{% endfor %}
</ul>
Is there a default way in Django that does this? There is Django pagination but I think that only splits data across pages. What would be the easiest way to do so?
It seems a letter-wise paginator does not exist by default. Pages like https://djangosnippets.org/snippets/1364/ <<< this one show hand-made implementations.
However, it's not so hard to implement: you can base yourself on startswith keyword and:
pages = [myQuerySet.filter(myfield__istartswith=i) for i in "ABC...XYZ"] #full alphabet here
(let myQuerySet be, actually, contact_list; let myfield be, actually, first_name).
I've done this once, by adding a letter field to my model and "paginating" manually. This raised a lot of interesting situation with foreign alphabets. Found this useful: https://pypi.python.org/pypi/Unidecode
Didn't find any "smarter" way to go about it. But I'd be interested in hearing about more "plug-n-play" solution...

How to iterate a dynamic variable in a Django template

Some slightly related questions have been asked about this, but the answers did not really help me. When I tried to implement a potential good hint suggested elsewhere (custom templates), I did not get the desired results.
In my template, I am iterating over a set of keys from a dictionary. The dictionary itself originates from submitting a Django formset.
XML Template snippet: (I am rendering to an XML file)
{% for x in range %}
<file type="{{ form-'x'-type }}" viewpath="{{ form-'x'-file }}"/>
{% endfor %}
The above obviously does not work. The iteration works. The rangevariable is a python argument corresponding to range(int(request.POST['form-TOTAL_FORM'])) passed from the view to the XML template.
At every iteration in the template, I need {{ form-0-type }}, {{ form-1-type}}, {{ form-2-type }}, etc.
How do I do that? If I really need to use a custom filter for this, how do I do this?
I hope this question (and the answers) will help many having the same problem.
Thanks.
Edit:(Dictionary posted)
<QueryDict:
{
u'form-MAX_NUM_FORMS': [u'1000'],
u'form-INITIAL_FORMS': [u'0'],
u'form-TOTAL_FORMS': [u'2'],
u'form-0-type': [u'1'],
u'form-1-type': [u'2'],
u'csrfmiddlewaretoken': [u'LpkjdDcqRCL4VPM0SAuU7efgZjgeubTN']
}>
Additional note:
In a second view, I lookup the values for the foreign keys and put the values in another dictionary, which I send to my XML template.
Snippet of the code that does this:
detailed_request = {}
for x in range(0, int(request.POST['form-TOTAL_FORMS'])):
detailed_request['form-'+str(x)+'-type'] = Upload_Type.objects.get(pk=request.POST['form-'+ str(x)+'-type'])
detailed_request['form-'+str(x)+'-file'] = request.FILES['form-'+str(x)+'-file']
The above is a working snippet. When I trace detailed_request, I have all the information I need:
{
'form-1-type': <Upload_Type: malib>,
'form-0-type': <Upload_Type: axf_file>
}
Just in case somebody has the same problem, I actually changed the way I do things.
I do not iterate the formset in the template. Instead, I implemented the solution from Paolo Bergantino here:
Dynamically adding a form to a Django formset with Ajax
Then in my views, I simply get every data I need from request.FILES
I hope that helps anybody who started with the same wrong approach.
You can access the for loop helper variables through the following variables
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
More at: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
So you'd do...
{{ form }}-{{ forloop.counter }}-{{ type }}

How to manage multiple HTML elements with same name using WTForms, Jinja & Python

I had defined an HTML template with Jinja, where I had defined three (3) textfields with same name. Then in the backend using the get_all method I collected all the values.
Then in order to add form validation, etc, I added WTForms library. Then I defined a Form as:
class RoleForm(BaseForm):
name = fields.TextField(_('Name'))
And in the HTML page I rendered this element three (3) times.
Now, when I submit the form and the validation fails, I re-render the template using the form as input. But instead each element has the value I had entered, all textfields have the value of the 1st textfield.
Moreover if validation is ok, I use form.name.data, which does not give me all the data from the three textfields, but only the first one.
Do you know how I can handle such situation?
Thanks in advance!
You are looking for the wtforms.fields.FieldList field enclosure:
class RoleForm(BaseForm):
name = fields.FieldList(fields.TextField(_('Name')), min_entries=3)
What you need to do is to create HTML inputelements like this for instance:
<input name="row-{{ loop.index0 }}" type="checkbox">
It will render inputs like the ones below:
<input name="row-0" type="checkbox">
<input name="row-1" type="checkbox">
Inside a loop or something like that. Then you'll be able to retrieve the Form contents:
class ListForm(Form):
row = FieldList(fields.TextField('Row'))

Categories