python - Django 多对多(通过),带有三个表和额外属性

标签 python django django-models

我已经有一个包含 3 个表的数据库:Person、Card 和 Permission。 用户可以访问多张卡,其中只有一些卡是该人拥有的。 我如何获取此人有权访问且具有所有权状态的所有卡? 由于系统的工作方式,数据库获取必须在单个查询中完成。好像需要使用一些魔法值(例如对象。_set....)才能使其正常工作?

理想的目标查询(包括人员表)是:

SELECT card.id, card.text, permissions.owner
FROM person.id JOIN permissions ON person.id = permissions.person_id JOIN cards.id = permissions.card_id
WHERE person.id = <some person id>;

针对用户 id=1 获取卡片的查询目标结果示例:

[
  {
    "id": 123,
    "text": "some random text",
    "owner": false
  },
  {
    "id": 682,
    "text": "more random text",
    "owner": true
  }
]

我还在其他一些线程中尝试了一些其他解决方案,但大多数解决方案要么不包含直通表中的额外数据,要么不起作用,因为它们似乎需要额外的表(例如Many-to-many relationship between 3 tables in Django 尝试构建额外模型时会抛出错误“关系 personcardpermissions 不存在”)。

数据库表创建SQL:

CREATE TABLE person (
    id SERIAL NOT NULL,
    name VARCHAR(5) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE card (
    id SERIAL NOT NULL,
    text VARCHAR(64) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE permissions (
    person_id INT NOT NULL,
    card_id INT NOT NULL,
    owner BOOLEAN NOT NULL,
    FOREIGN KEY (person_id) REFERENCES person(id),
    FOREIGN KEY (card_id) REFERENCES card(id),
    PRIMARY KEY (person_id, card_id)
);

当前使用的型号:

class Person(models.Model):
    name = models.CharField(max_length=5)

    class Meta:
        managed = False
        db_table = 'person'


class Card(models.Model):
    text = models.CharField(max_length=64)

    class Meta:
        managed = False
        db_table = 'card'


class Permissions(models.Model):
    person = models.ForeignKey(Person, models.DO_NOTHING)
    card = models.ForeignKey(Card, models.DO_NOTHING)
    owner = models.BooleanField()

    class Meta:
        managed = False
        db_table = 'permissions'
        unique_together = (('person', 'card'),)

阅读关于这个确切问题的 Django 文档( https://docs.djangoproject.com/en/3.2/topics/db/models/#intermediary-manytomany ),他们似乎没有提供解决方案,而只是提到使用以前的查询结果使用多个不同的查询(至少我是如何理解解决方案的)它们),对于这样一个简单的查询来说,这似乎非常昂贵。

最佳答案

您可以使用以下方式进行过滤:

from django.db.models import F

Card.objects.annotate(owner=F('permissions__owner')).filter(
    <b>permissions__person_id=<i>some_id</i></b>
)

此查询集中的 Card 对象将具有一个额外的属性 .owner,用于指定该人是否确实是所有者。


Note: normally a Django model is given a singular name, so Permission instead of Permissions.


Note: Your Permissions model acts as a junction table for a many-to-many relation between Card and Person. You can span a ManyToManyField [Django-doc] on the Card model with:

class Card(models.Model):
    # …
    persons = models.ManyToManyField(
        Person,
        through='Permissions'
    )

关于python - Django 多对多(通过),带有三个表和额外属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75644018/

相关文章:

Python Pandas GroupBy 最大日期

python - 整数数组作为 Scapy 自定义字段

python - 如何在 Keras ImageDataGenerator 中应用 OpenCV 颜色图转换?

python - 如何从Facebook获取用户的手机号码?

Django 信号 : How to signal for first entry in table

python - Django 重启服务器或 httpd

python - 退出 control-D 上的子进程?

python - django 如何处理二进制 post 数据?

django 模型 : How to have variable number of foreign keys in a model?

python - 如何在 Django 中使相关字段成为必填项?