在Django中的AbstractModel和覆盖保存方法

时间:2015-06-15 21:07:20

标签: django django-models

StackOverflow中提到了很多save()方法的例子。这是我的想法:模型是抽象的。

def save(self, *args, **kwargs):
    # take id of 'self' object by: last id + 1 or 1 if there is no objects in db 
    try:
        future_id = int(self.__class__.objects.latest('pk').pk) + 1
    except:
        future_id = 1

    # set slug by id     
    self.slug = '{future_id}'.format(future_id=future_id)

    # set slug by name and id
    if self.get_name():
        self.slug = '{name}-{slug}'.format(name=slugify(self.get_name()), 
                                           slug=self.slug)
    # save        
    super(AbstractCmsContent, self).save(*args, **kwargs)

问题是:我应该在数据库中使用last id准备一些通用表,还是使用latest()函数调用此解决方案应该在实践中运行良好?

加了:

我将回答我是如何改变这个功能的。最后,我的函数看起来像这样:

    def save(self, *args, **kwargs):

        if not self.slug:

            self.slug = '{name}'.format(name=slugify(self.get_name())) 

            objs = self.__class__.objects.filter(slug__startswith=self.slug)
            max_index = objs.aggregate(Max('slug_index'))['slug_index__max']

            # two conditions: 
            # max_index should be positive, 
            # or number of objects with simillar slug in db > 0
            if max_index or objs.count()>0:
                self.slug_index = max_index + 1
                self.slug = "{slug}-{index}".format(slug=self.slug,
                                                index=self.slug_index)

        super(AbstractCmsContent, self).save(*args, **kwargs)

第一个slug总是只基于名字,下一个有一些额外的索引:'slug-index'。另外我在我的模型中添加了一些额外的字段slug_index,但是像这样我可以很好地控制我的slu ..

1 个答案:

答案 0 :(得分:2)

一般来说,你不应该依赖于获得这样的最新ID,因为有一天你会面临竞争条件(当你的最新PK已经被拿走时)或者你的某些模型会出现错误的ID。

我建议让slug字段可以为空(如果它有unique=True之类的话,它是唯一的选项)并在super调用之后填充它。因此,您将通过将所有内容委托给数据库来获得防弹可靠ID并简化代码。此外,如果您使用现代数据库,它将全部发生在事务中,因此您的对象没有任何时间没有slug。

def save(self, *args, **kwargs):
    super(AbstractCmsContent, self).save(*args, **kwargs)
    self.slug = '{pk}'.format(pk=self.pk)
    if self.get_name():
        self.slug = '{name}-{slug}'.format(name=slugify(self.get_name()), slug=self.slug)
    self.__class__.objects.filter(pk=self.pk).update(slug=self.slug)