#29294: ModelAdmin.raw_id_fields should be included in select_related() by change_view and used by raw id widget -------------------------------------+------------------------------------- Reporter: Yurii Zolot'ko | Owner: nobody Type: | Status: new Cleanup/optimization | Component: contrib.admin | Version: 1.11 Severity: Normal | Resolution: Keywords: | Triage Stage: | Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Changes (by Jurrian Tromp):
* status: closed => new * resolution: needsinfo => Comment: I was about to create a new issue for what I think is the same thing so reopening, I [https://stackoverflow.com/questions/65794839/using- prefetch-related-in-django-in-combination-with-raw-id-fields also encountered] this problem. As stated the label_and_url_for_value() does a get() for each item. When using the raw_id_fields, this is something you don't want. Especially because it does not work with prefetching. I worked around the bug by subclassing it in my own project and actually did a benchmark: **Benchmark: change view page with 180 inline items with relations:** 1. Using no raw_id_field: 1658 queries 2. With raw_id_field and prefetching in Django 3.1: 384 queries 3. Patched raw_id_field and prefetching: 18 queries This proves that my patched ForeignKeyRawIdWidget considerably reduces queries as they already have been prefetched. The culprit here is django.contrib.admin.widgets:176 {{{obj = self.rel.model._default_manager.using(self.db).get(**{key: value})}}} This is a excerpt of what is needed to improve the behaviour which can be backwards compatible: we just need to try if value.pk exists, if not we use the default behaviour: {{{ class ForeignKeyRawIdWidget(widgets.ForeignKeyRawIdWidget): def format_value(self, value): """Try to return the `pk` if value is an object, otherwise just return the value as fallback.""" if value == '' or value is None: return None try: return str(value.pk) except AttributeError: return str(value) def label_and_url_for_value(self, value): """Instead of the original we do not have do a `get()` anymore instead access the instance directly so when value is prefetched this will prevent additional queries.""" try: pk = value.pk meta = value._meta except AttributeError: # Fallback for compatibility with plain pk values return super().label_and_url_for_value(value) }}} Note that this is what I made in order to fix it in a project. If accepted I can provide a more permanent solution. Please let me know if this of interest. -- Ticket URL: <https://code.djangoproject.com/ticket/29294#comment:2> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/064.7cb0872790007e51b432e2e9e102a8d0%40djangoproject.com.