【问题标题】:Django ORM: Reverse relation query multiple model from single modelsDjango ORM:从单个模型反向关系查询多个模型
【发布时间】:2020-01-02 23:20:15
【问题描述】:

我在查询反向关系时遇到了麻烦,我学到了很多关于 select_relatedprefetch_related 的知识,但我没能做到这一点。

首先看看我的模型:

from django.db import models
import uuid

class Person(models.Model):
    alias = models.UUIDField(primary_key=True,default=uuid.uuid4, editable=False, unique=True)
    name = models.CharField(max_length=20)

class Appointment(models.Model):
    patient = models.ForeignKey(Person, related_name="patient_for_appointment", on_delete=models.CASCADE)
    data = models.CharField(max_length=20)

class Sales(models.Model):
    customer = models.ForeignKey(Person, related_name="customer_for_sales", on_delete=models.CASCADE)
    amount = models.FloatField()

class Prescription(models.Model):
    patient = models.ForeignKey(Person, related_name="Patient_for_prescription", on_delete=models.CASCADE)
    details = models.CharField(max_length=100)

我正在尝试过滤 Person 模型以检查此人是否有任何 prescriptionsalesappointment 我想通过像此人这样的单个查询来获取所有这些。将用alias(主键)的人过滤它

我可以用单独的查询过滤它,比如

patient_alias = '53fsdfsdf-fdsfds-df-fdf'
queryset = Appointment.objects.filter(
     patient__alias=patient_alias
 )

但我不想要这个,因为它有性能问题。我不希望这个单独的查询。

我只想查询Person 模型来检查一个人是否有约会、处方或销售

点赞Person.objects.filter(alias='a person alias)

谁能帮我实现这个目标?

非常感谢

【问题讨论】:

    标签: django django-models django-queryset django-orm


    【解决方案1】:

    我们可以选择所有Persons,除了没有Appointment,也没有SalesPrescription的那些:

    Person.objects.exclude(
        patient_for_appointment=None,
        customer_for_sales=None,
        Patient_for_prescription=None
    )

    这将产生一个如下所示的查询:

    SELECT person.alias, person.name
    FROM person
    WHERE NOT (
        person.alias IN (
            SELECT U0.alias
            FROM person U0
            LEFT OUTER JOIN prescription U1 ON U0.alias = U1.patient_id
            WHERE U1.id IS NULL
        )
        AND person.alias IN (
            SELECT U0.alias
            FROM person U0
            LEFT OUTER JOIN sales U1 ON U0.alias = U1.customer_id
            WHERE U1.id IS NULL AND U0.alias = person.alias
        )
        AND person.alias IN (
            SELECT U0.alias
            FROM person U0
            LEFT OUTER JOIN appointment U1
            ON U0.alias = U1.patient_id
            WHERE U1.id IS NULL AND U0.alias = person.alias
        )
    )
    

    或者我们可以建立一个联合,比如:

    Person.objects.filter(
        patient_for_appointment__isnull=False
    ).union(
        Person.objects.filter(customer_for_sales__isnull=False),
        Person.objects.filter(Patient_for_prescription__isnull=False)
    )

    这将导致如下查询:

    (
        SELECT person.alias, person.name
        FROM person
        INNER JOIN appointment ON person.alias = appointment.patient_id
        WHERE appointment.id IS NOT NULL
    ) UNION (
        SELECT person.alias, person.name FROM person
        INNER JOIN sales ON person.alias = sales.customer_id
        WHERE sales.id IS NOT NULL
    ) UNION (
        SELECT person.alias, person.name
        FROM person
        INNER JOIN prescription ON person.alias = prescription.patient_id
        WHERE prescription.id IS NOT NULL
    )
    

    【讨论】:

    • 不,这不是正确的解决方案。我听说有人用 django ORM 的 select 相关预取 realted 进行查询。你的解决方案不行
    • 删除你的解决方案,这是完全不好的做法!
    • @mamuncode: prefetch_related 根本不为过滤器做任何事情!它只添加 extra 查询(!)然后在 Python 端执行 JOIN。所以这只会增加负载。
    • @mamuncode:你不能添加额外的.prefetch_related(..) 部分,比如Person.objects.filter( patient_for_appointment__isnull=False ).union( Person.objects.filter(customer_for_sales__isnull=False), Person.objects.filter(Patient_for_prescription__isnull=False) ).prefetch_related('patient_for_appointment', 'patient_for_prescription', 'customer_for_sales')。但是随后您将进行额外的查询。但这在这里还不错,实际上查询一对多关系并在一个查询中获取它可能会导致网络因重复而拥塞。
    • 那么你会得到一个 Persons 的查询集,它已经有一个 Appointment/Sales/Prescription,并且这些是在哪里获取的。通过在一个查询中执行此操作,您将创建一个由三个 (!) 连接组成的表,因此如果您的表很大,很容易导致数百万(重复)行。
    猜你喜欢
    • 2017-11-25
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 1970-01-01
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多