首页 > 解决方案 > 当某些行为该相关对象返回空值时,如何使用 select_related()?

问题描述

我想从成员资格请求)中获取两个相关对象,但是对于我正在使用的查询,成员资格请求可能为空,并且 django 不允许我这样做。查询:

member = Member.objects.get(id=12345)
Group.objects.annotate(membership=FilteredRelation('members', condition=Q(members__member=member))) \
    .annotate(request=FilteredRelation('requests', condition=(requests__member=member))) \
    .filter(Q(membership__isnull=False) | Q(request__isnull=False)) \
    .select_related('membership', 'request')

与模型

class GroupMembership(models.Model):
    group = models.ForeignKey('group.Group', related_name='members', on_delete=models.CASCADE)
    member = models.ForeignKey(
        'group.Member',
        related_name='group_membership',
        on_delete=models.CASCADE,
    )

class GroupMembershipRequest(models.Model):
    group = models.ForeignKey('group.Group', related_name='requests',  on_delete=models.CASCADE)
    member = models.ForeignKey(
        'group.Member',
        related_name='group_membership_request',
        on_delete=models.CASCADE,
    )

但我收到以下错误:

Traceback (most recent call last):
  ...
  File "/Users/Project/venv/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/Users/Project/venv/lib/python3.6/site-packages/django/db/models/query.py", line 66, in __iter__
    rel_populator.populate(row, obj)
  File "/Users/Project/venv/lib/python3.6/site-packages/django/db/models/query.py", line 1830, in populate
    self.local_setter(from_obj, obj)
  File "/Users/Project/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 869, in local_setter
    f.remote_field.set_cached_value(from_obj, obj)
  File "/Users/Project/venv/lib/python3.6/site-packages/django/db/models/fields/mixins.py", line 23, in set_cached_value
    instance._state.fields_cache[self.get_cache_name()] = value
AttributeError: 'NoneType' object has no attribute '_state'

可能是由查询的性质引起的(某些成员资格请求可能为空)。

是否有另一种方法可以通过单个查询来实现这一点,获取成员资格请求,即使它们是Null

标签: pythondjangodjango-models

解决方案


gm = GroupMembership.objects.filter(member=member,).values_list('group_id', flat=True)
gmr = GroupMembershipRequest.objects.filter(member=member,).values_list('group_id', flat=True)

g_ids = gm+gmr

Groups.objects.filter(id__in=g_ids,)

或者你可以尝试类似

gm = GroupMembership.objects.filter(member=member, group_id=OuterRef('pk'), )
gmr = GroupMembershipRequest.objects.filter(member=member,group_id=OuterRef('pk'), )

Groups.objects.annotate(is_member=Exists(gm), has_requested=Exists(gmr),)
     .filter(Q(is_member=True)|Q(has_requested=True),)

推荐阅读