La ragione per cui ModelChoiceField
, in particolare, crea un colpo durante la generazione delle scelte - a prescindere dal fatto che il QuerySet è stata popolata in precedenza - si trova in questa linea
for obj in self.queryset.all():
in django.forms.models.ModelChoiceIterator
. Come i punti salienti Django documentation on caching of QuerySets,
callable attributes cause DB lookups every time.
Quindi preferisco utilizzare solo
for obj in self.queryset:
anche se io non sono sicuro al 100% su tutte le implicazioni di questo (io so che non ho grande pianifica con il queryset in seguito, quindi penso di star bene senza la copia .all()
creata). Sono tentato di cambiare questo nel codice sorgente, ma dal momento che ho intenzione di non pensarci più alla prossima installare (ed è un cattivo stile per cominciare) ho finito per scrivere la mia personalizzato ModelChoiceField
:
class MyModelChoiceIterator(forms.models.ModelChoiceIterator):
"""note that only line with # *** in it is actually changed"""
def __init__(self, field):
forms.models.ModelChoiceIterator.__init__(self, field)
def __iter__(self):
if self.field.empty_label is not None:
yield (u"", self.field.empty_label)
if self.field.cache_choices:
if self.field.choice_cache is None:
self.field.choice_cache = [
self.choice(obj) for obj in self.queryset.all()
]
for choice in self.field.choice_cache:
yield choice
else:
for obj in self.queryset: # ***
yield self.choice(obj)
class MyModelChoiceField(forms.ModelChoiceField):
"""only purpose of this class is to call another ModelChoiceIterator"""
def __init__(*args, **kwargs):
forms.ModelChoiceField.__init__(*args, **kwargs)
def _get_choices(self):
if hasattr(self, '_choices'):
return self._choices
return MyModelChoiceIterator(self)
choices = property(_get_choices, forms.ModelChoiceField._set_choices)
Questo non risolve il problema generale della memorizzazione nella cache del database, ma dal momento che stai chiedendo informazioni su ModelChoiceField
in particolare e questo è esattamente ciò che mi ha fatto pensare a quel caching in primo luogo, pensavo che questo potesse essere d'aiuto.
Questa è un'ottima soluzione e funziona perfettamente in Django 1.8. Due suggerimenti minori che potrebbero rendere il codice leggermente più pulito: 1) È possibile rimuovere il '__init __()' da entrambe le classi, poiché sono non-ops. 2) 'cache_choices' è stato rimosso in Django 1.9, quindi è possibile rimuovere l'intero pezzo del codice. – Chad
Ciao, al momento non sto usando Django, quindi non ho impostato Django e quindi modo per verificarlo. Riluttante a cambiare questo codice al codice che non posso testare: per quanto riguarda la creazione di una risposta con il codice e modificare questo post in basso per collegarlo alla risposta? – Nicolas78