I have a template as below (the second column of the table is wrong, which is my question):
{% for thing in things %}
<tr><td>See the lovely {{ thing.name }}!</td>
<td><form method="POST" action="">
{% csrf %}
<input type="hidden" name="id" value="{{ thing.id }}">
<input type="submit" name="submit" value="Kill me!">
</form></td>
</tr>
{% endfor %}
And I'm a bit stumped how to make an array of forms like this. Of course, the above form works great modulo the csrf, so maybe all I need to do is figure out how to make the csrf work in that context and then I think I can just look at request.POST.get('id') (I think...).
Many thanks for any pointers.
I think the error is csrf. Use
{% csrf_token %}
Related
I have the following menu to change languages in my site:
<div class="btn-group navbar-right language menu">
<button class="btn btn-secondary btn-sm dropdown-toggle language-btn" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{% get_language_info for LANGUAGE_CODE as lang %}
{{ lang.name_local }} ({{ lang.code }})
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu2">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<ul class="language-item">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<input name="language" type="hidden" value="{{ language.code }}" />
<input type="submit" value="{{ language.name_local }} ({{ language.code }})" /> <span>{% if language.code == LANGUAGE_CODE %}✓{% endif %}</span>
</form>
</ul>
{% endfor %}
</div>
</div>
Being shown like
This works the same than the form suggested by Django docs but avoiding the "Go" button to switch languages.
It usually switches languages properly, except in certain cases, as I found out after a user reported the problem.
If the user gets to my site via www.mydomain.com, it will be redirected to www.mydomain.com/en/ (or /es/ or /de/) and as far as I know, changing languages works as expected.
However, if the user gets to my site via www.mydomain.com/es/, then when trying to change the language through the menu, www.mydomain.com/es/ is loaded again. The same behavior occurs with www.mydomain.com/de/.
Strange enough, when entering my site via www.mydomain.com/en/, changing languages works properly. Maybe because it is the default language?
I am able to replicate the issue consistently if entering the site through an incognito window. If I do it through a normal window, it is a similar behavior, but not always consistent. For instance, sometimes entering via www.mydomain.com/en/ will not let me change the language either. This makes me think it might have something to do with cookies. But this is as far as I got.
I checked for similar problems during hours and the only similar thing I found is the Django ticket In some cases i18n set_language does not change url language. Its conclusion is:
...I recreated the issue: we set a language (once) then try to reverse
a URL from the old language when setting the language again.
This obviously fails.
Workarounds:
keeping track of the old language and falling back to try that if the lookup with the current language fails.
Signalling across browser tabs that we already changed the language and adjusting accordingly (???).
Both of these are out of scope for the in-built i18n. (The first would
be possible on a project level — reimplementing e.g. set_language — if
it was deemed cost effective.)
I'm going to close this on that basis.
I am not sure if it is the same case, as I don't understand why it "obviously fails". As I see it, the obvious behavior should be to change the language.
I am surprised that such a basic feature does not work, so probably I am missing something.
Why is it not working in the cases described?
Any help would be appreciated.
Edit 1:
Previously I was using translated URLs instead of the form, as suggested here. However, this was taking 1 second to render due to the translation of the slug. This is why I decided to change
I experienced the same problem. It is still an existing issue, where django seemingly does not translate the HTTP referer header.
See Django source code of set_language
A way to workaround this is to send a hidden input field named next that you set to the same url you are at (request.get_full_path), but replace the current language part with the language you intend to switch to.
Here is a snippet of a language switcher solving this issue:
<li {% if current_language|slice:":2" == 'en' %} class="active"{% endif %}>
<form method="POST" action="{% url 'set_language' %}" autocomplete="off">
{% csrf_token %}
<span class="language-code">en</span>
<input type="submit" name="language" value="en">
<input type="hidden" name="next" value="{{ request.get_full_path|replace_language:"en" }}">
</form>
</li>
<li{% if current_language|slice:":2" == 'da' %} class="active"{% endif %}>
<form method="POST" action="{% url 'set_language' %}" autocomplete="off">
{% csrf_token %}
<span class="language-code">dk</span>
<input type="submit" name="language" value="da">
<input type="hidden" name="next" value="{{ request.get_full_path|replace_language:"da" }}">
</form>
</li>
Then you can implement a custom template tag called replace_language that runs through your configured languages and replaces it with the argument.
Hope this helps :-)
For further reference, I just went back to using translated URLs as suggested here, instead of the form.
I found out that what was making it so slow.
It turned out it was something that could be optimized, so now the translated URLs load very fast as well.
Solved the issue by removing the language code from the "next" input (slice the current language code from the url)
Next input:
<input name="next" type="hidden" value="{{ request.get_full_path|slice:"3:" }}">
Whole dropdown:
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<div class="row g-2">
<div class="col col-sm-12 col-lg-3 col-md-4">
<div class="form-floating">
<input name="next" type="hidden" value="{{ request.get_full_path|slice:"3:" }}">
<select class="form-select" name="language" onchange="this.form.submit()" id="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<label for="language">Language</label>
</div>
</div>
</div>
</form>
I have this form in my template:
<form method="POST" class="form" action="/groups/">
{% csrf_token %}
{% block hidden_debtors %}
{% for name, email in debtor_info.items %}
<input type="hidden" name="hidden-debtor" value="{{email}}">
{% endfor %}
{% endblock %}
<input type="text" name="new-debtor" id="round-input" placeholder="Select Debtor(s)"></input>
<button type="submit" name="add-debtor" class="btn btn-primary">Add Debtor</button>
</form>
As you can see the hidden type inputs all share the name "hidden-debtor" however they each have distinct email values. I was wondering how I would be able to access each one of these distinct values in my views.py through a loop or something
Thanks!
You can get a list of values in your view like this:
request.POST.getlist('hidden-debtor')
Documentation
I currently have a login.html, which has inside it a form for login. All my forms need to look similar, however will have different content. At the moment my code for it looks like this:
<form enctype="multipart/form-data" method="POST" action="">
<fieldset>
<legend>{{ legend }}</legend>
<div style="line-height:18px">{% block top %}{% endblock %}<br></div>
<table class="form">
{% for text,name,inputtype in formcontent %}
<tr>
<td class="right">
<label>{{ text }}:</label><br/>
</td><td style="float:left">
<input name="{{ name }}" type="{{inputtype}}">
</td>
</tr>
{% endfor %}
</table>
<input value="{{ button }}" type="submit">
<div style="line-height:18px">
<div class="err">
{{ err }}
</div>
{{ bottom }}
</div>
</fieldset></form>
I was wondering if there was a better way to do it than to put variables into my urls.py (given that there may be multiple forms on hte page, I don't believe that this would work under all circumstances). A nice solution would be to create a class, but I don't know how to call this class from a page. I know it would involve making a tag, but I don't see how you can provide a 2d array as an argument from a template.
Django Crispy Forms were made for this exact reason. I think they are exactly what you need.
With this code:
urls.py
url(r'^login/',
"django.contrib.auth.views.login"),
and tamplate like that:
Login
which is redirecting to page with this code:
{% if not user.is_authenticated %}
<form method="post" action="">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Zaloguj" />
<input type="hidden" name="next" value="" />
</form>
{% else %}
<h1>Już jestes zalogowany chujku</h1>
{% endif %}
I have context processor 'django.core.context_processors.request' but after login in I am redirected to
accounts/profile/
When I am on login page url is: /accounts/login/?next=/gallery/newest/. More, after login in it loged me in but I am still in /accounts/login/?next=/gallery/newest/1/.
Have I bugs in this code or answer is laying somewhere else?
Just remove <input type="hidden" name="next" value="" /> from your form, it makes django think that next variable is empty.
Finally i found answer.
I think that this code did not use my own login.html template (but if i am wrong, please correct me):
url(r'^login/',
"django.contrib.auth.views.login")
I change it to:
url(r'^login/',
"django.contrib.auth.views.login", {'template_name': 'login.html'}),
Then I change my login.html tempalate code to:
<form method="post" action="">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Zaloguj" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
I don't have the deeper meaning of what happend but this code which I copied here is working. Thanks for all for suggestions. It helps me to find answer and give a little better understanding of some things.
I want to use django.contrib.comments in a blogging application and customize the way the form is displayed. My problem is that I can't get the fields to display although displaying the hidden fields works just fine. I had a look at the docs and compared it with the regular way of displaying forms but honestly I don't know why the following doesn't work out:
{% get_comment_form for comments_object as form %}
<form action="{% comment_form_target %}" method="POST">
[…]
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.fields %}
{{field}}
{% endfor %}
[…]
</form>
The output looks like this:
<form action="/comments/post/" method="POST">
<input type="hidden" name="content_type" value="flatpages.flatpage" id="id_content_type" />
<input type="hidden" name="object_pk" value="1" id="id_object_pk" />
<input type="hidden" name="timestamp" value="1269522506" id="id_timestamp" />
<input type="hidden" name="security_hash" value="ec4…0fd" id="id_security_hash" />
content_type
object_pk
timestamp
security_hash
name
email
url
comment
honeypot
[…]
</form>
</div>
Can you tell me what I'm doing wrong? Thanks in advance
use {% for field in form.visible_fields %}
form.fields is a dictionary where the keys are the names of the fields, and the values are the actual form.Field() objects.
You can also do {% for field in form %} which should include both hidden and visible fields.