It's true that the generated queries might be inefficient (I'm not sure all 
DBMS can optimize something like "*SELECT ... FROM foo WHERE id IN (SELECT 
id FROM foo ORDER BY bar LIMIT 10)*"). I would not use such a construction 
on a big production dataset and if performance really matters I would do 
something else.

However, I don't think this is subject to the kind of problem you describe 
as the inner queryset should be turned into a subquery of the main queryset.

On Thursday, November 6, 2014 9:34:53 PM UTC+1, Marc Tamlyn wrote:
>
> The dangers of fetching objects in the class definition is precisely why 
> the extra `.all()` calls exist in `ModelChoiceField` and part of the reason 
> why this does not work. The proposed code from Thomas is dangerous, and 
> even putting that code in the `__init__` will result in rather inefficient 
> queries, although it will work.
>
> To be more explicit as to why this is dangerous: django queries executed 
> at module level will be executed on start of the server, and not rerun as 
> the data or database underneath them changes until the server is restarted. 
> Depending on where they are, they may completely break the `migrate` 
> command needed to create the tables!
>
> On 6 November 2014 11:16, Kamil Śliwak <[email protected] <javascript:>> 
> wrote:
>
>> Sorry, for a late reply.
>>
>> Personally I don't feel that it's a particularly common need, but I can 
>>> see your use case. More common is that a reasonable filter is applicable - 
>>> say books with a rating over 80.
>>>
>>
>> Yeah, I thought about using some other filter but it's a bit harder to 
>> control the number of results that way. You can get more or less than you 
>> want if you can't predict the contents of the database. This makes sense in 
>> some situations but in others, like in mine, you just want top N results, 
>> no matter what they are and getting that with a filter is just a cumbersome 
>> workaround for something that can be easily expressed in SQL.
>>
>> As far as I know we don't have any support for SQL intersects and I don't 
>>> believe there are any plans to introduce it.
>>>
>>
>> OK. My bad. I was under impression that you can get an INTERSECT with 
>> something like 
>>
>> Book.objects.filter(id__gt = 100) & Book.objects.filter(id = 300)
>>
>> But looking at the SQL now I see that this simply combines the conditions 
>> with AND and that something like this fails:
>>
>> Book.objects.filter(id__gt = 100)[:10] & Book.objects.filter(id = 300)
>>
>> In that case the solution is not as straightforward as I originally 
>> thought.
>>
>> I do agree that this should be both documented and preferably raise an 
>>> error - please open a ticket.
>>>
>>
>> OK.
>>
>> The obvious nicety handled by 
>>> ModelChoiceField is the transformation from ids back to objects; the 
>>> less 
>>> obvious one is that a ModelChoiceField runs the query anew for every 
>>> form; 
>>> your ChoiceField cannot be initialized by a query in its definition, and 
>>> needs 
>>> to have its choices set in the form's __init__(). 
>>>
>>
>> Thanks, good to know. I actually do want the instance to make this query, 
>> not the class as since the content of my table is not entirely constant.
>>
>> I can also add another gotcha to your list - if you fetch objects in 
>> class definition, the query is performed before the test runner can switch 
>> database to TEST_DATABASE so the data comes from the default database. I 
>> ran into this when trying to set 'initial' and it was breaking my tests. I 
>> have to move it to __init__().
>>
>> you can base your condition on some subquery, for instance :
>>>
>>> class BookForm(forms.Form):
>>>         book = forms.ModelChoiceField(queryse
>>> t=Book.objects.filter(pk__in=Book.objects.order_by('-rating
>>> ')[:100].values_list('pk')))
>>>
>>> I don't know if there is a better way to do that...
>>>
>>
>> Thanks, that's a really nifty workaround. I thought that something like 
>> this would make two queries but I see that Django is smart enough to 
>> combine it into a single query with a subquery. Nice. A great thing is that 
>> I don't see any downsides to it except that it's a bit less clear than 
>> doing the limit in the main query. And I think that it shouldn't really 
>> degrade performance as the outer query is trivial.
>>
>> Maybe having the from detect LIMIT and do something like this internally 
>> would be a good way to handle this in the Form class?
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected] 
>> <javascript:>.
>> Visit this group at http://groups.google.com/group/django-developers.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-developers/044f428c-8192-48ff-8619-21b22833a7fd%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/django-developers/044f428c-8192-48ff-8619-21b22833a7fd%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/e3ef6f0c-45aa-480f-ac90-000ebb77cb04%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to