Automatically add more items if an item exists in template - django

I have an app that passes "book" object to the template from my view.
I want to automatically add more items to the template context if "book" is being passed. I don't want to do it for every view that passes "book".
e.g. if "book" exists, add "other_books_user_read" in relation to "books" to the template.
I was trying to do this using middleware but I cannot figure out how to check the context if "book" exists.

You can make a template tag that does this behavior, or you could put a method on your book model that you can access in the template.
Here's the simplest one to explain:
class Book(Model):
def other_books_users_read(self):
return Book.objects.filter(...)
{{ book.other_books_users_read }}
Template tag: It's your responsibility to figure out how a custom template tag works, but essentially the code would be...
#register.assignment_tag
def get_other_books_users_read(book):
return Book.objects.filter(...) # logic here to get the books you need.
{% get_other_books_users_read book as other_books_users_read %}
{% for book in other_books_users_read %}
...
Now, if you truly want it in the context, and one line of code (and a dot) is too much work, you can set up a middleware that injects content into the context.
https://docs.djangoproject.com/en/dev/topics/http/middleware/?from=olddocs#process-template-response
class MyMiddleware(object):
def process_template_response(self, request, response):
if 'book' in response.context_data:
response.context_data['other_books'] = Book.objects.filter(...)
return response
But IMO that's a silly way to use a template context middleware since you literally have access to a book object in your template.

Related

Getting the Name of the Model in a Django template using the Form tag

I want to Display the name of the model in my generic form template in Django.
I thought about accessing the name via the form template tag. I know that I can easily hand over this information via the context dict - but I want to use the Information from the formclass since I already given the info in the ModelForm's meta.
Is there a way to access this information inside the template?
Update:
Since I can not access the value directly I assigned the form a name in the views.py:
def form_view(request):
form = Form(request.POST or None)
form.name = 'Name'
...
render (request, 'generic_form_tempalte.html', {'form':form}
and in the template:
{% extends '__base.html' %}
<h1 class="page-header">{{form.name}}</h1>
...
This works - however it is one step more
Not really. The model is available via form._meta.model, but you can't access underscore-prefix attributes in a template, unfortunately.

How can I tell if I'm doing a create or an update with django generic views (CreateView vs UpdateView) from my template?

I'm sharing the same template for my CreateView and UpdateView using django's generic views. I want the "submit" button in my template to say "Add" when I'm using the CreateView and "Update" when I'm using the UpdateView. Is there any way in my template to distinguish which view is being used (CreateView vs UpdateView)?
I know I could use a separate template using template_name_suffix and put the common stuff in a separate include or something but just wanted to see if there was a way to do it without creating a separate template.
When creating a new object, object will always be None, at the moment the template is rendered. You could check for the existence of {{ object }} in your template:
{% if object %}Update{% else %}Add{% endif %}
Override get_context_data and add a flag in your view:
def get_context_data(self, **kwargs):
context = super(YourClass, self).get_context_data(**context)
context['create_view'] = True
return context
Change YourClass to your Class View name
Then in your template you can:
{% if create_view %}

Django basics: how to render a context with a class based view

My 'Note' model has a Charfield called 'tags'. I want to take the Note.tags string and render it as a . I have a method that will give me a python list and I am sort of hoping that I can use the form method '.as_ul' in the template. But I can't seem to get the variable into the template. Here is what I am trying:
My view class:
import string
...
class NoteDetailView(generic.DetailView):
model = Note
template_name = 'note_taker/note'
def tag_string_to_list(self):
tag_string = Note.tags
tag_list = string.split(tag_string)
return render(template_name, Context({'tag_list':tag_list}, note_taker))
My template:
<ul>
{{ tag_list.as_ul }}
</ul>
even if I am wrong about how to use '.as_ul' I can't even render the list with {{ tag_list }}
I suppose I am not understanding how view methods work then.
Use the get_context_data method.
class NoteDetailView(generic.DetailView):
def get_context_data(self, **kwargs):
context = super(NoteDetailView, self).get_context_data(**kwargs)
context['tag_list'] = Note.tags.split()
return context
Within the template, you won't be able to use .as_ul, but there is a built in filter unordered_list that will probably do what you want:
<ul>
{{ tag_list|unordered_list }}
</ul>
Although you should really consider defining a standalone Tag model and using a many-to-many relationship rather than just a char field. This is one of the classic examples of many-to-many relationships. Or using one of the third-party Django tagging packages.
I always use Django's standard ContextMixin. It makes sure that the view object is available in the template as view.
So the view becomes like
class NoteDetailView(generic.ContextMixin, generic.DetailView):
model = Note
template_name = 'note_taker/note'
def tag_string_as_list(self):
return Note.tags.split()
And in the view you do:
<ul>{{ view.tag_string_as_list }}</ul>

Sending an object with request

In the below code i am trying to send a object with the request,Is this correct if so how to decode it in template
def index(request):
cat = Category.objects.filter(title="ASD")
dict = {'cat' : cat}
request.update('dict' : dict)
#or
request.dict=dict;
And In the templates can we write the code as
{% for obj in request.dict%}
obj.title
{% endfor %}
EDIT:
If i am calling function like
def post_list(request, page=0, paginate_by=20, **kwargs):
logging.debug("post_list")
page_size = getattr(settings,'BLOG_PAGESIZE', paginate_by)
return list_detail.object_list(
request,
queryset=Post.objects.published(),
paginate_by=page_size,
page=page,
**kwargs
)
You could do this, but why would you want to? Django has a simple, well-defined and well-documented way of passing data into templates - through the context. Why try and find ways to work around that?
Edit after comment No. Again, Django has a perfectly good way of passing extra context into a generic view, via the extra_context parameter which again is well-documented.
You're not showing the actual function you use to render your view (render(), render_to_response(), etc.).
Let's say you are using render_to_response() :
render_to_response(template_name[, dictionary][, context_instance][, mimetype])
Renders a given template with a given
context dictionary and returns an
HttpResponse object with that rendered
text.
So if you pass in {"foo": your_object} as a dictionary you can use {{ foo }} directly in your template.
If you are using the object_list generic view you should use the extra_context:
extra_context: A dictionary of values
to add to the template context. By
default, this is an empty dictionary.
If a value in the dictionary is
callable, the generic view will call
it just before rendering the template.

Django: How can I identify the calling view from a template?

Short version:
Is there a simple, built-in way to identify the calling view in a Django template, without passing extra context variables?
Long (original) version:
One of my Django apps has several different views, each with its own named URL pattern, that all render the same template. There's a very small amount of template code that needs to change depending on the called view, too small to be worth the overhead of setting up separate templates for each view, so ideally I need to find a way to identify the calling view in the template.
I've tried setting up the views to pass in extra context variables (e.g. "view_name") to identify the calling view, and I've also tried using {% ifequal request.path "/some/path/" %} comparisons, but neither of these solutions seems particularly elegant. Is there a better way to identify the calling view from the template? Is there a way to access to the view's name, or the name of the URL pattern?
Update 1: Regarding the comment that this is simply a case of me misunderstanding MVC, I understand MVC, but Django's not really an MVC framework. I believe the way my app is set up is consistent with Django's take on MVC: the views describe which data is presented, and the templates describe how the data is presented. It just happens that I have a number of views that prepare different data, but that all use the same template because the data is presented the same way for all the views. I'm just looking for a simple way to identify the calling view from the template, if this exists.
Update 2: Thanks for all the answers. I think the question is being overthought -- as mentioned in my original question, I've already considered and tried all of the suggested solutions -- so I've distilled it down to a "short version" now at the top of the question. And right now it seems that if someone were to simply post "No", it'd be the most correct answer :)
Update 3: Carl Meyer posted "No" :) Thanks again, everyone.
Since Django 1.5, the url_name is accessible using:
request.resolver_match.url_name
Before that, you can use a Middleware for that :
from django.core.urlresolvers import resolve
class ViewNameMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
url_name = resolve(request.path).url_name
request.url_name = url_name
Then adding this in MIDDLEWARE_CLASSES, and in templates I have this:
{% if request.url_name == "url_name" %} ... {% endif %}
considering a RequestContext(request) is always passed to the render function. I prefer using url_name for urls, but one can use resolve().app_name and resolve().func.name, but this doesn't work with decorators - the decorator function name is returned instead.
No, and it would be a bad idea. To directly refer to a view function name from the template introduces overly tight coupling between the view layer and the template layer.
A much better solution here is Django's template inheritance system. Define a common parent template, with a block for the (small) area that needs to change in each view's version. Then define each view's template to extend from the parent and define that block appropriately.
If your naming is consistent in your urls.py and views.py, which it should be, then this will return the view name:
{{ request.resolver_match.url_name }}
Be sure to apply some context to it when you call it in the template. For example, I use it here to remove the delete button from my detail view, but in my update view the delete button will still appear!
{% if request.resolver_match.url_name != 'employee_detail' %}
Since Django 1.5 you can access an instance of ResolverMatch through request.resolver_match.
The ResolverMatch gives you the resolved url name, namespace, etc.
one simple solution is :
def view1(req):
viewname = "view1"
and pass this viewname to the template context
def view2(req):
viewname = "view2"
and pass this viewname to the template context
in template access the viewname as
{{viewname}}
and also you can use this in comparisons.
I'm working on this for a help-page system where I wanted each view to correspond to a help-page in my cms with a default page shown if no help page was defined for that view. I stumbled upon this blog where they use a template context processor and some python inspect magic to deduce the view name and populate the context with it.
This sounds like the perfect example of a generic view that you can set up.
See the following resources:
Django Book - Chapter 11: Generic Views
Django Docs -Tutorial: Chapter 4
Django Docs - Generic Views
These links should help you simplify your views and your templates accordingly.
If you're using Class Based Views, you most likely have a view variable you can access.
You can use several methods from that to determine which view has been called or which template is being rendered.
e.g.
{% if view.template_name == 'foo.html' %}
# do something
{% else %}
# other thing
{% endif %}
Another option is to take out the piece of the template where you need something to change and make it into a snippet and then use {% include 'my_snippet.html' with button_type = 'bold' %} in your templates, sending arbitrary values to the snippet so it can determine what to show / how to style itself.
Most generic views — if not all — inherits the ContextMixin which adds a view context variable that points to the View instance.
In your template, you can access the current view instance like this:
{{ view }}
Define class_name method in your view
class ExampleView(FormView):
...
def class_name(self):
return self.__class__.__name__
You can get the class name of the current view in a template like this:
{{ view.class_name }}
{% if view.class_name == "ExampleView" %} ... {% endif %}
Why not trying setting up a session cookie, then read the cookie from your template.
on your views set cookies
def view1(request):
...
#set cookie
request.session["param"]="view1"
def view2(request):
request.session["param"]="view2"
then in your ONE template check something like..
{% ifequal request.session.param "view1" %}
... do stuff related to view1
{% endifequal %}
{% ifequal request.session.param "view2" %}
... do stuff related to "view2"
{% endifequal %}
Gath