仅当外键未保存为属性时,Django 才过滤相关模型

Django filter a related model only if a foreign key is not saved as an attribute

我有以下型号:

class Route(Model):
    first_stop = models.ForeignKey(
        Stop,
        help_text="The departure point",
    )
    last_stop = models.ForeignKey(
        Stop,
        help_text="The destination point",
    )

    
class Stop(Model):
    location = models.CharField(max_length=100)
    
    route = models.ForeignKey(
        Route,
        related_name="stops",
        related_query_name="stop",
        help_text="the route that this stop belongs to",
    )

一条路线至少有两个停靠点,对第一个停靠点和最后一个停靠点的引用将作为属性保留。

我正在尝试过滤经过特定位置的路线,而不仅仅是第一站或最后一站。

如果该位置仅出现在其第一站或最后一站,则应排除该路线。

如果位置出现在中间停靠点(不是 first_stop 或 last_stop),则无论该位置是否也出现在其第一个或最后一个停靠点,都应包括该路线.

如果一条路线只有两个停靠点,则应将其排除。

我做了一个解决方案,但它非常冗长和丑陋,而且可能效率低下:

routes_to_exclude = []
for route in result: # result is a queryset
    matched_stops = False
    for stop in route.stops.exclude(
        pk__in=(route.first_stop_id, route.last_stop_id)
    ):  # to make sure the desired location isn't only on the first or last stop
        if str(stop.location) == desired_location:
            matched_stops = True
            break
    if matched_stops:
        routes_to_exclude.append(route.pk)
result = result.exclude(pk__in=routes_to_exclude)

有没有更好的方法来实现这个过滤器?

您可以 .filter(…) [Django-doc] 使用:

从django.db.models导入Q

q1 = Q(count__gt=2) # 不止两次,所以也是一个中间值
q2 = Q(count__gt=1) & ( # 不止一个,所以至少有一个 start/stop 不匹配
    ~Q(first_stop=<i>specific_location</i>) |
    ~Q(last_stop=<i>specific_location</i>)
)
q3 = ( # 两个位置不匹配
    ~Q(first_stop=<i>specific_location</i>) &
    ~Q(last_stop=<i>specific_location</i>)
)

Route.objects.filter(
    停止=<i>specific_location</i>
)。注释(
    cnt=计数('stop')
)。筛选(
    q1 |问题2 |问题3
)

可以使用双下划线 (__) 来查看“through”关系。因此,我们检索 Routes,其中有一个相关的 stopspecific_location,但它不是 first_stoplast_stop.