﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
23870	Sliced QuerySets in ModelChoiceField	Kamil Śliwak	nobody	"== The issue ==

`ModelChoiceField` raises an exception if its `queryset` is a query that has been sliced (i.e. resolves to a SQL `SELECT` with `LIMIT`). The failure occurs only after form submission - during validation - so it's not obvious to the user if it's unsupported or if he's just using it incorrectly.

This should either be fixed or documented as an unsupported use case. In the latter case the error should appear earlier (in field constructor?) and the message should tell the user explicitly that it's not supported.

== Example ==

Let's say you have a model called Book:

{{{#!python
class Book(models.Model):
    rating = models.IntegerField()
}}}

You want to create a form that lets user select one of the top rated books. So you try:

{{{#!python
class BookForm(forms.Form):
    book = forms.ModelChoiceField(queryset = Book.objects.order_by('-rating')[:100])
}}}

It appears to work - the form can be rendered and you can choose one of a hundered top-rated books. But when you submit, you get the following error:

{{{
AssertionError: Cannot filter a query once a slice has been taken.
}}}

The error is caused by [[https://github.com/django/django/blob/bfb11b95626f39e2f5e18d97d7761c6f93dcc1a9/django/forms/models.py#L1195-L1203|`ModelChoiceField.to_python()`]] validating the existence of the selected item by calling `get()` on the queryset:

{{{#!python
value = self.queryset.get(**{key: value})
}}}

And this is not supported for sliced querysets as the error above states.

== Workarounds ==

To work around the problem one can make the sliced query a subquery:

{{{#!python
class BookForm(forms.Form):
    book = forms.ModelChoiceField(queryset = Book.objects.filter(pk__in = Book.objects.order_by('-rating')[:100].values_list('pk')))
}}}

On my machine this is about 4 times slower than a simple query with `LIMIT` (see the discussion thread linked below) but seems to work without any adverse effects.

One nice feature of this workaround is that the outer query can have different ordering than the one used for slicing which might be useful in some cases. E.g. select top rated books but sort them by title.

I think that it would be a good idea to mention this workaround in [[https://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.ModelChoiceField.queryset|the docs]].

== Discussion ==

Here's the discussion thread regarding the issue on django-developers mailing list: [[https://groups.google.com/forum/#!topic/django-developers/ELqU2xt_Qo0|Why doesn't ModelChoiceField.queryset support slicing?]]"	Bug	new	Forms	1.6	Normal		modelchoicefield limit queryset slicing		Accepted	0	0	0	0	0	0
