I am new to Python and Django.
I was trying to count the foreign key items/records of a model and display it as a column in the Admin list_display.
So I have a model "Author", as Foreign key to model "Book".
Here's the models.py:
class Author(models.Model):
name = models.CharField(
max_length=100,
)
class Meta:
ordering = ['-name ']
verbose_name = _('Author')
verbose_name_plural = _('Authors')
def __str__(self):
return self.author
@models.permalink
def get_absolute_url(self):
return reverse('author_detail', kwargs={'pk': self.pk})
class Book(models.Model):
author = models.ForeignKey(
'Author',
related_name='menu_items',
verbose_name=_('author'),
)
bookname= models.CharField(
max_length=100,
)
publisher= models.CharField(
max_length=100,
)
class Meta:
ordering = ['-bookname']
verbose_name = _('Book')
verbose_name_plural = _('Books')
def __str__(self):
return self.bookname
@models.permalink
def get_absolute_url(self):
return ('book_detail', [self.pk])
Here's the admin.py
from django.contrib import admin
from .models import Author, Book
class BookInline(admin.TabularInline):
model = Book
extra = 1
@admin.register(Author)
class LibraryAdmin(admin.ModelAdmin):
def NumberOfBooks(self, obj):
#I guess sth is wrong here when trying to count the book_set
return obj.book_set.count()
NumberOfBooks.short_description = "Books Count"
list_display = ['bookname', 'publisher', 'NumberOfBooks']
inlines = [BookInline]
I want to count how many books each Author wrote, and display like this on the second level of the admin page Home>Authors>Author:
Author | Books Count
Someone1 NumberOfBooks
Someone2 NumberOfBooks
Someone3 NumberOfBooks
Someone4 NumberOfBooks
However I get the error:
'Author' object has no attribute 'book_set'
1. did I do the obj.book_set.count() wrong?
I thought obj.book_set
would refer to "book" under the same "author"(obj), sounds like I misunderstood it but I am not sure how to achieve what I intended to.
2. Instead, if I wanted to add a field to 'Authors' which would auto-count number of "book" related to each Author, should this be a better approach and so how to do it?
There should be a list with all the available fields on the error page and you should find a field called menu_items
(that's what you put into related_name
in your Book
model).
But that might be not the best option. You should be able to override get_queryset()
method on your LibraryAdmin(admin.ModelAdmin)
class like this:
...
from django.db.models import Count
...
@admin.register(Loan)
class LibraryAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(LibraryAdmin, self).get_queryset(request)
return qs.annotate(books_count=Count('menu_items'))
def books_count(self, inst):
return inst.books_count
list_display = ['bookname', 'publisher', 'books_count']
inlines = [BookInline]
This way counting will be done by your DB.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With