python - 如何在 django 中避免循环引用并编写 DRY 代码

标签 python django dry circular-reference

每当我创建稍后可以重用的 DRY 函数,然后在模型中使用它们时,我都会得到循环引用;

例如:

我有以下型号:

from social.services import get_top_viewed_posts

class Post(models.Model):  
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    title = models.CharField('Post Title', max_length=255) 

class ActivityUpdateEmail(models.Model):
    sent = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now = True)

    def send(self):        

        posts = get_top_viewed_posts()

我查看最多的帖子功能是另一个名为 services.py 的文件,因此我可以在其他地方访问它。它看起来像:

from social.models import Post

def get_top_viewed_posts():
    posts = Post.objects.filter(
        pk__in=popular_posts_ids,
        ).order_by(
                '-created_at'
                )

    return posts

然后我收到错误:

services.py", line 1, in <module>
    from social.models import Post
ImportError: cannot import name 'Post'

如果我将其更改为:

交易 = Action.objects.filter( 内容类型__pk=35, 创建于__gte=开始日期, ).values_list('object_id', flat=True)

popular_posts_ids = []
popular_posts = Counter(transactions).most_common()[:result_amount]

for dic in popular_posts:
    popular_posts_ids.append(dic[0])


class ActivityUpdateEmail(models.Model):
    sent = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now = True)

    def send(self):  

         posts = Post.objects.filter(
              pk__in=popular_posts_ids,
         ).order_by(
            '-created_at'
            )

这没问题。

如何使用这种抽象功能的干方法,然后能够在我的模型中使用它们?

最佳答案

发生错误的原因是,当您在 models.py 顶部导入 get_top_viewed_posts 时,Post 模型尚未声明。

您有几种选择。

将导入从 models.py 顶部移至方法内部

def send(self):        
    from social.services import get_top_viewed_posts
    posts = get_top_viewed_posts()

不用担心性能,导入会被缓存 - 但如果您在其他方法中使用它,则一遍又一遍地重复相同的导入可能会很乏味。

抽象类

通过将模型作为参数传递,使函数更加通用,这样您就不需要在 services.py 文件顶部导入模型:

def get_top_viewed_model(model, popular_ids, order_by='-created_at'):
    return model.objects..filter(
        pk__in=popular_ids,
    ).order_by(
        order
    )

然后:

def send(self):        
    posts = get_top_viewed_model(type(self), popular_posts_ids)

# at other places
get_top_viewed_model(Posts, popular_posts_ids)

使用自定义管理器

使用 top_viewed 方法创建自定义管理器:

class TopViewedManager(models.Manager):
    def __init__(self, order='-created_at', **kwargs):
        self._order = order
        self._filter = kwargs

    def top_viewed(self):
        return self.get_queryset().filter(**self._filter).order_by(self._order)

class Post(models.Model):
    ...
    objects = TopViewedManager(pk__in=popular_posts_ids)

然后只需在需要使用 get_top_viewed_model 的地方使用它即可:

Post.objects.top_viewed()

这个管理器非常通用,因此您可以将它与您想要的任何模型、过滤器和顺序一起使用。

可能还有其他选择,这取决于个人喜好。

关于python - 如何在 django 中避免循环引用并编写 DRY 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51662462/

相关文章:

javascript - 如何让这个 jQuery 代码在相同的 html 元素上工作?

javascript - jQuery 干涸功能

python - 如何对数据库包装器进行单元测试?

python - python的多处理池的键盘中断

django - 组合两个 Django 项目的最简单方法

javascript - {Javascript} 调用POST xmlHttpRequest时如何返回Json

python - 忽略 nan 值并执行 numpy.polyval 的函数

Python 无法打开符号链接(symbolic link)文件

python - 如何检索其中包含哈希的 GET 变量

java - 当需要在每个 setter 中使用相同的条件运算符时如何保持干燥?