How to customize breadcrumbs in Django REST Framework Browsable API - python

Currently the Browsable API seems to derive the breadcrumbs from the classname of my views. However I am using nested resources for my API so I can get Breadcrumbs like:
Root / User List / User Detail / User Invite List / User Invite Detail
However the fact that the 'User Invite'-views show User again is pretty redundant. I would rather have that their breadcrumbs would just be 'Invite List' and 'Invite Detail'.
Now the most obvious solution would ofcourse be to just rename the view classes but that is not an option for me since I also have the classes ChatInviteList and ChatInviteDetail that share the same problem. So I can't name both of them InviteDetail and InviteList.
Is there a way to customize these breadcrumbs in another way? For example by setting some variable in the view class or something. I tried searching the docs but couldn't find anything.

Write a template called 'rest_framework/api.html' (docs) that extends 'rest_framework/base.html' in which you override the breadcrumbs block. For guidance, the original block looks:
{% block breadcrumbs %}
<ul class="breadcrumb">
{% for breadcrumb_name, breadcrumb_url in breadcrumblist %}
{% if forloop.last %}
<li class="active">{{ breadcrumb_name }}</li>
{% else %}
<li>{{ breadcrumb_name }}</li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}

Related

Django How can I cache properly to reuse data?(with using django-mptt package and redis module)

I am making kind of dynamic menu. when you click menu on the top, it show sub menu on the left side. I searched with keyword 'dynamic menu' from stackoverflow and google. I got idea to build that kind of menu. I made it like below.
1) render data(menu list) in context to template by custom context processor.
2) using custom template tag which is provided by django-mptt package.
3) show top menu in base template.
4) move to another template to show sub menu according to what top menu you click
I made custom context_processor to use menu in context in every template.
context_processor.py
from manager.models import Menu
def menu(request):
menu_list = list(Menu.objects.all())
return {'menu':menu_list}
template.py(example)
{% load mptt_tags %}
<nav id="{{ menu_id }}" class="tree-menu">
<ul>
{% recursetree menu %}
<li class="menu
{% if node.is_root_node %}root{% endif %}
{% if node.is_child_node %}child{% endif %}
{% if node.is_leaf_node %}leaf{% endif %}
{% if current_menu in node.get_descendants %}open{% else %}closed{% endif %}
">
{{ node.menu_name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
{% if node.items and node.items.exists %}
<ul class="items">
{% for item in node.items.all %}
{% if item_template %}
{% include item_template %}
{% else %}
{% include "menu/tree-item.html" %}
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
</nav>
mptt_tags.py
#register.tag
def recursetree(parser, token):
"""
Iterates over the nodes in the tree, and renders the contained block for each node.
This tag will recursively render children into the template variable {{ children }}.
Only one database query is required (children are cached for the whole tree)
Usage:
<ul>
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul>
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError(_('%s tag requires a queryset') % bits[0])
queryset_var = template.Variable(bits[1])
template_nodes = parser.parse(('endrecursetree',))
parser.delete_first_token()
return RecurseTreeNode(template_nodes, queryset_var)
My Question
If you see django manual about QuerySet, it says that "Each QuerySet contains a cache to minimize database access". It is obvious that, if you query same data in certain rule, it doesn't seem hit database again but return result from cache. Then I am querying Menu.objects.all() in custom context processor. This result(menu_list = Menu.objects.all()) will be in context every time, you can use menu data on every template repeately. So does it reuse the result from cache without hitting database again?
If menu_list = Menu.objects.all() in custom context processor hit database every time whenever template load this menu list, Does it work in this way to reuse menu data from cache without hitting database everytime?
context_processors.py
from manager.models import Menu
from django.core.cache import cache
def menu(request):
menu_list = cache.get_or_set('menu_list', list(Menu.objects.all()))
return {'menu':menu_list, 'redis':"Food"}
Lastly, I don't know if there are many people using django-mptt package. I guess just a few people have experience using it in person. It says "Only one database query is required (children are cached for the whole tree)" so does it mean if I use django-mptt package and get menu from it on template, it automatically cache its data?
Well, I am not clear about django cache system.
It would be really appreciate if you can give me answer and insight for my questions. Thanks for reading!

Django. Customize action for model

I need to edit the "Add Object" action in the admin. It needs to redirect the user to a custom cause the logic required for adding objects is too complex to be managed in the admin. So, how do I make this possible? i.e:
The picture shows a django-suit admin, but the question is the same. How can I make that button redirect to a custom url? Or, how can I create a similar button that redirects to a custom url (I could disable the default create and leave only the custom button).
Override change_list_template html, the block object-tools-items. It's where add button is placed.
class MyModelAdmin(admin.ModelAdmin):
change_list_template = 'change_list.html'
In your change_list.html
{% extends "admin/change_list.html" %}
{% load i18n admin_static admin_list %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
<a href="your/custom/url" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
{% endif %}
{% endblock %}
You need to add your new html in any dir that is included on TEMPLATE_DIRS options. But, you should do it inside your model's app.
-app
-templates
-admin
change_list.html
Add above dir in TEMPLATE DIRS paths.

Django TemplateSyntaxError in with template tag

I'm trying to use this app in my project.
https://github.com/streema/django-favit
I already can use the fav-unfav part of this app. I also want to list favourites of user for every user. In read me part it says use this and it will be listed but I have an error with
{% with user_favorites <user> "baslik.Entry" as favorite_list %}
{% for fav_obj in favorite_list %}
{{ fav_obj }}
{% endfor %}
{% endwith %}
Error:
TemplateSyntaxError at /
u'with' expected at least one variable assignment
This is the template tag part for user_favorites:
#register.assignment_tag
def user_favorites(user, app_model=None):
"""
Usage:
Get all user favorited objects:
{% with user_favorites <user> as favorite_list %}
{% for fav_obj in favorite_list %}
{# do something with fav_obj #}
{% endfor %}
{% endwith %}
or, just favorites from one model:
{% with user_favorites <user> "app_label.model" as favorite_list %}
{% for fav_obj in favorite_list %}
{# do something with fav_obj #}
{%
{% endwith %}
"""
return Favorite.objects.for_user(user, app_model)
How can I get rid of this error? Thanks.
It's a reasonably common convention in documentation that anything in angle brackets is a placeholder to be replaced by the actual value. In this case, <user> is supposed to be replaced by the object containing the actual user.
{% with user_favorites request.user ...
I must say, though, that the documentation still doesn't make any sense. You can't use an assignment tag in a with statement like that - even after correcting the user issue, this still won't work. The confusing thing is that the same syntax is repeated throughout the documentation, but it simply doesn't work.
I think this is simply a bug with the documentation, and suspect that if you simply remove the word "with" this will work.
To use custom template tag in django, it is needed to explicitly load it in template.
Add this line at the beginnig of your template (but after {% extends ... %}, if you have such):
{% load favit_tags %}
Looks like this step is missed from django-favit README.

Dynamic session access in templates

I'm trying to access session keys within a loop that needs to be dynamic, I think you'll get what I'm going for by looking at my code that isn't working.
{% for q in questions %}
<div class="question_wrap">
<h2>{{ q }}</h2>
# this does not work
{% if not request.session.get(str(q.id), False) %}
<!-- show them vote options -->
{% else %}
<!-- dont show options -->
{% endif %}
</div>
{% endfor %}
The syntax of Django templates is very limiting in order to prevent people from putting too much logic inside templates and doesn't allow you to pass parameters to methods.
You can prepare a list of tuples already in the view or write a simple template tag for that. The first options is usually easier:
In the view:
questions = [(q, request.session.get(str(q.id), False)) for q in questions]
In the template:
{% for q, has_voted in questions %}
...
{% endfor %}

Question on Django: Displaying many to many fields

I seem to have a problem with Django when it comes Rendering ManyToManyField in a template. I can make it work partially, but I cannot make it work properly as I want it.
Firstly I have an invoice template which displays Invoice details from my data base
#invoice_details.html
{% extends "base.html" %}
{% block content %}
<h2>Invoice Details</h2>
<div id="horizontalnav">
Add an Invoice
Add a Work Order
Add Payment
</div>
<ul>
<div id="list">
{% for invoice in invoices_list %}
{{invoice.client}}<br/>
{{invoice.invoice_no}}<br/>
{{invoice.contract_info}}<br/>
{{invoice.date}}<br/>
{{invoice.work_orders}}<br/>
{% endfor %}
</div>
</ul>
{% endblock %}
In my database, {{invoice.work_orders}} was displayed like the following below. This is because {{invoice.work_orders}} uses a manytomanyfield
<django.db.models.fields.related.ManyRelatedManager object at 0x8a811ec>
Now I tried to change {{invoice.work_orders}} to {{invoice.work_orders.all}} and I got this.
[<Work_Order: Assurance Support Service >]
This sort of works, but I want it to display "Assurance Support Service" only. So I am wondering how I can do this change if possible.
The content of {{invoice.work_orders.all} is a list of Work_Order objects.
If you want to print them, you should iterate the list:
{% for invoice in invoice.work_orders.all %}
{{invoice}}<br />
{% endfor %}

Categories

Resources