Django JSONField сложный запрос ... практический пример запроса к сложной вложенной структуре данных

Я унаследовал следующую структуру данных JSONField:

[
  {
    "name": "Firstname",
    "show": {
      "value": true
    },
    "type": "text",
    "uuid": "55668e45-07d1-404e-bf65-f6a3cacfaa97",
    "label": {
      "for": "Firstname",
      "display": "First name"
    },
    "value": "Michael",
    "options": [],
    "required": true,
    "component": "Input",
    "placeholder": "Input text here",
    "validationErrors": []
  },
  {
    "name": "Surname",
    "show": {
      "value": true
    },
    "type": "text",
    "uuid": "ce91fefa-66e3-4b08-8f1a-64d95771aa49",
    "label": {
      "for": "Surname",
      "display": "Surname"
    },
    "value": "Roberts",
    "options": [],
    "required": true,
    "component": "Input",
    "placeholder": "Input text here",
    "validationErrors": []
  },
  {
    "name": "EmailAddress",
    "show": {
      "value": true
    },
    "type": "email",
    "uuid": "6012a805-da62-4cee-8656-b7565b5f8756",
    "label": {
      "for": "Email",
      "display": "Email"
    },
    "value": "michael@hiyield.co.uk",
    "options": [],
    "required": true,
    "component": "Input",
    "placeholder": "Input text here",
    "validationErrors": []
  },
  {
    "name": "University",
    "show": {
      "value": true
    },
    "type": "text",
    "uuid": "434e3781-ab8a-4f09-9c68-5ec35188f3c7",
    "label": {
      "for": "University",
      "display": "University/College"
    },
    "value": "University College London",
    "options": [],
    "required": true,
    "component": "Input",
    "placeholder": "Input text here",
    "validationErrors": []
  },
  {
    "name": "Subscribe",
    "show": {
      "value": true
    },
    "type": "checkbox",
    "uuid": "79bdc29e-6357-4175-bf65-07be60776a29",
    "label": {
      "for": "Subscribe",
      "display": "Subscribe to the KEVRI mailing list"
    },
    "value": true,
    "options": [],
    "required": true,
    "component": "Checkbox",
    "description": "KEVRI is committed to respecting and protecting your privacy. The data collected here will create your personalised report which we can email to you after this review if you wish. We will not share personal data with anyone else or send you any further emails.",
    "placeholder": "",
    "validationErrors": []
  }
]

который существует в models.JSONField под названием "about" для "MyModel", следующим образом:

class MyModel(
    AbstractTimestampedModel
):

    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    about = models.JSONField()

Мне интересно, как мне отфильтровать MyModel, где поле внутри about называется по "имени": "EmailAddress" ... а затем запросить "значение" этого конкретного поля?

По сути, для набора запросов MyModel.objects.all().filter() ... Я хочу отфильтровать все значения, в которых EmailAddress равен некоторому значению ...

Я не уверен, что это достижимо в рамках Django ORM. Однако, возможно, найдется кто-то, кто может посоветовать ...

Если я прав, вы должны использовать jsonb_to_recordset функцию PostgreSQL.

Во-первых, вы должны создать пользовательскую функцию базы данных, поскольку в Django Core нет функции для этого.

class JSONRecordSet(Func):
    template = "(SELECT id from %(function)s(%(expressions)s) as items(%(key)s %(output_type)s) where %(key)s='%(search)s')"
    function = "jsonb_to_recordset"

    def __init__(self, expression, key, output_type, search):
        super().__init__(expression, key=key, output_type=output_type, search=search)

Пожалуйста, помните о SQL-инъекциях.

После этого вы можете использовать эту функцию с annotate.

MyModel.objects.annotate(_id=JSONRecordSet(expression="about", key="EmailAddress", output_type="text", search="foo@bar.com")).filter(id=F("_id"))

Возвращаем все экземпляры MyModel, которые имеют значение "foo@bar.com" в ключе EmailAddress.

Попробуйте такой подход:

MyModel.objects.filter(about__name='EmailAddress')

Возможно, он вернет нужный вам результат.

Также посмотрите эту ссылку. Там также описано, как сделать запрос во вложенный словарь с помощью JSONField:

https://docs.djangoproject.com/en/3.2/topics/db/queries/#key-index-and-path-transforms

Вернуться на верх