代码之家  ›  专栏  ›  技术社区  ›  Atma

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

  •  1
  • Atma  · 技术社区  · 6 年前

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

    例如:

    我有以下型号:

    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()
    

    我的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, 创建日期=开始日期, ).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'
                )
    

    这没问题。

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

    1 回复  |  直到 6 年前
        1
  •  2
  •   Paulo Scardine    6 年前

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

    你有几个选择。

    从顶部移动导入 模型.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()
    

    这个管理器是非常通用的,所以您可以将它用于任何模型、过滤器和您想要的顺序。

    可能还有其他选择,这是个人品味的问题。