I am using django to make a new admin panel and I am also using django-admin-notifications to show notifications in my admin panel. I don't know why it is not working.
Here is my models.py
from __future__ import unicode_literals
from django.db import models
class MyAlbum(models.Model):
title = models.CharField(max_length=30)
photos = models.IntegerField()
def __unicode__(self):
return self.title
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
def __unicode__(self):
return self.first_name
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
def __unicode__(self):
return self.first_name
my admin.py
from django.contrib import admin
from django.contrib.admin import AdminSite
from .models import Person,MyAlbum,Musician
from django.contrib import admin
class MyAdminSite(AdminSite):
site_header = 'Wedding Administration'
site_admin = MyAdminSite(name='weddingadmin')
admin.site.register(Person)
admin.site.register(MyAlbum)
admin.site.register(Musician)
site_admin.register(Person)
site_admin.register(MyAlbum)
my notifications.py
import admin_notifications
from models import Person
def notification():
broken_links = Person.objects.filter(status=False).count()
if broken_links:
return "You have %s broken link%s.<br>You can view or fix them using the <a href='/admin/linkcheck/'>Link Manager</a>." % (broken_links, "s" if broken_links>1 else "")
else:
return ''
admin_notifications.register(notification)
I have also made changes in index.html of admin site
{% load notification_tag %}
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block content %}
{% error_notifications %}
<div id="content-main">
{% if app_list %}
{% for app in app_list %}
<div class="app-{{ app.app_label }} module">
<table>
<caption>
{{ app.name }}
</caption>
{% for model in app.models %}
<tr class="model-{{ model.object_name|lower }}">
{% if model.admin_url %}
<th scope="row">{{ model.name }}</th>
{% else %}
<th scope="row">{{ model.name }}</th>
{% endif %}
{% if model.add_url %}
<td>{% trans 'Add' %}</td>
{% else %}
<td> </td>
{% endif %}
{% if model.admin_url %}
<td>{% trans 'Change' %}</td>
{% else %}
<td> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
{% else %}
<p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% trans 'Recent actions' %}</h2>
<h3>{% trans 'My actions' %}</h3>
{% load log %}
{% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %}
<p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion or not entry.get_admin_url %}
{{ entry.object_repr }}
{% else %}
{{ entry.object_repr }}
{% endif %}
<br/>
{% if entry.content_type %}
<span class="mini quiet">{% filter capfirst %}{{ entry.content_type }}{% endfilter %}</span>
{% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
please tell me what I am doing wrong.The index.html is the actual index.html of the admin template
EDIT 1:
TemplateSyntaxError at /admin/
'notification_tag' is not a registered tag library. Must be one of:
admin_list
admin_modify
admin_static
admin_urls
cache
i18n
l10n
log
static
staticfiles
tz
I was installing django-admin-notifications via pip but i found that only init.py file was installed in the site-packages so i cloned the repository so my advice is don't install django-admin-notifications via pip although there is a package available but only the init.py file was installed
Related
when I click the post title it is supposed to go to the post detail(detail.html) but it's not working, how do i fix this?
Here is Model.py
class Post(models.Model):
.......
def get_absolute_urls(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.publish.day, self.slug])
Urls.py
urlpatterns= [
path('',views.post_list,name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',views.post_detail,name='post_detail'),
]
Views.py
def post_detail(request,year,month,day,post):
post= get_object_or_404(Post,slug=post,status='published',publish_year= year,publish_month= month, publish_day= day)
return render(request,'blog/detail.html',{'post':post})
list.html
{% extends "blog/base.html" %}
{% block title %} My Blog {% endblock title %}
{% block content %}
<h1>My Blog</h1>
<p>this is working in list.html</p>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published{{ post.publish }} by {{ post.author }}
</p>
{{ post.body| truncatewords:30|linebreaks }}
{% endfor %}
{% endblock content %}
detail.html
{% extends "blog/base.html" %}
{% block content %}
<h1>{{ post.title }}</h1>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
{% endblock content %}
You need to use {% url 'get_absolute_urls' %}
or
change your function name above your model get_absolute_url instead of get_absolute_urls
Solution:
in models.py
def get_absolute_url(self): # removed the letter s
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.publish.day, self.slug])
in .html
{% extends "blog/base.html" %}
{% block title %} My Blog {% endblock title %}
{% block content %}
<h1>My Blog</h1>
<p>this is working in list.html</p>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published{{ post.publish }} by {{ post.author }}
</p>
{{ post.body| truncatewords:30|linebreaks }}
{% endfor %}
{% endblock content %}
book_list.html
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if book_list %}
<ul>
{% for book in book_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% endif %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% endblock %}
class in views.py :
class BookListView(generic.ListView):
model = Book
paginate_by = 2
queryset =Book.objects.all()
urls.py :
urlpatterns =[
url('^$',views.index, name ='index'), # matching with an empty string
url('^books/$',views.BookListView.as_view(),name ='books'), #the one to which I am adding the paginator
url('^book/(?P<pk>\d+)/$',views.BookDetailView.as_view(),name='book-detail'),
]
Book model :
class Book(models.Model):
title=models.CharField(max_length=100)
author = models.ForeignKey('Author',on_delete=models.SET_NULL,null = True)
summary = models.TextField(max_length=200,help_text="Enter the description")
isbn = models.CharField('ISBN',max_length=13 ,help_text='13 Character ISBN number' )
genre = models.ManyToManyField(Genre,help_text = 'selct a genre for this book')
class Meta:
ordering =["title"]
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book-detail',args=[str(self.id)] )
The book_list gets rendered perfectly, the problem is with the paginator, the is_paginated condition is not working and it executes the else statement, I have been trying for more than 3 hours, but couldn't find a solution, What Am I missing here ?
Django version : 1.11.2
Python : 3.5
Edit :
update 1: The problem was the paginate_by value was two, and the total items to display was also two hence it didn't initiate the is_paginated tag,It worked fine when I added one item more than paginate_by value.
use this, you had some problem with the if condition
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if object_list %}
<ul>
{% for book in object_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% else %}
<h4> No book</h4>
{% endif %}
{% endblock %}
I search for terms in the model and it didnt bring 'No result found'.I checked the source code of the page and it claerly shows it is seeing something in the search but its not displaying it in browser
<h3>Results</h3>
<p>
</p>
This is my model:
class Feed(models.Model):
text=models.TextField(blank=False,max_length=5000)
auth=models.ForeignKey(Authority,blank=False)
search-indexes.py
class FeedIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True,)
text1 = indexes.CharField(model_attr='text')
auth = indexes.CharField(model_attr='auth')
def get_model(self):
return Feed
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
feed_text.txt
{{ object.text }}
{{ object.auth.name }}
search.html
{% extends 'base.html' %}
{% block content %}
<h2>Search</h2>
<form method="get" action=".">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
{{result.object.text}}
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}{% endif %}« Previous{% if page.has_previous %}{% endif %}
|
{% if page.has_next %}{% endif %}Next »{% if page.has_next %}{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% endblock %}
Kindly help me out
Is there a way to display every last actions made in the Django admin? By default the admin display only last actions of the current user but I would like to see last actions of every administrators. Since I don't have any code of this page in my project, how can I interact with this widget? Should I override the whole index?
I would like to get something like this:
instead of just the 2 first entries if I'm connected as er**** (according to the screen).
Yes, it is. Everything in the Django admin is customizable by overriding the template. All you need is to override the file templates/admin/index.html of your current Django version and change this line:
{% get_admin_log 10 as admin_log for_user user %}
and remove the for_user user part. It will display the 10 last recent actions, without filtering by user. To be perfect, you also need to change the name of the block and add action author. The sidebar block should be something like:
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% trans 'Recent Actions' %}</h2>
<h3>{% trans 'Last Actions' %}</h3> {# Title modified #}
{% load log %}
{% get_admin_log 10 as admin_log %} {# No more filtering #}
{% if not admin_log %}
<p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion or not entry.get_admin_url %}
{{ entry.object_repr }}
{% else %}
{{ entry.object_repr }}
{% endif %}
<br/>
{% if entry.content_type %}
{# Add the author here, at the end #}
<span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}, by {{ entry.user }}</span>
{% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
This is very easy to override on django 1.9:
In your master urls.py where the admin interface is loaded (with admin.autodiscover()), overwrite the name of the admin index template file:
from django.contrib import admin
admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()
Then create the file admin\my_custom_index.html inside any application's template directory (eg. \my_app\templates\admin\my_custom_index.html). It can extend the existing template, so does not need to be that lengthy:
{% extends "admin/index.html" %}
{% load i18n static %}
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% trans 'Recent actions' %}</h2>
<h3>{% trans 'All users' %}</h3>
{% load log %}
{% get_admin_log 30 as admin_log %}
{% if not admin_log %}
<p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion or not entry.get_admin_url %}
{{ entry.object_repr }}
{% else %}
{{ entry.object_repr }}
{% endif %}
<br/>
{% if entry.content_type %}
<span class="mini quiet">{% filter capfirst %}{{ entry.content_type }}{% endfilter %}, by {{ entry.user }}</span>
{% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
The block has varied in django over the years, the version here is newer than that in Maximime's answer.
I need to display number of objects at main django site admin page.
For example, in list of models I need to display
Elephants (6)
instead of
Elephants
I added this code to my model:
class Elephant(models.Model):
....
class Meta:
verbose_name_plural = 'Elephants ' + '(' + unicode(count_elephants()) + ')'
where count_elephants() calculates number of objects. The problem is that verbose_name_plural is calculated at server start and is not called when I delete/insert objects, so this calculated value becomes irrelevant.
Is it possible to do it in correct way?
Thanks!
Since verbose_name_plural is used in many other ways, a better way to do this will be to change the admin index view and admin template.
However, since the admin app can change, this is probably tied to a specific version of
django. I am attaching for example the modified admin taken from django 1.2.5.
(Note: I will use an in place replacement for the index method, but it will be probably better to subclass it instead of replacing the method)
As a start, copy from django/contrib/admin/sites.py the AdminSite.index method and it's required imports, and modify it to include counts (one line changed, look for 'THIS LINE WAS ADDED"). Add it to any of your admin.py files or somewhere else appropriate:
from django.utils.text import capfirst
from django import template
from django.shortcuts import render_to_response
from django.views.decorators.cache import never_cache
from django.utils.translation import ugettext as _
def index_with_count(self, request, extra_context=None):
"""
Displays the main admin index page, which lists all of the installed
apps that have been registered in this site.
"""
app_dict = {}
user = request.user
for model, model_admin in self._registry.items():
app_label = model._meta.app_label
has_module_perms = user.has_module_perms(app_label)
if has_module_perms:
perms = model_admin.get_model_perms(request)
# Check whether user has any perm for this module.
# If so, add the module to the model_list.
if True in perms.values():
model_dict = {
'name': capfirst(model._meta.verbose_name_plural),
'admin_url': mark_safe('%s/%s/' % (app_label, model.__name__.lower())),
'perms': perms,
'count': model.objects.count(), # THIS LINE WAS ADDED
}
if app_label in app_dict:
app_dict[app_label]['models'].append(model_dict)
else:
app_dict[app_label] = {
'name': app_label.title(),
'app_url': app_label + '/',
'has_module_perms': has_module_perms,
'models': [model_dict],
}
# Sort the apps alphabetically.
app_list = app_dict.values()
app_list.sort(lambda x, y: cmp(x['name'], y['name']))
# Sort the models alphabetically within each app.
for app in app_list:
app['models'].sort(lambda x, y: cmp(x['name'], y['name']))
context = {
'title': _('Site administration'),
'app_list': app_list,
'root_path': self.root_path,
}
context.update(extra_context or {})
context_instance = template.RequestContext(request, current_app=self.name)
return render_to_response(self.index_template or 'admin/index.html', context,
context_instance=context_instance
)
site.index = never_cache(type(site.index)(index_with_count, site, AdminSite))
Now copy the django/contrib/admin/templates/admin/index.html file into admin/index.html in any of your templates folders to override the original template and modify it to show the counts:
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% load adminmedia %}{% admin_media_prefix %}css/dashboard.css" />{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block bodyclass %}dashboard{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block content %}
<div id="content-main">
{% if app_list %}
{% for app in app_list %}
<div class="module">
<table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
<caption>{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</caption>
{% for model in app.models %}
<tr>
<th scope="row">
{% if model.perms.change %}
{{ model.name }}
{% else %}
{{ model.name }}
{% endif %}
({{ model.count }})
</th>
{% if model.perms.add %}
<td>{% trans 'Add' %}</td>
{% else %}
<td> </td>
{% endif %}
{% if model.perms.change %}
<td>{% trans 'Change' %}</td>
{% else %}
<td> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
{% else %}
<p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>{% trans 'Recent Actions' %}</h2>
<h3>{% trans 'My Actions' %}</h3>
{% load log %}
{% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %}
<p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
{% if entry.is_deletion %}
{{ entry.object_repr }}
{% else %}
{{ entry.object_repr }}
{% endif %}
<br/>
{% if entry.content_type %}
<span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span>
{% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
This will do it.
(You will still need to modify the app_index view to see the counts correctly in the app index pages, I leave this as an exercise to you :-)
A 2022 update using Django 4.0
Subclass the default admin site, see the official Django doc on subclassing the AdminSite.
in the subclass, overwrite the _build_app_dict() method to add count in its model_dict as in:
model_dict = {
"name": capfirst(model._meta.verbose_name_plural),
"object_name": model._meta.object_name,
"perms": perms,
"admin_url": None,
"add_url": None,
"count": model.objects.count(), # THIS IS ALL YOU NEED TO ADD
}
Override the default admin site for your project with the subclass that we have created and optimized. see the official Django doc overriding the default admin site.
Override the app_list.html template if you haven't already. Inside your app_list.html template, you can now use the model.count variable like so {{ model.count }}. see the official Django docs on overriding templates.