避免在Django应用中循环模型导入

12 投票
1 回答
9619 浏览
提问于 2025-04-16 22:46

我有一个Django项目,里面有两个应用,结构如下:

## tags app, models.py
class Tag(models.Model):
    title = models.CharField(max_length=50)


## items app, models.py
from application.tags.models import Tag

class Item(models.Model):
    title = models.CharField(max_length=300)
    tags = models.ManyToManyField(Tag, related_name="items")

更新以澄清函数位置

在另一个模型items.models中,我有一个方法,可以获取所有带有一组标签的项目。

这个方法得到的查询结果是这样的:

## Gets all of the items that have tags t1 and t2
Item.objects.filter(tags=t1).filter(tags=t2)

这个方法使用了Item模型和Tag模型,这样是可以的,因为Tag已经被引入到items应用中。

不过,我想在tags应用中也能使用这个方法,但这样做会导致循环导入的问题。

目前,我在tags应用中获取所有带有一组标签的项目的解决办法是对多对多字段的反向关系进行集合交集操作。

## Get all items that have the tags with ids tag_ids
item_set = set(Tag.objects.get(pk=tag_ids[0]).items.all())
for cur_tag_id in tag_ids[1:]: ## for all of the rest of the tags
     item_set = item_set & set(Tag.objects.get(pk=cur_tag_id).items.all())

这样会产生更多的查询和一个集合交集操作。我能否在tags应用中的Tag模型里做类似Item.objects.filter(tags=t1).filter(tags=t2)...的操作?

我通过使用contenttypes来获取Item模型,从而完成了相同的查询。这样做可以吗,还是有更好的方法来组织这些代码?

1 个回答

28

当你定义带有外键的模型时,可以使用这样的格式:

tags = models.ManyToManyField('tags.Tag', ...)

这意味着你不需要导入Tag这个类,只要安装了tags这个应用就可以了。

这样你就可以把一个函数放在其他地方,这个函数可能会同时导入Tag和Item,而不需要担心循环导入的问题。

撰写回答