简体   繁体   English

Django - 在 model 创建之前

[英]Django - before model create

I have a model:我有一个 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.对于新的 model 实例,字段book_number_by_release_year必须自动生成并在release_year字段中递增 1。

What is the best way to do this in Django?在 Django 中执行此操作的最佳方法是什么? Thank you for your help谢谢您的帮助

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从 django 文档中,您可以创建自定义 django-admin 命令,如果您的操作系统是 unix,则当它的日期是您设置的日期时,该命令将自动调用,查看上面文档中的示例

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考虑添加您的尝试和 models.py 以获得更详细的答案,对于好的问题,请查看此问题以获取更多详细信息

You can use pre_save signal, or override the save method.您可以使用pre_save信号,或覆盖save方法。 I prefer the former as we're not changing methods defined by django .我更喜欢前者,因为我们不会更改django定义的方法。 Here is a rough implementation on using pre_save signal:这是使用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: Do note that there's a race condition possibility, like any other autoincrement function. PS:请注意存在竞争条件的可能性,就像任何其他autoincrement function 一样。

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

We can try using AutoField for the above use case.对于上述用例,我们可以尝试使用AutoField Instead of relying on a pre_save signal, we can make our changes at model definition like so:我们可以在 model 定义中进行更改,而不是依赖pre_save信号,如下所示:

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

Link to the official documentation: https://docs.djangoproject.com/en/4.0/ref/models/fields/#autofield官方文档链接: https://docs.djangoproject.com/en/4.0/ref/models/fields/#autofield

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM