1

Using django non-rel 1.3 with MongoDB as the DB backend:

I'm trying to setting a filter on a field (CharField) of MyModel class, in the corresponding django ModelAdmin class, like this:

class MyModelAdmin(admin.ModelAdmin): list_filter = ('myfield',)

but what i get is:

TemplateSyntaxError at /admin/myapp/mymodel

Caught DatabaseError while rendering: This query is not supported by the database.

It seems that Django MongoDB engine doesn't support filter, but i don't find documentation about.

EDIT: The error comes from template file .../admin/templates/change_list.html, and the line that throws it is line 85:

{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}

My model is:

class MyModel(models.Model): myfield=models.CharField(max_length='300')

and my admin model is:

class MyModelAdmin(admin.ModelAdmin): list_filter = ('myfield',)

and register it with:

admin.site.register(MyModel, MyModelAdmin) .

Debugging the code, the exception is throwed by method check_query of basecompiler.py. This method verifies that self.query.distinct or self.query.extra or self.query.having is true and then throws the exception (self.query.distinct is equal to 'True' in the interested query object, so the cause is this).

Giovanni Bitliner
  • 2,032
  • 5
  • 31
  • 50

5 Answers5

1

I'm a Python/Django newb, but I managed to fix this by copying AllValuesFieldListFilter from https://github.com/django/django/blob/stable/1.4.x/django/contrib/admin/filters.py (make sure to change your branch to your version of Django) and then I removed the call to distinct. Had to import a bunch of stuff. Then it works. I also applied the changes from @AlexeyMK's answer to make it distinct again.

for 1.4:

from django.contrib.admin.filters import FieldListFilter
from django.contrib.admin.util import (get_model_from_relation, reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value)
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode, force_unicode

class MongoFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
    self.lookup_kwarg = field_path
    self.lookup_kwarg_isnull = '%s__isnull' % field_path
    self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull,
                                             None)
    parent_model, reverse_path = reverse_field_path(model, field_path)
    queryset = parent_model._default_manager.all()
    # optional feature: limit choices base on existing relationships
    # queryset = queryset.complex_filter(
    #    {'%s__isnull' % reverse_path: False})
    limit_choices_to = get_limit_choices_to_from_path(model, field_path)
    queryset = queryset.filter(limit_choices_to)

    def uniquify(coll):  # enforce uniqueness, preserve order
      seen = set()
      return [x for x in coll if x not in seen and not seen.add(x)]

    self.lookup_choices = uniquify(queryset.order_by(field.name).values_list(field.name, flat=True))

    super(MongoFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path)

def expected_parameters(self):
    return [self.lookup_kwarg, self.lookup_kwarg_isnull]

def choices(self, cl):
    from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
    yield {
        'selected': (self.lookup_val is None
            and self.lookup_val_isnull is None),
        'query_string': cl.get_query_string({},
            [self.lookup_kwarg, self.lookup_kwarg_isnull]),
        'display': _('All'),
    }
    include_none = False
    for val in self.lookup_choices:
        if val is None:
            include_none = True
            continue
        val = smart_unicode(val)
        yield {
            'selected': self.lookup_val == val,
            'query_string': cl.get_query_string({
                self.lookup_kwarg: val,
            }, [self.lookup_kwarg_isnull]),
            'display': val,
        }
    if include_none:
        yield {
            'selected': bool(self.lookup_val_isnull),
            'query_string': cl.get_query_string({
                self.lookup_kwarg_isnull: 'True',
            }, [self.lookup_kwarg]),
            'display': EMPTY_CHANGELIST_VALUE,
        }

Then specify it to use this filter like so:

list_filter = (('myfield', MongoFieldListFilter),)

It's nice because there's no patching required.

Jonathan Rowny
  • 7,588
  • 1
  • 18
  • 26
0

The query that the admin filters require isn't supported by Mongo-Db-Engine, as described here

Giovanni Bitliner
  • 2,032
  • 5
  • 31
  • 50
0

The error occurs because Django Admin's list_filters use a distinct() when trying to figure out which members belong in the list.

Our (internal, hacky) solution was to patch django non_rel to make the distinct call happen in memory rather then on the DB end. This is by no means the 'correct' solution, and we haven't made a point of testing it in use cases other then ours, but it's better than nothing.

YMMV.

https://github.com/BlueDragonX/django-nonrel/commit/4025327efbe5c17c6b77e0497c2b433819c42918

AlexeyMK
  • 6,245
  • 9
  • 36
  • 41
-1

So basically you want to Retrieve only some fields from mongo isn't it?

Looking at the tutorial, I believe you'll have to this in the Django View or Template

You can also try the Google group for further info

Gianfranco P.
  • 10,049
  • 6
  • 51
  • 68
-1

What type is myfield of? You can't order by relationships.

Jonas H.
  • 2,331
  • 4
  • 17
  • 23