Django - перед созданием модели
У меня есть модель:
book(book_id, release_year, book_number_by_release_year)
Поле book_number_by_release_year
должно автоматически генерироваться и увеличиваться на 1 в поле release_year
для новых экземпляров модели.
Какой лучший способ сделать это в Django? Спасибо за помощь
из документации django вы можете создать пользовательские команды django-admin и если ваша операционная система основана на unix, эта команда будет автоматически вызываться, когда ее дата будет соответствовать заданной вами, смотрите пример в docs выше
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))
это автоматически закроет опросы, созданные пользователем
.
для вашего случая
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()
подумайте о добавлении ваших попыток и models.py для более подробного ответа и для хорошего вопроса проверьте этот вопрос для более подробной информации
Вы можете использовать сигнал pre_save
или переопределить метод save
. Я предпочитаю первый вариант, так как мы не изменяем методы, определенные django
. Вот примерная реализация использования pre_save
сигнала:
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: Обратите внимание, что существует возможность возникновения состояния гонки, как и в любой другой autoincrement
функции.
Документация: https://docs.djangoproject.com/en/4.1/ref/signals/
Мы можем попробовать использовать AutoField
для вышеупомянутого случая использования.
Вместо того чтобы полагаться на сигнал pre_save
, мы можем внести изменения в определение модели следующим образом:
class Book(models.Model):
book_id = models.IntegerField()
release_year = models.IntegerField()
book_number_by_release_year = models.AutoField(primary_key=False)
Ссылка на официальную документацию: https://docs.djangoproject.com/en/4.0/ref/models/fields/#autofield