Customizing RadioSelect - django

Hello I have a form with ChoiceField whose widget is set to RadioSelect
Now to override default html output one needs to subclass RadioFieldRenderer like this:
class SimpleRadioFieldRenderer(forms.widgets.RadioFieldRenderer):
def render(self):
"""Outputs widget without <ul> or <li> tags."""
return mark_safe(u'\n'.join([u'%s'
% force_unicode(w.tag()) for w in self]))
All is good now except I'd like to be able to render 1 radio button at a time from template.
Something like this:
{{ form.myfield.0 }}}
Or perhaps hanging it onto widget itself:
{{ form.myfield.field.widget.0 }}
What bugs me is that RadioFieldRenderer already implements __get_item__ to get just one RadioInput. The problem is that the renderer does not contain data, neither does the widget. And I'd really hate to mess with Field and BoundField.
I need this to inject html before/after each radiobutton and I'd like it to be done in the template. From the code it would be easy.
Any ideas are welcome.

I think this post in django-users may provide a way to do it (with an accessor function in the form class):
http://groups.google.com/group/django-users/msg/b60410692c7c60e2

Related

How can one create a custom "as_table()" method for forms?

I have a relatively complicated form that's used in multiple places on my website (in fact, it's a form from which many other form classes inherit). In the templates, the inherited part of this form is always formatted identically—but that formatting is somehwat involved; each field is rendered and positioned manually in the template.
This means that every template which displays this form has a lot of identical HTML markup that renders the form appropriately.
I would like to create a custom output that can be called, similar to the as_table() methods. I'm aware that one can override the normal_row, error_row, etc. attributes—but the formatting of this form goes beyond that (for example, three of the form's five fields should be printed side-by-side, with a combined title). All of the tutorials/answered-questions I've seen either refer to overriding the above-mentioned attributes, or give instructions on how to manually render forms.
Originally, I was thinking something like this:
Class StrangeForm(form.Forms):
....
def as_table_custom():
html_string = "\
<tr><td>Title 1:</td><td>self.fields['field1']</td><tr>\
<tr><td>Title 2:</td><td>self.fields['field2']</td><tr>\
<tr><td>Titles 3, 4, 5:</td><td>self.fields['field3']\
</td><td>self.fields['field4']</td><td>self.fields['field5']</td></tr>\
"
return html_string
But, after reading through the _html_output() and as_table() methods of Django's forms.py file, it doesn't look like it'll be that easy. If I write this from scratch, have to somehow account for errors, help text, etc. I think.
Is there an easy way to override something such that the form's HTML output can be defined like above? Or do I have to re-write things from scratch. If the latter, how can I account for all of the things I need to account for?
I wouldn't take this approach. You're better off creating the form in an HTML template that you include in the various templates where you have a form you want to display that way.
So create a my_strange_form.html template where you assume a 'form' object is passed in the context with the right number of fields. In that template just create the HTML, using things like {{ field.label_tag }} and {{ field }}. You can loop through the fields with a {% for field in form %} and check the counter of your loop with {{ forloop.counter }}. I foresee a lot of {% if forloop.counter... %} statements to generate the combined row, and it will look ugly, but you'll only have to look at it once :-)
Then in your main templates {% include 'my_strange_form.html' with form=form %}.

Hiding ModelMultipleChoiceField on template for custom input

I want the user to select a number of elements belonging to a certain model. I don't want to use the default 'ctrl+click' input of django forms, but create a table of checkboxes myself.
For that reason I hide the ModelMultipleChoiceField by defining the widget:
field = forms.ModelMultipleChoiceField(..., widget=forms.MultipleHiddenInput())
Then I add the form element into the template as follows:
<form method="POST" class="locklist-form" id="locklist-form">{% csrf_token %}
{{ form.field }}
</form>
At this step, I expect the select-option elements to be added to HTML page (as hidden), so that I can reach to element options and modify them with javascript. However, it doesn't add anything to the HTML page.
I use this approach with other type of form fieds. For a TextField HTML page have a hidden element as shown:
Why doesn't it work with ModelMultipleChoiceField? How can I modify the choices of this field with Javascript?
Edit:
MultipleHiddenInput renders only if with initial data is a similar question. But applying it doesn't lead to the expected solution. In this question, it is expected to render the following as hidden:
But following the MultipleHiddenInput renders only if with initial data, when I modify the form constructor as:
form = MyForm(initial={'field':MyModel.objects.all()})
Rendered element is as follows:
It maybe useful, but not exactly the expected one. I need to mark a few options as selected, among a list of objects.
I have done it using Javascript, instead of depending on Django's capabilities. I add the form with ModelMultipleChoiceField directly to the template (not hidden). Then I run a Javascript script, when the page is loaded:
var field = document.getElementById('id_field');
selecter.setAttribute('class', 'hidden');
CSS definition of hidden class is as follows:
.hidden{
display: none;
}
This gets me to the desired situation. ModelMultipleChoiceField is rendered hidden as follows:
At this point, I can modify certain items through Javascript:
document.getElementById('id_field').options[index].selected = boolValue;

Django: creating graphs in admin Inlines

I'm working in the admin interface, and I'm trying to create a InlineModelAdmin subclass that given a model will just give me certain values from related values (say, date and value fields) and use them in a subclassed template to build a graph.
Problem is: I don't know what to subclass in the inline!. The inline_admin_formset seems to have the form already cooked and I can't access the date. get_form I can't get to send the data I want to the template. I tried change_view to put the data as extra_context, but it's only called for the parent class. And so on.
Can anyone orient me as to where would be the best place to work?.
I know this would be a lot easier in a custom view, but the high command is adamant that this has to be done in the admin interface.
Thank you!
Looks like I managed to access the raw data from the inline objects using the following code in the template:
<script>
var data = google.visualization.arrayToDataTable([
["Date", "Value"],
{% for form in inline_admin_formset %}
["{{form.original.date}}", {{form.original.value}}],
{% endfor %}
]);
</script>
So it looks like now I only need to parameterize what fields the graph is going to plot from the inline, or from the object (date and value in this case). Perhaps add a graph_fields() method to both.
In any case, thanks to whoever gave this a thought.

Django forms: How to add class to field_content?

When I render a form, it generates something like this for each Field:
<div class="field_content">
<label>...</label>
<div class="field">...</class>
</div>
I would like to be able to uniquely identify each Field in my stylesheet. Is there a way to add another class to the outer div (in addition to field_content), or an outer div (parent to field_content)?
If it's enough to set the class of the field you can specify it as an attribute of your widget:
name = forms.CharField(widget=forms.TextInput(attrs={'class':'special'}))
If you need more control it's probably best to render your form manually or if you don't mind relying on an external app there are even more flexible solutions:
In django-floppyforms you could use form layouts and in django-crispy-forms you could use layout objects and to achieve what you want.

django - post form on select

I made a simple django form, with a list of choices (in radio buttons):
class MyForm(forms.Form):
choices=forms.ChoiceField( widget=forms.RadioSelect(), choices=[(k,k) for k in ['one','two','three']],label="choose one")
I would like the form to submit automatically when a user selects one of the options. In straightforward HTML I would've done it as
<select name='myselect' onChange="FORM_NAME.submit();">
....
</select>
But I do not know how to integrate this into the form class without writing a template. Specifically, I would need to know FORM_NAME so I can call FORM_NAME.submit() in the above snippet.
Can it be done without using a template?
I think you do not need to know the form name. This should work as well:
<select name='myselect' onChange="this.form.submit();">
A quick solution to integrate this into your form would involve adding a attribute to your widget.
widget=forms.RadioSelect(attrs={'onchange': 'this.form.submit();'})
Now one could argue if this isn't better separated from your form definition (separating definition, style and behaviour), but that should do it.