Home > OS >  Django - before model create
Django - before model create

Time:09-06

I have a model:

book(book_id, release_year, book_number_by_release_year)

Field book_number_by_release_year must be automatically generated and incremented by 1 within the release_year field for new model instances.

What is the best way to do this in Django? Thank you for your help

CodePudding user response:

from django docs you can create custom django-admin commands and if your operating system is unix based this command will automatically called when it's date is what you have set, looking form example in the docs above

from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll

class Command(BaseCommand):
    help = 'Closes the specified poll for voting'

    def add_arguments(self, parser):
        parser.add_argument('poll_ids', nargs=' ', type=int)

    def handle(self, *args, **options):
        for poll_id in options['poll_ids']:
            try:
                poll = Poll.objects.get(pk=poll_id)
            except Poll.DoesNotExist:
                raise CommandError('Poll "%s" does not exist' % poll_id)
            # you can type your logic here 
            poll.opened = False
            poll.save()

            self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))

this will automatically close the polls that is created by user
for your case

def handle(self, *args, **options):
        .
        .

            # you can type your logic here 
            if (datetime.date.today() - self.release_year) == 0:
            self.book_number_by_release_year  =1
            self.save() 

consider adding your attempts and models.py for more detailed answer and for good question check this question for more details

CodePudding user response:

You can use pre_save signal, or override the save method. I prefer the former as we're not changing methods defined by django. Here is a rough implementation on using pre_save signal:

from django.db.models.signals import pre_save
from django.db.models import Max
from django.db import models

class Book(models.Model):
    book_id = models.IntegerField()
    release_year = models.IntegerField()
    book_number_by_release_year = models.IntegerField()


@receiver(pre_save, sender=Book)
def populate_book_number_by_release_year(sender, instance, *args, **kwargs):
    # fetch the last book_id given
    args = Book.objects.filter(release_year=instance.release_year)
    max_value = args.aggregate(Max('book_number_by_release_year'))
    
    if max_value == None:
        instance.book_number_by_release_year=0
    else:
        instance.book_number_by_release_year=max_value['book_number_by_release_year']

PS: Do note that there's a race condition possibility, like any other autoincrement function.

Documentation: https://docs.djangoproject.com/en/4.1/ref/signals/

  • Related