最近在维护一个前同事的 django 项目,维护起来略有蛋疼,在这里,我分享些我的经验。

一、用 property 代替比较

(模板和视图中)代码存在大量的 obj.status == 1 ,obj.status == 2 可读性非常差,根本不知道 等于 1 和等于 2 是啥意思(特别是模板中而且特么的没有注释,根本不能忍)。 其实我们可以用 property 来代替比较

    @property
    def is_status_started(self):
        return self.status == 1

    @property
    def is_status_finished(self):
        return self.status == 2

这样,我们在调用的时候 直接 obj.is_status_started 我们就能很清楚的知道代码的含义, 而不用再次去查看代码,当我们的每个 app 下的 choices 非常多的时候,阅读起来非常蛋疼。

二、用函数来代替变量的设置

同样的,当我们设置一个对象的属性的值的时候,

   obj.status = 2
   obj.save()

除非我们在这行代码附近添加注释,否则我们根本不知道这里 设置值为 2 是什么意思。 我们可以编写一个函数来完成该功能。

    def set_status_finished(self, *args, **kwargs):
        self.status = 2
        super(self.__class__, self).save(*args, **kwargs)

这样,在设置变量的时候,只需要

obj.set_status_finished()

就可以了。

上面的这两点有一个很好的优点,那就是 我们的数值是可以修改的,比如的系统 A 中,性别有 男和女,其中 1 代表男,2代表女。 系统 B 中,由于某些原因,发现 1 代表女, 2代表男,你的经理要求你把两个项目连起来用。 你只需要简单的改一个数字,就能完成你的需求。

注意: 更改状态后你还需要更新数据库,用一个临时数字来中转就可以了。 2 -> 3, 1-> 2, 3 -> 1 然后,我们的性别就调整过来了。

三、contenttype 关联的数据项不要删除

其实真的要说的话,最好是所有数据都不要删除。而是用一个状态来表示删除,比如下面这样

  is_deleted = models.BooleanField(default=False, verbose_name='is deleted')

这里再来说说 contenttype 关联的数据。 比如我们的项目中有视频,有音乐,有文章,用户可以对他们进行评论。

class Video(models.Model):
    name = models.CharField(max_length=255, verbose_name='name')
    ...

class Music(models.Model):
    name = models.CharField(max_length=255, verbose_name='name')
    ...

class Comment(models.Model):
    object_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    obj = generic.GenericForeignKey(ct_field="object_type", fk_field="object_id")
    content = models.TextField(blank=True, null=True)

其中,我们的 object_type 指向 Video 和 Music, object_id 就指向 Video 和 Music 对应的 id,那么,我们的 Comment 就是一个通用的评论。

但是,但是,但是,如果我们的 Video 或这 Music 具体的一项被删除的话,评论本身并没有被删除,一旦之后某一条数据的 id 和之前已经删除的一样(这种情况是的确会出现的,这与数据库有关),就会发现莫名其妙的这个下面这么多出了某些评论。

那要怎么处理呢 ?

3.1 、重写 Video 和 Music 的 delete 方法,在删除时,同时删除评论

这样可以保证数据的一致性,但是有一个很致命的缺点,就是 如果类似 Comment 这样的 model 很多, 就有可能出现遗漏。

3.2、Video 和 Music 的数据项不删除。

就如之前所说,使用状态来表示删除。 返回数据的时候,把删除状态的数据过滤掉就可以了。