I am using Django and I want to change the site language when users click a button for example. I can get the current language code using {% get_current_language as LANGUAGE_CODE %} but how can I change it from a template?
<form name="setLangEnglish" action="/i18n/setlang/" method="POST">
{% csrf_token %}
<input name="next" type="hidden" value="{{request.path}}"/>
<input type="hidden" name="language" value="en"/>
</form>
What this form actually does is changing your current language to "en" which is english.Since this form input type is hidden,you wouldn't see form in html. What you have to do is find out how you would like to change language(with clicking text or clicking country flag.).Here is an example for changing langugage with clicking text.
<a onclick="document.setLangEnglish.submit();return false;">ENG</a>
This code submit the form above whenever user clicks "ENG".In order to be this working, make sure that url(r'^i18n/',include('django.conf.urls.i18n')), is in the urls.py.
Related
I'm building a simple Django app that lets users track stuff for specific days:
It records entries with a name and a date using the upper form.
<form action="" method="post" style="margin-bottom: 1cm;">
{% csrf_token %}
<div class="form-group">
{{ form.entry_name.label_tag }}
<div class="input-group">
<input type="text" class="form-control" id="{{ form.entry_name.id_for_label }}" name="{{ form.entry_name.html_name }}" aria-label="new entry field">
{{ form.entry_date }}
<div class="input-group-append">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
<small id="{{ form.entry_name.id_for_label }}Help" class="form-text text-muted">This can be anything you want to track: An activity, food, how you slept, stress level, etc.</small>
</div>
</form>
Below the form, there are quick add buttons that let users quickly add a new entry with a specific name. In addition, I'd like to use the date selected in the form above. I.e., if a user sets a date in the upper form but then clicks one of the suggested buttons, it should still use the selected date for adding the new entry.
This is what the code for the suggested buttons currently looks like:
{% if entry_counts and entry_dict|length > 0 %}
<div class="card" style="margin-bottom: 1cm;">
<div class="card-body">
<div class="card-title">Suggested entries</div>
{% for name, count in entry_counts.items %}
<form method="post" action="{% url 'app:add_entry_with_date' name form.entry_date.value %}" style="display: inline-block;">
{% csrf_token %}
<button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;">{{ name }}</button>
</form>
{% endfor %}
</div>
</div>
{% endif %}
I'm trying to access the selected date and pass it to the corresponding view: action="{% url 'app:add_entry_with_date' name form.entry_date.value %}", but it still adds the entry at the default date (today) not on the selected date.
My guess, is that the problem is with <button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;">{{ name }}</button>. Does this just pass name but not the date when submitting?
Here are the relevant URL patterns:
class DateConverter:
regex = '\d{4}-\d{2}-\d{2}'
def to_python(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d')
def to_url(self, value):
return value
register_converter(DateConverter, 'yyyymmdd')
urlpatterns = [
path('', views.index, name='index'),
path('add/<entry_name>/', views.add_entry, name='add'),
path('add/<entry_name>/<yyyymmdd:entry_date>/', views.add_entry, name='add_entry_with_date'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
So whenever adding a new entry (with or without specific date), my add_entry view is called:
#login_required
def add_entry(request, entry_name, entry_date=datetime.date.today()):
# only works for post
# if request.method == 'POST':
entry_name = entry_name.strip().lower()
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index'))
You're trying to pass the date value as part of the URL,
{% url 'app:add_entry_with_date' name form.entry_date.value %}
however, form.entry_date.value won't have a defined value unless your form is bound before it's passed to the template for rendering. As a result, probably, your add_entry view is being called via the URL pattern add, not add_entry_with_date.
Another challenge with your current code is that you want to have the same date-type input element ({{ form.entry_date }}) serve as the source for different, separate HTML forms (you have the first form for adding entries, and then you have one form for each suggested entry). Changing the value of that input when the page is already rendered in the browser won't update the action URLs for the suggested entry forms—unless you use JavaScript.
I think the quickest way to make your existing code work is to write some JavaScript to manipulate the action attribute for the suggested-entry forms whenever the date input value changes.
Manipulating action attributes looks strange though, and also I believe your view, which should work only for POST requests, should use only POST data and not rely on URL parameters. Therefore I recommend that you use hidden inputs, e.g.
<input type="hidden" name="variable-name" value="temporary-date-value-here">
and then have the JavaScript manipulate these input elements' values instead of the form action attribute. Of course you have to update the view too.
Update: sample JS for synchronizing inputs across forms
HTML:
<html>
<head>
<title>Sample synchronization of inputs across forms</title>
</head>
<body>
<h1>Sample synchronization of inputs across forms</h1>
<h2>Form 1</h2>
<form>
<input class="synchronized-inputs" type="date" name="input_date">
</form>
<h2>Form 2</h2>
<form>
<input class="synchronized-inputs" type="date" name="input_date">
</form>
<script src="sync-inputs-across-forms.js" type="text/javascript"></script>
</body>
</html>
JavaScript (sync-inputs-across-forms.js):
var syncedInputs = document.getElementsByClassName('synchronized-inputs');
Array.from(syncedInputs).forEach((source) => {
source.addEventListener('change', () => {
Array.from(syncedInputs).forEach((target) => {
target.value = source.value;
});
});
});
Note that:
Without the JS, selecting a date in one form won't update the other form's value
As indicated in the original answer, you'd want to use hidden inputs for the suggested-entry forms. To do that, just change type="date" to type="hidden" for the other form. Synchronization will still work as the value is tracked in the (invisible parts of the) DOM.
Im building a site using Django. I am trying to pass an input from index.html and display it in about.html using view.py.
My input seems to get passed as it is in the url at the top the browser.I am trying to store this value in a variable and display the variable in a html paragraph. However it does not show. Instead of seeing the input associated with the variable i just see the string of text with the variable name.
My index.html:
<form action="{% url 'theaboutpage' %}">
<input type="text" name="user_input">
<input type="submit" value="click here now">
</form>
My about.html:
<a href={% url 'thehomepage' %}>go back to the home page</a>
<p>{{'input_from_home_page'}}</p>
My views.py:
def about(request):
Hellothere = request.GET['user_input']
return render(request, 'about.html', {'input_from_home_page':Hellothere})
Just remove the quotation marks around the variable in your template at about.html. It should look like this:
<p>{{ input_from_home_page }}</p>
As side notes:
If the information entered in <input type="text" name="user_input"> is sensitive information, then you should consider passing it using "POST" HTTP method instead of "GET". In which case, remember to include the {% csrf_token %}. To get the passed info, you can use: request.POST.get('user_input') in your view.
By convention, you should name variables with lowercase. In your case, it's nice to have hello_there instead of Hellothere.
I am attempting to create a django web app, and I'm running into an issue with forms. I have a simple index.html set up that has two separate regular html forms on the page. One for filtering and the other for sorting. Currently, I can get either filtering, or sorting to work, but not both at the same time. I think this is because I'm missing a fundamental understanding of django somewhere. Yes, I've done the tutorials.
I've attempted manually appending the URL to my url config, but that didn't work as intended.
<form action="" method="get">
{% for filter in view.all_filters %}
<label>
<input type="checkbox" name="filter" value="{{ filter }}">
{{ filter }}
</label>
{% endfor %}
<input type="submit" value="Apply Filters">
</form>
<form action="." method="get">
<label>
Sort By
<select name="order_by">
<option value="name">Name</option>
<option value="description">Description</option>
<option value="cvssBaseScore">Cvss Base Score</option>
<option value="cvssV3BaseScore">Cvss V3 Base Score</option>
</select>
</label>
<input type="submit" value="Submit">
</form>
I would like the url to be able to append something like ?filters=one&filters=two&order_by=name or something as such.
The question is not really related to Django but rather to how HTML forms work:
A <form> element encapsulates all the data (<input>s) that it submits, so if you put two separate forms in your HTML page, then you intentionally want only one of the forms to be submitted with its data.
Just put both your inputs (the filter and the order_by inputs) inside the same <form> element so that both are submitted when either of the submit buttons is clicked.
I have a django form displayed like this in a template:
<div>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
</div>
Which contains a field like this:
class CreateArticle(forms.Form):
organization = forms.ModelChoiceField(queryset=models.Organization.objects.all())
introduction_text = forms.CharField(widget=forms.Textarea)
As you can see in the screenshot below the field description (Introduction text) ends up to the left of the textfield, I would like it to be placed above.
Is there a way to do this in the field definition in the form, without changing the projects css files and/or making the template file more complicated?
Actually, I have found an easy way to do this without touching the css files (which I shouldn't do in this particular project). Just add a 100% width attribute to the text field and it will fill up whatever / or whatever it is part of which will automatically place the text on top of the text field.
introduction_text = forms.CharField(widget=forms.Textarea(attrs={'style': "width:100%;"}))
By adding help in .py field you can make label/description above the text box.
Like this -> introduction_text = forms.CharField(widget=forms.Textarea,help='You can add description here')
Wrapping the text with a div will let textarea to come on a new line. Since div is a block element.
<div>
<form method="post">
<div>
{% csrf_token %}
</div>
<div>
{{ form.as_p }}
</div>
<input type="submit" value="Submit">
</form>
</div>
I have the following code in my template:
<form action="" method="post">{% csrf_token %}
{%for category, category_votes in votes%}
<p>{{category}}: {{category_votes}} <!-- displays as expected -->
<input type="hidden" name="votedCat" value="{{category}}" id={{forloop.counter}}>
<input type="submit" name="upvote" value="Vote for...">
<input type="submit" name="downvote" value="Vote against...">
</p>
{%endfor%}
</form>
The variable {{category}} displays as expected when rendered, but looking in the POST data, "votedCat" is always the last category value in votes.
For example, if votes=[('a',1),('b',2),('c',3)], then request.POST['votedCat'] returns 'c' regardless of which input button is used to submit the form. What did I do wrong?
Because you only have one single form, with multiple inputs for votedCat. Clicking any of the buttons submits the whole form, with all the values for votedCat. If you were to access request.POST.getlist('votedCat') you would see that you actually have all the values.
There are two ways of fixing this. The first is to have separate form elements for each iteration through the loop - to do that, just move the <form> and </form> elements inside the loop.
The second is to have the votedCat input actually be the submit button:
<input type="submit" name="votedCat" value="Vote for {{category}}" id={{forloop.counter}}>
The disadvantage here is that now you have the words 'Vote for' in your variable, which you'll need to parse out in the view code.
Better than both of these would be to have a simple radio button set or select box with a single submit button, but I understand that design requirements sometimes get in the way.
Finally, you should really be using Django's forms framework, rather than using manual HTML and dealing with the POST directly.
I'm not sure if this is the best solution, but you can create a new form inside the loop:
{%for category, category_votes in votes%}
<p>{{category}}: {{category_votes}} <!-- displays as expected -->
<form action="" method="post">{% csrf_token %}
<input type="hidden" name="votedCat" value="{{category}}" id={{forloop.counter}}>
<input type="submit" name="upvote" value="Vote for...">
<input type="submit" name="downvote" value="Vote against...">
</form>
</p>
{%endfor%}
You could consider using the django.forms.Form class to build and process your forms.