The 2 types of validation error a form field in django can have are 'required' and 'invalid'. Is there any way to find out which of these two errors has happened, from the template? Something like
{% if form.username.errors %}
{% for error in form.username.errors %}
{% if error.required %}
Please enter the username
{% else %}
{{ error }}
{% endif %}
I just want to override the error message for the 'required' error, i.e., I want to display my own error message if that error happens. I am using django.contrib.auth.views which uses django.contrib.auth.forms.AuthenticationForm which I don't want to try customizing.
Hope you are searching for this type of handle in html template
{% for x in form.errors %}
{%if "__all__" in x %}
Wrong username and password
{%else%}
{%if "username" in x %}
Requires username
<br>
{%endif%}
{%if "password" in x %}
Requires Password
<br>
{%endif%}
{%endif%}
{%endfor%}
Messages will be printed like this on your login page
Requires username
Requires Password
Wrong username and password
You really should just override the Authentication form. The view accepts an argument that allows for you to override form easily.
I think something like this should work:
All you need to do is override the clean_username method like so:
edit:
overriding the clean_username method fails to change the validation error message because of the following from the form and field validation docs:
The clean() method on a Field
subclass. This is responsible for
running to_python, validate and
run_validators in the correct order
and propagating their errors. If, at
any time, any of the methods raise
ValidationError, the validation stops
and that error is raised. This method
returns the clean data, which is then
inserted into the cleaned_data
dictionary of the form.
The clean_<fieldname>() method in a
form subclass – where is
replaced with the name of the form
field attribute. This method does any
cleaning that is specific to that
particular attribute, unrelated to the
type of field that it is. This method
is not passed any parameters. You will
need to look up the value of the field
in self.cleaned_data and remember that
it will be a Python object at this
point, not the original string
submitted in the form (it will be in
cleaned_data because the general field
clean() method, above, has already
cleaned the data once).
The Field subclass is validated first and returns the cleaned data that is used for the clean_<field_name>() method. If an error occurs there the validation of that field stops.
This means that to override the message you need to either override the Field validation or make the field not require a value so no validation error is raised at that step and raise a required method in the clean_<fieldname>() method
>>> from django.contrib.auth.forms import AuthenticationForm
>>> class MyAuthForm(AuthenticationForm):
... def __init__(self, *args, **kwargs):
... super(MyAuthForm, self).__init__(*args,**kwargs)
... self.fields['username'].error_messages['required']='Custom Required Msg'
...
>>> form = MyAuthForm(data={'password':'asdf'})
>>> form.is_valid()
False
>>> form.errors
{'username': [u'Custom Required Msg']}
>>>
urls.py
from someapp.forms import MyAuthForm
urlpatterns = patterns('',
...
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'someapp/login.html', 'authentication_form':MyAuthForm, }),
...
Related
I am trying to implement a for loop in my Kotlin script. The task is for example The actions are {% foreach a in trip.actions %} a.name {% endfor %} and I have to identify her the for loop and interpret the string. The interpreted string if trip.actions are ["arrive", "load", "unload"] should result in "The actions are arrive, load, unload" etc.
EDIT Upon finding the solution, I changed the title to better reflect the issue. Unstuckify's reply remains valid and relevant to the text of the question
I have a list of dictionaries that I want to loop through with Jinja2:
dict = [{'symbol': 'BTCUSDT', 'price': 59325.1234, 'Qty': 2501}, {'symbol': 'ETHUSDT', 'price': 55.12, 'Qty': 14}]
I've used the loop below (from here). I expected the outer 'for' statement to pick up the first item in the list (which would be a dict) and the inner 'for' loop to iterate through the k,v in the dict.
{% for dict_item in dict %}
{% for key, value in dict_item.items() %}
<h1>Key: {{key}}</h1>
<h2>Value: {{value}}</h2>
{% endfor %}
{% endfor %}
However, Jinja gives me the following error - which suggests Jinja doesn't recognise the elements in the list as dicts:
jinja2.exceptions.UndefinedError: 'list object' has no attribute 'items'
Even heavily simplifed I keep getting the same error:
{% for symbol in dict %}
<h2>{{ symbol }}</h2>
{% endfor %}
The Jinja docs aren't detailed enough on this. I've also tried this and looked at this approach without success. Passing just a dict (not a list of dicts) works well.
Can anybody explain why I'm getting this error and suggest better code? Getting the same error message with different approaches leads me to think there's some fundamental error in my thinking, but I can't figure it out.
What does your code look like on the back end?
I have this in python:
#app.route('/test1')
def test1():
dict = [{'symbol': 'BTCUSDT', 'price': 59325.1234, 'Qty': 2501}, {'symbol': 'ETHUSDT', 'price': 55.12, 'Qty': 14}]
return render_template('test1.html', dict=dict)
This in my .html file:
<!doctype html>
<title>Jinja Test</title>
{% for dict_item in dict %}
{% for key, value in dict_item.items() %}
<h1>Key: {{ key }}</h1>
<h2>Value: {{ value }}</h2>
{% endfor %}
{% endfor %}
My rendered output looks how I would expect it to look with the formatting:
Key: symbol
Value: BTCUSDT
Key: price
Value: 59325.1234
etc.
The issue wasn't with the code, but rather environmental - I changed the title of the question to better reflect the issue.
It turns out that there was most probably an issue with the Flask install, as a re-install (largely) solved the issue - the code above (both in the question and the answer) works as expected.
In addition, during debugging I noticed that Jinja2 in my environment doesn't like commented text in the HTML () and behaves in a non-deterministic way when this is present. Equal code will sometimes throw an error, sometimes it won't and the Jinja2 error message will point to commented out code.
Python 3.9.6, Flask 2.0.1, Jinja2 3.0.1, Chrome 93.0.4577.63, PyCharm 2021.1 on Win10 Home 20H2 19042.1165
I have a UpgradeView with the same possibility for saving like in the django admin. I can save, save and continue editing or save and create a new object.
Each leading to a different view:
DetailView, UpdateView and the CreateView.
After saving I want to give a message out, on every view or template its leading to.
For example "Successfully saved" or "Object could not be saved."
When writing custom template tags it's getting really hard for me, because after I created the tag, I don't know how, where and when to pass the message to the other views.
This is the UpdateView where i come from.
class TopicEditView(UpdateView):
fields = ['title','description',]
model = Topic
...
def get_success_url(self):
if self.request.POST.get('save'):
return reverse('topic_detail', kwargs={'pk':self.object.pk})
elif self.request.POST.get('save_and_continue'):
return reverse('topic_edit', kwargs={'pk':self.object.pk})
elif self.request.POST.get('save_and_create_new'):
return reverse('topic_create')
else:
return reverse('fallback_success_url')
My custom template tag is still empty, because the only examples i saw are pretty hard to understand for me.
#register.inclusion_tag('msg.html', takes_context=True)
def get_msg(context):
return None
Inside 'msg.html' i only have the string saying "Successfully saved", this did lead to nothing and i forgot why i did that.
And this is in my template (nothing):
{% load msg_handler %}
{% get_msg %}
How and where can I pass the message to these views using the session?
Try the Django messages framework instead:
http://docs.djangoproject.com/en/1.8/ref/contrib/messages
I got this faster done than I ever thought.
This is my custom template tag:
#register.simple_tag(takes_context=True)
def get_msg(context):
try:
return context.request.session.pop('msg')
except KeyError:
return ''
And this is my view, passing the message:
class TopicEditView(UpdateView):
...
def get_success_url(self):
self.request.session['msg']='Successfully saved!'
...
Nothing have changed in my template.
If there is a more elegant/useful way, i would appreciate it.
EDIT :
Thanks to Lorenzo Peña's comment, i tried using the messages framework which was really easy to use!
First i went to my views.py again and imported messages
from django.contrib import messages
and changed this line
self.request.session['msg']='Successfully saved!'
To this:
messages.add_message(self.request, messages.SUCCESS, 'Successfully saved!')
Then i made a new template called msg_loader.html containing this:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
And changed in my other templates this
{% load msg_handler %}
{% get_msg %}
to this
{% include "msg_loader.html" %}
Newbie here. My application name is ccad. And the model name is logbook. User A has no permission to edit, add or delete the logbook model from an available user permission.
So I tried hiding the save, save and continue editing, save and add another buttons from User A.
I followed the advised I found in SO.
Here's from picomon inquiry that was answered by Sid. And daniel the same inquiry.
I ended up writing the code below to my template.
change_form.html located at {{template folder}}/admin/app_name/model_name/
{% if perms.ccad.add_logbook %}
<li><input type="submit" value="{% trans 'Save ' %}" class="grp-button grp-default" name="_save" {{ onclick_attrib }}/></li>
<li><input type="submit" value="{% trans 'Save and add another' %}" class="grp-button" name="_addanother" {{ onclick_attrib }} /></li>
<li><input type="submit" value="{% trans 'Save and continue editing' %}" class="grp-button" name="_continue" {{ onclick_attrib }}/></li>
{% endif %}
But the user with no permission can still see the buttons I mention.
I also try changing {% if perms.ccad.add_logbook %} to {% if perms.ccad.can_add_logbook %} with no avail.
What's best way to do this?
Start with checking the perms variable in the template context. Add a ...{{ perms }}... somewhere visible to the template. It should render like this ...<django.contrib.auth.context_processors.PermWrapper object at X>....
If this is not the case you are missing the permissions in the template.
Verify that your settings TEMPLATE_CONTEXT_PROCESSORS tuple contains a django.contrib.auth.context_processors.auth.
Also make sure to use a RequestContext not a Context when rendering the template.
If you finally see a PermWrapper but your permission check still doesn't work change the previous debug to ...{{ perms.ccad }}....
This should output something similar to "set([u'ccad.add_...',...]).
If not then your app might not be called ccad.
Finally before creating the if condition be sure that the permission returns something `...{{ perms.ccad.add_logbook }}...´. This should return either True or False.
Now that i am at the end i noticed that your problem is the other way around and all I wrote so far is useless. :)
add {{ user.is_superuser }} to your template. If its True the current user has superuser rights that return always True even for {{ perms.omg.can_facepalm }}
I have a liquid template where I need to render a partial inside that.
Please note #current_page.page_layout.content will load the content from the DB.
My liquid layout file is as follows:
#layouts/public.html.erb
<%= Liquid::Template.parse(#current_page.page_layout.content).
render('page_content' => yield, 'page_title' => yield(:title)) %>
and following is my code, which includes the partial as well
{{page_content}}
{% include 'this_is_the_partial_name' %}
and I'm getting this error
Liquid error: This liquid context does not allow includes.
I tried searching the web and found this solution, but still I'm not sure what to enter for this code:
Liquid::Template.file_system =
Liquid::LocalFileSystem.new(template_path)
liquid = Liquid::Template.parse(template)
Little late to the party.. but this is how you should use it:
In an initializer (like /config/initializers/liquid.rb) add:
template_path = Rails.root.join('app/views/snippets')
Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
Add your partial file, eg. app/views/snippets/_partial_name.liquid.
Now in your liquid template use:
{% include 'partial_name' %}