Ejemplo n.º 1
0
    def remove_invalid_fields(self, queryset, fields, view, request):
        """Remove invalid fields."""
        order_fields = []
        for field in fields:
            # When a dot is present in the order field, treat it as a JSON path.
            if '.' not in field:
                order_fields.extend(
                    super(JsonOrderingFilter,
                          self).remove_invalid_fields(queryset, [field], view,
                                                      request))
                continue

            path = field.split('.')
            base_field = path[0]
            if len(path) < 2:
                continue
            if not super(JsonOrderingFilter, self).remove_invalid_fields(
                    queryset, [base_field], view, request):
                continue

            reverse = False
            if base_field[0] == '-':
                base_field = base_field[1:]
                reverse = True

            # Resolve base field.
            try:
                quote_name = connection.ops.quote_name
                model_meta = queryset.model._meta  # pylint: disable=protected-access
                base_field = '{}.{}'.format(
                    quote_name(model_meta.db_table),
                    quote_name(model_meta.get_field(base_field).column),
                )
            except FieldDoesNotExist:
                continue

            placeholders = '->'.join(['%s'] * (len(path) - 2))
            # The last placeholder should be accessed via the ->> operator.
            if placeholders:
                placeholders = '->{}->>%s'.format(placeholders)
            else:
                placeholders = '->>%s'

            expression = RawSQL(
                # We can use base_field here directly because we've resolved it via Django ORM.
                '{}{}'.format(base_field, placeholders),
                params=path[1:],
            )

            if reverse:
                expression = expression.desc()

            order_fields.append(expression)

        return order_fields
Ejemplo n.º 2
0
    def order_by_json_path(self, json_path, language_code=None, order='asc'):
        """
        Orders a queryset by the value of the specified `json_path`.

        More about the `#>>` operator and the `json_path` arg syntax:
        https://www.postgresql.org/docs/current/static/functions-json.html

        More about Raw SQL expressions:
        https://docs.djangoproject.com/en/dev/ref/models/expressions/#raw-sql-expressions

        Usage example:
            MyModel.objects.language('en_us').filter(is_active=True).order_by_json_path('title')
        """
        language_code = (language_code or self._language_code
                         or self.get_language_key(language_code))
        json_path = '{%s,%s}' % (language_code, json_path)
        # Our jsonb field is named `translations`.
        raw_sql_expression = RawSQL("translations#>>%s", (json_path, ))
        if order == 'desc':
            raw_sql_expression = raw_sql_expression.desc()
        return self.order_by(raw_sql_expression)