Django messages repeating itself instead of updating - python

classinfo = EventType.objects.all()
length = EventType.objects.all().count()
for i in range(length):
messages.success(request, classinfo[i])
So I'm using this to print out a list of all events that are located in EventType.
Image
This is what it looks like. However, when I add another item to the list using the Class Add feature, it repeats the original list again and then adds the additional event. But if I add an additional another event after this it will add it to the list properly. How can I go about fixing this so it doesn't repeat the initial list when I add an event?
How it looks right now when I add an event
This is what the HTML looks like:
{% for message in messages %}
<li>
{{ message }}
</li>
{% endfor %}

By default Django uses the FallbackStorage class, which means that it will first use CookieStorage to store your messages. As long as your cookie does not exceed 2KB, then it will store all your messages in a cookie. What you are doing is creating messages when you run your request, all these messages are stored in a cookie. You then add an event and make another request. The view will then loop through all your EventType's again and add it to the cookie, along with the original content of the cookie from the first request. I don't know why when you add an EventType a third time it shows the list properly, perhaps you are at the size limit of the cookie and it drops its existing contents.
Do you really need to store messages? Messages are used as a logging mechanism. You are using messages to iterate over a model, which is unnecessary. Simply pass classinfo into your context dictionary and iterate over it instead of messages:
view.py:
classinfo = EventType.objects.all()
template.html:
{% for event in classinfo %}
<li>{{ event }}</li>
{% endfor %}
Better yet, simply use Django's ListView, this is exactly what it is for:
class EventListView(ListView):
model = EventType

Related

Jinja2 failsafe template rendering

I'm using Jinja2 to create email notification messages, mostly error notifications.
Sometimes I get invalid or incomplete data about the error details. After all, it is an error condition when this happens. E.g. a dict item might be missing or value type could be incorrect. In such case the rendering fails, but the error notification has to be sent.
I can do following in the exception handler:
To send the template as-is. At least the type of error event will be known to the recipient, but important data will be missing
To send a backup template with just raw data. That would mean to maintain two versions of each message.
What I really want is to render the template on a "best-effort" basis skipping all errors. Is there a way to do that in Jinja2?
Use defaults everywhere it's necessary. Also handles undefined variables:
default(value, default_value=u'', boolean=False):
If the value is undefined it will return the passed default value, otherwise the value of the variable:
{{ my_variable|default('my_variable is not defined') }}
This will output the value of my_variable if the variable was defined, otherwise 'my_variable is not defined'. If you want to use default with variables that evaluate to false you have to set the second parameter to true:
{{ ''|default('the string was empty', true) }}
Or you could use none if you're creating more complex structures based on the data:
{% if p is not none %}
{{ p.User['first_name'] }}
{% else %}
NONE
{%endif %}

How to order a set of object in a view

My code currently lists all domains in a server using:
{% for domain in server.domain_set.all %}
I want to order the domains in the view by their url. Something like:
{% for domain in server.domain_set.all().order_by('url') %}
But I get an exception "could not parse the remainder". How can I order the list?
The "could not parse the remainder" errors is because you're including Python code in your django template. Django doesn't allow that.
You could add a method on the model:
def sorted_domains(self):
return self.domain_set.all().order_by('url')
And then call it like this:
{% for domain in server.sorted_domains %}
An alternative is to set the default sort order on your Domain model with a Meta attribute.
You can use a dictsort filter:
Takes a list of dictionaries and returns that list sorted by the key
given in the argument.
{% for domain in server.domain_set.all|dictsort:'url' %}
Also see:
Sorting related items in a Django template
order_by template filter

Django cache invalidation using versioning

I have a template fragment caching like:
{% cache 3600 my_list request.path %}
... some html
{% endcache %}
the request.path could be in the following form:
list/2012-01-01
list/2012-02-01
...
I've searched so far and read that to invalidate everything under the name 'my_list' I could use versioning and just increment the version using cache.incr_version, but it accepts a key which I don't know since there's no way to predict what URL the user is accessing.
Basically those urls just list some models and when a new one is added, I want to invalidate the cache so it reflects the newly added record. But I can't call .delete or .incr_version because I don't know the full key.

Automatically add a variable into context on per-application basis in Django?

I want to add a context variable in Django, so that I could define its value on per-application basis, or leave it empty.
Example:
apps/someapp/views.py:
def_context_var('app_name', 'Calendar')
templates/base.html:
{% if app_name %}You are in {{ app_name }} app.{% endif %}
....
{% if app_name %}Subsections of {{ app_name }}: ...{% endif %}
I considered the following:
Declare a variable in the app (in a view, or in URLs), and make a context processor. But I can't understang how to extract that var given the request object.
Put decorators on views. Hm, I don't like the idea: too much boilerplate or duplicated code.
#1 but nicer: make methods (like in the example above) that are executed on server restart, write the data into a dict, then a context processor somehow (how?) gets the application name and extracts the data from the dict. Where do I put the method, the dict, how does the context processor know where the view object is in?
You can call resolve(request.path) in a context processor to resolve the current url. See the django documentation on resolve for its return values, especially app_name.

Django: Template context processor request variable

I am trying to implement django-facebookconnect, for I need to check if a user logged in via Facebook or a regular user.
At the template, I can check if user logged in via facebook by checking request.facebook.uid
such as:
{% if is_facebook %}
{% show_facebook_photo user %}
{% endif %}
For this, I need to pass is_facebook': request.facebook.uid to the template and I will be using this in everywhere thus I want tried to apply it to an existing template context processor and call the snipplet above at the base.html, and it works fine for Foo objects:
def global_variables(request):
from django.conf import settings
from myproject.myapp.models import Foo
return {'is_facebook': request.facebook.uid,'foo_list': Foo.objects.all()}
I can list Foo objects at any view without any issue however it fails for this new is_facebook, it simply returns nothing.
If I pass 'is_facebook': request.facebook.uid in every single view , it works but I need this globally for any view rendering.
If you have access via the request object, why do you need to add a special is_facebook boolean at all? Just enable the built-in django.core.context_processors.request and this will ensure that request is present in all templates, then you can do this:
{% if request.facebook.uid %}
It could be a timing issue. Make sure that the Common middleware comes before the facebook middleware in your settings file. You can probably debug and see when the facebook middleware is modifying the request and when your context processor is invoked. That may give you some clue as to why this is happening. But, as Daniel said, you can always just use the request object in your templates.

Categories