【问题标题】:Join and query Django models on non-primary-key relationship?在非主键关系上加入和查询 Django 模型?
【发布时间】:2015-07-30 23:25:46
【问题描述】:

我有两个模型通过一个不是主键的字段在逻辑上相关。是否可以在不引入ForeignKey 列的情况下查询它们(例如select_related(…))?

例如,考虑人为的模型:

class LogEntry(Model):
    source_name = CharField(…)
    log_message = CharField(…)

class LogSource(Model):
    name = CharField(…)
    domain = CharField(…)

我希望能够查询LogEntry,加入并过滤相关的LogSource(例如,我可以访问log_entry.source而无需额外查询):

LogEntry.objects
    .select_related(
        source=Join(LogSource, on="logsource.name = logentry.source_name")),
    )
    .filter(source__domain="example.com")

这是否可能不引入 ForeignKey

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    您应该能够通过使用extra()tables 选项来做到这一点。

    LogEntry.objects.extra(
        tables=['logsource'],
        where=['logsource.name=logentry.source_name',
               'logsource_domain="example.com"',
               ]
    )
    

    另一种选择是将source_name 更改为外键,但指定db_columnto_field 参数以使用现有列。我知道您说过您不想添加外键,但这可能是可以接受的,因为它只更改模型,而不是数据库表中的列。但是,请注意 Django 可能想要创建外键约束。一种技巧是伪造该迁移,以便不在数据库中创建约束。

    class LogEntry(Model):
        source_name = models.ForeignKey(db_column=source_name', to_field='name')
    

    log_entry.source_name 将是 LogSource 实例,log_entry.source_name_id 将是存储在 source_name 列中的值。在转换为外键后将字段从 source_name 重命名为 source 可能有意义,但这不是必需的。

    【讨论】:

    • 有趣...我没有考虑使用带有自定义db_columnto_fieldForeignKey...我必须做一些摆弄以确保不强制执行 FK 约束(即,所以我可以在对应的LogSource 存在之前插入一个LogEntry
    • 有没有办法将extra查询的结果转换成LogSource的实例?或者我需要做一些摆弄来获取log_source.* 列并创建我自己的LogSource 实例?
    • 是的,好点,你需要小心它不会创建任何不需要的外键约束,我已经更新了上面的答案。
    • 不,我认为没有任何方法可以将额外的查询转换为 LogSource 实例。正如您在上面看到的,另一个限制是我必须将域过滤器从filter() 移动到extra() 调用中。
    猜你喜欢
    • 2013-05-27
    • 2020-05-30
    • 2018-01-10
    • 2020-04-20
    • 1970-01-01
    • 2016-06-30
    • 2015-03-25
    • 1970-01-01
    • 2020-01-02
    相关资源
    最近更新 更多