如何避免循环引用并在 Django 中编写 DRY 代码
how to avoid circular references and write DRY code in django
每当我创建以后可以重用然后在模型中使用它们的 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(
content_type__pk=35,
created_at__gte=start_date,
).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()
不要担心性能,导入会被缓存 - 但如果您在其他方法中使用它,一遍又一遍地重复相同的导入可能会很乏味。
摘要class
使函数更通用,将模型作为参数传递,这样您就不需要在 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()
这个管理器非常通用,所以您可以将它用于您想要的任何模型、过滤器和顺序。
可能还有其他选择,这取决于个人品味。
每当我创建以后可以重用然后在模型中使用它们的 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( content_type__pk=35, created_at__gte=start_date, ).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()
不要担心性能,导入会被缓存 - 但如果您在其他方法中使用它,一遍又一遍地重复相同的导入可能会很乏味。
摘要class
使函数更通用,将模型作为参数传递,这样您就不需要在 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()
这个管理器非常通用,所以您可以将它用于您想要的任何模型、过滤器和顺序。
可能还有其他选择,这取决于个人品味。