记一次Python MRO多继承使用

引言 之前只是看书的时候看过Python多继承的MRO顺序, 从来没在代码里面具体实践过, 今天终于遇到了一次. 在写NWU.ICU的过程中, 有课程评价一项, 建立Model的时候, 为了实现标记删除, 继承了自定义的SoftDeleteModel模型, class Review(SoftDeleteModel): .... pinyin = models.TextField(verbose_name='拼音', blank=True) search_vector = SearchVectorField(null=True) objects = SearchManager() SoftDeleteModel如下 class SoftDeleteManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(is_deleted=False) class SoftDeleteModel(models.Model): is_deleted = models.BooleanField(default=False) deleted_at = models.DateTimeField(null=True, blank=True) objects = SoftDeleteManager() all_objects = models.Manager() def soft_delete(self): self.is_deleted = True self.deleted_at = timezone.now() self.save() soft_delete_signal.send(sender=self.__class__, instance=self) def restore(self): self.is_deleted = False self.deleted_at = None self.save() class Meta: abstract = True 概括就是删除的时候标记is_deleted为true, 并且重写了get_queryset方法, 使得model.objects.get()时, 让已被标记删除的数据不被查询到. 这本来工作好好的, 但为了引入拼音模糊搜索功能, 我在Review模型, 加了几行, 也就是上文里面的 pinyin = models.TextField(verbose_name='拼音', blank=True) search_vector = SearchVectorField(null=True) objects = SearchManager() 使得我的model.objects.get()一直可以获取到已经被标记删除的数据. 解决方案 其中SearchManager如下 class SearchQuerySet(models.QuerySet): def search(self, query, query_table_name): ... class SearchManager(models.Manager): def get_queryset(self): return SearchQuerySet(self.model, using=self._db) def search(self, query, page_size=10, current_page=1): ... search_results = self.get_queryset().search(query, query_table_name) return ... 原因很明显, objects = SearchManager()中get_queryset的覆盖了我在SoftDeleteModel定义的objects的原有方法. ...

2024-09-29 · Moo