By default, Django's admin renders ForeignKey fields in admin as a select field, listing every record in the foreign table as an option. In one admin-accessible model, I'm referencing the User model as a ForeignKey, and since I have thousands of users Django is populating the select with thousands of options. This is causing the admin page to load incredibly slowly, and the select is not very useful since it can take a while to scroll through thousands of options to find the one you want.
What's the best way to change the rendering of this field in order to improve page load and usability? I'd like the select field to be replaced with some sort of button to launch a search form popup, or a text field that searches keywords via Ajax to find the Id for the specific User they want to associate. Does admin have anything like this builtin, or would I have to write this from scratch?
Add raw_id_fields to your model to only show the ID instead of a dropdown.
You're right, Cerin, the cause of the slowdown is because Django is populating the <select> element with too many options. You might want to use an autocomplete element instead.
Interestingly, Django 2.0 has introduced a new feature on the admin site, called autocomplete_fields, which I think you will find useful in this case. It uses AJAX.
class ExampleAdmin(models.ModelAdmin):
autocomplete_fields = ['example_field_user']
You can use one of the few autocomplete apps for Django. Check them at Django Packages.
There's also django-extensions that have ForeignKeyAutocompleteAdmin that fit your needs pretty well.
Another option is to add readonly_fields instead of raw_id_fields
Related
my app has grown so that that drop downs in the django admin have 100,000s of options. I can't even open my admin anymore because of its load on the database, not too mention I wouldn't be able to find an option in the select box.
Does django have an autocomplete option?
What is the best option for handling big data in django admin?
Django 2.0 has introduced a new feature on the admin site, called autocomplete_fields, which is helpful for models with foreign keys. It replaces the normal <select> element with an autocomplete element:
class QuestionAdmin(admin.ModelAdmin):
ordering = ['date_created']
search_fields = ['question_text']
class ChoiceAdmin(admin.ModelAdmin):
autocomplete_fields = ['question']
Here's a screenshot of the element:
Use raw_id_fields, like this:
class SomeModelAdmin(admin.ModelAdmin):
raw_id_fields = ('problematic_field', )
You can read more about this, here:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields
Basically - it will change the select boxes with raw id field with a lens icon - which open another window to make changes.
There is many solutions to your problem out there but here is two ways I consider as viable:
If you need a built-in solution where you don't want to involve an external library, raw_id_fields may help you. This is from the documentation:
By default, Django’s admin uses a select-box interface () for
fields that are ForeignKey. Sometimes you don’t want to incur the
overhead of having to select all the related instances to display in
the drop-down.
raw_id_fields is a list of fields you would like to change into an
Input widget for either a ForeignKey or ManyToManyField:
class ArticleAdmin(admin.ModelAdmin):
raw_id_fields = ("newspaper",)
Use an auto-complete widget. There is ton of existing packages, see this list. Be careful to look which one has recent commits, it will give you an idea of the community awarness.
I am trying to add a non-model form in django admin interface and am not able to find any particular way to do it. This form would do some processing and change some data in the DB. But this is not related to a particular Model and should stand out. This form should not be available for the user to use.
One thing I can do is add the form to the general view and prohibit using permissions but I was thinking since django admin interface already exists, it would be better to add that to the django admin interface.
Is this possible to do in Django?
You can add arbitrary views that within a ModelAdmin that do whatever you want. See the documentation for ModelAdmin.get_urls. You can do the same at a higher level by defining AdminSite.get_urls.
We have some models that are have a user as a foreign key. But with about 25000 users in our system, it's a bit daunting to find the one we need.
Is there a solution out there that's better than the select box? Maybe an autocomplete so we can start typing the user name / address? Or just a search box? When switching the related user for these objects, it's getting harder and harder with 25000 unsorted users.
Even just setting it to sort the users by username would be helpful.
I had this problem and my conclusion was to use an autocomplete field instead. It works pretty well in most cases. The only problem is when you have a lot of entries that are mostly the same. For example, in your case, if you type Robert for the name and there's a few hundred Robert entries in the list...
UPDATE
As mentions in shuckc's answer, Django 2.0+ admin as now autocomplete built in.
For older Django or to use outside of the admin (old answer)
There are many apps that add autocomplete to the Django admin:
django-autocomplete-light
django-extensions (ForeignKeyAutocompleteAdmin)
django-autocomplete (on google code)
django-ajax-selects
django-admin-autocomplete
django-autocomplete (tyrion)
My preferred one is the last one. It's well written, it can be used with the admin and outside of the admin, it works with ManyToManyFields, ForeignKeyFields, CharFields, etc.
I did a fork of this project for my client that adds some niceties like a lookup (loupe) button like the ForeignKeyRawIdWidget.
Django 2.0 admin has autocomplete built in, just set the autocomplete_fields field on the ModelAdmin class. e.g.
class QuestionAdmin(admin.ModelAdmin):
ordering = ['date_created']
search_fields = ['question_text']
class ChoiceAdmin(admin.ModelAdmin):
autocomplete_fields = ['question']
The simplest out-of-the-box solution is to add the field to your ModelAdmin's raw_id_fields -- then you'll get a pop-up window in which you can use the built-in searching/filtering and pagination control's to find and select the object you're after.
If you really want autocomplete, the other answers give a you reasonable starting point.
You can use the ForeignKeyRawIdWidget from django.contrib.admin.widgets. It renders FK relations as an input with a small button along-side which presents a searchable pop up.
There is an app for that (django-autocomplete).
Is there a raw_id_field style widget for use when rendering list_filter fields on Django admin changelist pages?
When I add a foreign-key based field to a Django modeladmin list_filter, Django renders every row in the associated table to the right-hand panel in a select box. If that table is large (e.g. if it points to the User table) this tends to dramatically slow down load time as Django works to renders thousands of rows. Even after it finishes rendering, it can be difficult finding your selection in the huge dropdown.
There's not, but in Django 1.4 the list_filter system was expanded so you can write your own custom filters. See
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
It'd be trivial to, say, limit the number of Users displayed. Making a raw_id_fields-style filter would be slightly trickier - you'd just need to override the filter template and instead of dispaying a list of links, show a form and submit button.
This are my first steps with django so please take no offense if this seems trivial.
I have a very huge table mynames (~ 1 000 000 entrys) and I want to make this table editable in the django admin site. I hooked things up like described in the official django book: I have a model, and I registered it by admin.site.register(mymodel). I can see the "table" on my admin site and I can click on it to see the first page full of names. That is nice so far. As soon as I click on the "show next page button" at the bottom of the page, the query seams to take forever.
Where could the problem be?
Update:
I added an index to the relevant column and now it is fast. I thought by doing
name = models.CharField(max_length=100, db_index=True, unique=True)
in the model definition there would be an index for this column. But there was none. Only unique index. Is this the way it should be or do I miss something?
It would be easier to see what the problem is if you pasted your full model class. Is there a specified ordering on the table? If so, you need to create a corresponding index to make pagination on that field fast. Is the list_display attribute set on the ModelAdmin class for the model? By default, django should order the rows based on the primary key so you should not need an additional index. Also check if you have overridden the __unicode__ method for the model in a way that causes additional database lookups when showing the entity in django admins table?