Hi there, I have been experiencing poor performance with django-admin when list_editable includes ForeignKey fields. In particular, rendering the changelist requires O(m*n) database queries where m is the number of ForeignKey fields included in list_editable and n is the number of rows in the changelist. I have searched extensively for possible causes and, after finding nothing and receiving no response on either django-users ('list_editable duplicate queries') or IRC, I am starting to think that it is a legitimate bug.
The problem, as I understand it, stems from the fact that the choices for the ForeignKey widgets are not cached. So, when every ForeignKey widget on every row is rendered, it queries the database to retrieve the list of possible values. The result in an unacceptible number of queries, especially given the default changelist length of n=100. For my own purposes, I have addressed this issue in three ways: 1. Adding a widget cache to django/forms/widgets.py:~431 -- A patch is available upon request. 2. Manually rendering the data using a custom display function in the admin model. 3. Overriding the ForeignKey widget with a custom CachedSelect widget. The last fix has worked best for me because it does not require hacking up django, but I think that this issue is worth addressing properly in Django. So, does this warrant a ticket? Thanks, Chad PS: For the sake of posterity, I have included the code for my CachedSelect widget. Yes, I am aware that using regular expressions to parse the key is a nasty hack. If you have any better ideas, please let me know! ~~~widgets.py~~~ import re from django.forms.widgets import Select class CachedSelect(Select): cache = {} regex = re.compile('^form-(?P<id>[0-9]+)-(?P<model>.*)$') def render(self, name, value, attrs=None, choices=()): # If name does not match form-<num>-<model>, render widget regularly match = self.regex.match(name) if not match: return super(CachedSelect, self).render(name, value, attrs, choices) id = match.group('id') model = match.group('model') # Cache the data if necessary (first hit of changelist or not cached) if id == '0' or not self.cache.has_key(model): self.cache[model] = [choice for choice in self.choices] self.choices = self.cache[model] return super(CachedSelect, self).render(name, value, attrs, choices) ~~~admin.py~~~ from widgets import CachedSelect ... class BlahAdmin(admin.ModelAdmin): formfield_overrides = {models.ForeignKey:{'widget': CachedSelect()}} ... -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.