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/