user5647529
user5647529

Reputation:

How to add custom function to admin forms?

I would like to implement a function that updates quantity in LibraryBook each time the admin adds a book in SingleBook on the admin site. I have been searching for means to do so but to no avail. Any pointers including links to documentation would be very much appreciated. Here is my code:

#models.py
class LibraryBook(models.Model):
    book_title = models.CharField(max_length=100, blank=False)
    book_author_id = models.ForeignKey(BookAuthors, on_delete=models.CASCADE)
    category = models.ForeignKey(BookCategory, on_delete=models.CASCADE)
    quantity = models.IntegerField(blank=False, default=0)
    number_borrowed = models.IntegerField(default=0)

    def __unicode__(self):
        return unicode(self.book_title)

class SingleBook(models.Model):
    serial_number = models.CharField(primary_key=True , max_length=150, blank=False)
    book_id = models.ForeignKey(LibraryBook, on_delete=models.CASCADE)
    is_available_returned = models.BooleanField(default=True)
    is_borrowed = models.BooleanField(default=False)

    def __unicode__(self):
        return unicode(self.book_id)

#admin.py
class SingleBookAdmin(admin.ModelAdmin):
    list_display = ('book_id', 'serial_number')

class LibraryBookAdmin(admin.ModelAdmin):
    list_display = ('book_title', 'book_author_id', 'quantity')
    search_fields = ('book_title', 'book_author_id')
    fields = ('book_title', 'book_author_id', 'quantity')

PS: I have omitted the import and admin.site.register code

Django==1.9.8
django-material==0.8.0
django-model-utils==2.5.1
psycopg2==2.6.2
wheel==0.24.0

Upvotes: 2

Views: 93

Answers (2)

e4c5
e4c5

Reputation: 53774

override save_model

If you only want to make the changes when an admin updates a record, the best way is to override the save_model method in ModelAdmin

The save_model method is given the HttpRequest, a model instance, a ModelForm instance and a boolean value based on whether it is adding or changing the object. Here you can do any pre- or post-save operations.

class SingleBookAdmin(admin.ModelAdmin):
    list_display = ('book_id', 'serial_number')

    def save_model(self, request, obj, form, change):
       admin.ModelAdmin.save_model(self, request, obj, form, change)


       if obj.is_borrowed:
          do something to obj.book_id.quantity
       else:
          do something to obj.book_id.quantity

post_save signal

from django.dispatch.dispatcher import receiver
from django.db.models.signals import post_save

@receiver(post_save, sender=SingleBook)
def user_updated(sender,instance, **kwargs):
    ''' Fired when a SingleBook is updated or saved
    we will use the opporunity to change quantity'''
    
    # your logic here

Other pointers

If on the other hand, you wanted to make changes based on all user actions, catching the post_save signal is the way to go. In either case, you might want to override the from_db method in the model to keep track of which fields have changed.

You might also want to change quantity and number_borrowed to IntegerFields (unless you are only using sqlite in which case it doesn't matter)

Also book_author_id should probably be book_author and book_id should probably be book (this is not a rule, just a convention to avoid the ugly book_id_id reference)

Upvotes: 3

GwynBleidD
GwynBleidD

Reputation: 20569

Use signals. Just attach post_save signal to SingleBook model and update according LibraryBook in it. post_save signal takes created argument, so you can determine if book is newly created or edited and apply your action based on that.

Also attach post_delete signal to decrease counter when SingleBook is removed.

To avoid race conditions (when 2 admins are adding books at the same time), I'm suggesting use of queryset update method together with F on changing LibraryBook counter, example:

LibraryBook.objects.filter(id=single_book.book_id_id).update(quantity=F('quantity') + 1)

Doing it that way will ensure that actual math operation will be performed on database level.

Upvotes: 0

Related Questions