使用Django ORM进行表连接

1 投票
1 回答
1153 浏览
提问于 2025-04-18 05:09

我正在学习Django的ORM(对象关系映射),但对表连接的概念有点困惑。

假设我有下面三个模型,简化了以便阅读。“User”是Django自带的用户模型,“AppUser”是一个对应的模型,用来存储额外的个人资料信息,比如邮政编码,而“Group”是用户的集合(注意,这个组和认证组没有关系)。每个AppUser和每个User之间是一对一的关系。同时,每个AppUser也指向它所属的Group(这个Group可能是空的)。

我的任务是:给定一个group_id,生成所有成员的邮箱列表。

我知道可以通过 .appuser_set.all() 从Group向回查找到AppUser,但我不知道怎么进一步获取相关的User及其邮箱,而不想通过遍历的方式,这样会对数据库造成很大的负担,像这样:

appUser = AppUser.objects.get(user_id=request.user.id)
group = appUser.group
appUsers = group.appuser_set.all()
emails = []
for x in appUsers:
    emails.append(x.user.email) 

另外,我可以写一个原始的SQL连接来实现这个功能,但我怀疑Django的ORM也能做到。请问,正确且最有效的方法是什么呢?

模型:

class User(Model):
    id = IntegerField()
    username = CharField()
    email = CharField()

    class Meta:
        db_table = "auth_user"


class AppUser(Model):
    user = OneToOneField(User, primary_key=True)
    group = ForeignKey('Group', null=True, on_delete=SET_NULL)
    zip = CharField()

    class Meta:
        db_table = "app_users"


class Group(Model):                
    creator = ForeignKey(AppUser, related_name='+')
    created = DateTimeField()
    name = CharField()

    class Meta:
        db_table = "groups"

1 个回答

2

诀窍是始终从你想要获取的模型开始。在这个例子中,你想获取的是电子邮件,而电子邮件是用户模型上的一个字段。所以,从用户模型开始,然后用双下划线的语法来跟踪到组的关系:

users = User.objects.filter(appuser__group_id=group_id)

在这种情况下,其实你只需要一个 JOIN,因为 group_id 是 AppUser 自身的一个字段(它是 group 外键在数据库中的实际字段)。如果你有组名,那就需要两个 JOIN:

users = User.objects.filter(appuser__group__name=group_name)

撰写回答