I'm not at all sure that my approach to this problem is valid, so I'll appreciate "strategic" recommendations. From the other hand I hope to get some educational value from resolving the problem as it is.
I have a model Record and I want to edit values of several instances of it at once, on the same page.
That is ~how my edit form should looks like
For that I created this template:
**template.html**
#with some omissions
{% for record in records %}
<td>
<input type ="text"
name="position_for_record_{{ record.id}}"
value ="{{ record.position }}"
size ="3">
</td>
<td>
<input type ="text"
name="hours_for_record_{{ record.id }}"
value = "{{ record.hours }}"
size ="3">
</td>
<td>
<input type ="text"
name="tips_for_record_{{ record.id}}"
value = "{{ record.tips }}"
size ="3">
</td>
{%endfor%}
After submitting this form I'll get all those fields in the request.POST, the question is how to extract them? I can, of course, iterate through ALL records
**views.py**
def form_returns_here(request):
all_records=Record.objects.all()
for record in all_records:
if "position_for_record_"+str(record.id) in
request.POST:
But it just doesn't seem right.
Thank you.
Related
I'm trying to add debug information to a frontend; for reasons that don't need to be gone into at the moment I'm storing the pertinent information in a JSONField.
Storing and retrieving the information works correctly, but when I try to render it via J2 to the page it's supposed to be at I'm running into some issues.
Here's the segment in question:
{% for log in connection.debug_logs.all %}
<tr>
<td></td>
<td>{{ log.log_message }}</td>
<td>
{% for key in log.log_data %}
{{ key }}: {{ log.log_data.key }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
What I'm hoping for is for that to produce a series of lines of key: value. What I'm getting instead is:
<td>Login requested by vmx1.internal (11.22.33.44)</td>
<td>
Framed-Route: <br/>
Service-Type: <br/>
Framed-IP-Address: <br/>
Framed-IPv6-Route: <br/>
control:Auth-Type: <br/>
Framed-IPv6-Prefix: <br/>
Delegated-IPv6-Prefix: <br/>
ERX-Egress-Policy-Name: <br/>
ERX-Ingress-Policy-Name: <br/>
ERX-Virtual-Router-Name: <br/>
control:Cleartext-Password: <br/>
</td>
Using {{ log.log_data | pprint }} does yield the keys and values, but renders them as a plaintext JSON string which gets flattened by the html renderer and isn't terribly useful for debugging purposes.
Trying 'log.log_data[key]' instead yields a 'Could not parse the remainder' error.
I've tried the suggestions in this question as well as these and a few others that came up during google searches, but none of them seem to address this issue -- all of them are either working with known keys, working with an actual dict instead of a JSONField, or sometimes both.
I'm probably missing something very simple and straightforward, but I've run out of ways to phrase my question in a search engine. Any tips?
EDIT No, it is not actually a dictionary. I've also tried the solutions in this answer and that leads back to the Could not parse the remainder error.
So the data I'm looking for is absolutely there, I'm just having issues trying to get it to render properly.
Third and final edit: The problem was apparently that Django templates are not quite Jinja2 templates, and rather than {% for key, value in log.log_data.items() %} I needed to use {% for key, value in log.log_data.items %}
Do the conversion from json inside your view to have a greater range of utilities than inside the jinja2 template world.
import json
DEBUG_LOGS_JSON = "[
{"log_data": {"Framed-Route": "route1", "Service-Type": "type1"}, "log_message": "my"},
{"log_data": {"Framed-Route": "route2", "Service-Type": "type2"}, "log_message": "name"},
{"log_data": {"Framed-Route": "route3", "Service-Type": "type3"}, "log_message": "Tarquinius"},
]"
def my_view(request):
my_dict = json.loads(DEBUG_LOGS_JSON) # instead you could also restructure the data passed to the template here.
return render("my_template.html", context=my_dict)
{% for dictionary in my_dict %}
<tr>
<td>{{ dictionary.log_message }}</td>
<td>
{% for key, value in dictionary.log_data.items() %}
{{ key }}: {{ value }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
If this does not represent the structure of your json, then please provide an example. Let me know how it goes.
I am having an issue that I have database updated with the same value as for both id's even though they are different as per my example below:
Lets assume that I entered as input for id 1 -- P_350 =" try_1" id 2 -- P_350 = "try_2" when I click submit then it become both id's the same "try_2" value.
What you suggest to overcome this situation.
Should I need to use variable input name including the id in front of the input name ?
Or any easier method ?
I have the below view.py for my database updates:
ids = request.POST.getlist("id")
qs = fp.objects.filter(id__in=ids)
P_350 = request.POST["P_350"]
P_450 = request.POST["P_450"]
updates = {}
if len(P_350) > 1:
updates['P_350'] = P_350
if len(P_450) > 1:
updates['P_450'] = P_450
if updates:
qs.update(**updates)
Here is my html file input section:
<td style="display:none;">
<input name="id" type="text" value={{ field.id }} >
</td>
<td width="650">
{{ field.FP_Item }}
</td>
{% if field.P_350|length == 0 %}
<td style="display:none;">
{% else %}
<td>
{% endif %}
<input name="P_350" type="text" value={{ field.P_350 }} >
</td>
{% if field.P_450|length == 0 %}
<td style="display:none;">
{% else %}
<td>
{% endif %}
<input name="P_450" type="text" value={{ field.P_450 }} >
</td>
Wrong logic
If you putting different value at same input P_350 this will get the last value you place when it reaches the backend, you probabily should put your first value in P_350 and the second in P_450.
In your example you only manipulate P_350 2 times... so P_450 will never be updated because he dont have a new value.
If you have multiple inputs related with P_350, you should first get all first and then send to backend (AJAX like async) or place multiple P_350 with different names and handle it at backend when save each one
https://medium.com/#taranjeet/adding-forms-dynamically-to-a-django-formset-375f1090c2b0
I have the following code :
{% for assessments in list_assessments%}
<form action="/test/" method="post">{%csrf_token%}
<tr>
<td>{{assessments.assessment_id}}</td>
<td>{{assessments.name}}</td>
<td>{{assessments.assessment_begin_date}}</td>
<td>{{assessments.assessment_end_date}}</td>
<td>{{assessments.is_active}}</td>
<td>{{assessments.is_complete}}</td>
<td>{{assessments.created_at}}</td>
<td>{{assessments.updated_at}}<br></td>
<td><input type="submit" value="Edit Assessment" /></td>
</tr>
{%endfor%}
</form>
All the data here are dynamically coming.
In this following code, i need to assign an name to assessments.name dynamically, something like
<td name="dynamic_name">{{assessment.name}}</td>.
And on clicking the button "Edit Assessment", i want the dynamic_name to be passed and received my the view.
The idea is each assessment has its own set of parameters. I want to display only the parameters related to the name. So if i could pass the value i would be able to do it.
Any help appreciated.
Your ending **</form>** tag should be before for loop.
{% for assessments in list_assessments%}
<form action="/test/" method="post" name="form-{{ assessments.counter }}">{%csrf_token%}
<tr>
<td>{{assessments.assessment_id}}</td>
<td>{{assessments.name}}</td>
<td>{{assessments.assessment_begin_date}}</td>
<td>{{assessments.assessment_end_date}}</td>
<td>{{assessments.is_active}}</td>
<td>{{assessments.is_complete}}</td>
<td>{{assessments.created_at}}</td>
<td>{{assessments.updated_at}}<br></td>
<td><input type="submit" value="Edit Assessment" /></td>
</tr>
</form>
{%endfor%}
Now, You can get specific block values by form name ( see above code ) in javascript as well as in python.
In Javascript,
form = document.getElementByTagName("form")
elems = form.children("td")
elems will give you all td elements.
So I'm using jQuery UI to skin the radio buttons but I can't get Django to render my form the way it has to be done.
I need to have this structure:
<table>
<tr>
<td><label for="notify_new_friends">Notify when new friends join</label></td>
<td class="radio">
<input type="radio" name="notify_new_friends" id="notify_new_friends_immediately" value="1" checked="checked"/><label for="notify_new_friends_immediately">Immediately</label>
<input type="radio" name="notify_new_friends" id="notify_new_friends_never" value="0"/><label for="notify_new_friends_never">Never</label>
</td>
</tr>
</table>
So to summarize that I need the radio buttons within a class (radio) where they have an input and a label for.
When I render the form in my template with {{ profile_form.notify_new_friends }} I get the following:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
Which is exactly what I want except for the list-part. So I tried looping over it which gives me the labels formatted differently:
{% for item in profile_form.notify_new_friends %}
{{ item }}
{% endfor %}
which gives me:
<label><input type="radio" name="notify_new_friends" value="0" /> Immediately</label>
<label><input type="radio" name="notify_new_friends" value="1" /> Never</label>
So the problem here is that it stops using label for and starts using just label to wrapp it all with.
I also tried doing something like this, but then the label and label_tag don't render anything.
{{ profile_form.notify_new_friends.0 }}
{{ profile_form.notify_new_friends.0.label_tag }}
{{ profile_form.notify_new_friends.0.label }}
So does anyone know how I can render this properly!?
FYI, this is my forms.py:
self.fields['notify_new_friends'] = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect, choices=NOTIFICATION_CHOICES)
In my code I discovered that changing the widget from
forms.RadioSelect
to
forms.RadioSelect(attrs={'id': 'value'})
magically causes the resulting tag value to include the id attribute with the index of the item appended. If you use
{% for radio in form.foo %}
<li>
{{ radio }}
</li>
{% endfor %}
in the form you get a label wrapped around an input. If you want the more conventional input followed by label, you need to do this:
{% for radio in form.value %}
<li>
{{ radio.tag }}
<label for="value_{{ forloop.counter0 }}">{{ radio.choice_label }}</label>
</li>
{% endfor %}
Unfortunately this is more complicated than it should be, it seems you need to override at least 2 classes: RadioRenderer and RadioInput. The following should help you get started but you might need to tweak it a little.
First create a custom radio button input widget. The only purpose of us overriding the render method is to get rid of annoying structure Django enforces (<label><input /></label>) where instead we want ours (<label /><input />):
class CustomRadioInput(RadioInput):
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
value = value or self.value
attrs = attrs or self.attrs
if 'id' in self.attrs:
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
else:
label_for = ''
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'%s<label%s>%s</label>' % (self.tag(), label_for, choice_label))
Now we need to override RadioRenderer in order to:
Force it to use our custom radio input widget
Remove <li> wraping every single input field and <ul> wrapping all input fields:
Something along these lines should do:
class RadioCustomRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx]
return CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
def render(self):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
Finally instruct Django to use custom renderer
notify_new_friends = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect(renderer=RadioCustomRenderer), choices=NOTIFICATION_CHOICES)
Please bear in mind: This now outputs radio buttons together with encompassing <td> hence you need to build a table around it in your template, something along these lines:
<table>
<tr>
<td><label for="{{field.auto_id}}">{{field.label}}</label></td>
<td>{{ field.errors }} {{field}}</td>
</tr>
</table>
If anyone stumble upon this problem and just want to render the radio button without ul: they should follow this link.
https://docs.djangoproject.com/en/3.1/ref/forms/widgets/#selector-widgets
Example below.
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
Since it doesn't seem to be a good way to do this I chose to rearrange the generated code using jQuery.
// First remove the ul and li tags
$('.radio ul').contents().unwrap();
$('.radio li').contents().unwrap();
// Then move the input to outside of the label
$('.radio > label > input').each(function() {
$(this).parent().before(this);
});
// Then apply the jQuery UI buttonset
$( ".radio" ).buttonset();
This made it go from:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
to:
<input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /><label for="id_notify_new_friends_0"> Immediately</label></li>
<input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /><label for="id_notify_new_friends_1"> Never</label></li>
and my jQuery UI styling works fine.
Try like this , I got it..
from django.forms.widgets import RadioFieldRenderer
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
class RadioCustomRenderer( RadioFieldRenderer ):
def render( self ):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
in form
widgets = {
'validity': forms.RadioSelect(renderer=RadioCustomRenderer),
}
Using django, I have a form in which a user enters his 'position'. The user may add multiple positions. The user may also delete positions. There are two things worth noting with this:
1) in the form, there are two buttons, 'Add' and 'Delete'.
2) I am using a for loop in the template to populate the list of positions and delete buttons.
This is what I currently have:
# in template
<tr>
<td>Position</td>
<td>{{ form.position }}
<input type="submit" value="Add" , name='action'/>
</td>
</tr>
<tr>
<td> </td>
<td>
{% for position in positions %}
{{ position}}
<input type="submit" value="Delete {{position }}", name='action'/>
{% endfor %}
</td>
</tr>
# in views.py
...
if action == 'Add':
positions.append(request.POST['position'])
return render_to_response(...)
if 'Delete' in action:
positions.remove(request.POST['action'][7:])
return render_to_response('...)
This seems like a very inelegant way to do the "Deletion" part.
Is there a better way to get the value of the position, without having to cram in additional information in the 'Delete' submit button, and then slicing it off to get its value?
I see three options here:
Use checkbox field for each position and one "Delete" button. In that case a user can choose multiple positions to be deleted and you can get their IDs from request easily.
Use a hidden field position and a little bit of Javascript to fill it. If you use jquery it could be:
<input type="hidden" name="position" value="" />
{% for position in positions %}
<input type="submit" value="Delete" name="action" data-position="{{ position }}" />;
{% endfor %}
<script type="text/javascript">
var $position_input = $("input[name='position']");
$("input[name='action'][value='Delete'].click(function(e) {
var $this = $(this);
var position = $this.data("position");
$position_input.val(position);
});
</script>
Insert position ID into name attribute, like this:
<input type="submit" value="Delete" name="delete-position.{{ position }} />
In view function you'll have to look through all data in request.POST and find all items which start with delete-position and then use slicing.