Django admin list_display weirdly slows down with foreign keys

Django 1.2.5 Python: 2.5.5

My list of administrators of a sports model just went very slowly (5 minutes for 400 entries). He came back in a second or so, until we got 400 games, 50 strange teams and 2 sports.

I fixed it horribly, so I would like to see if anyone has seen this before. My application is as follows:

models: Sport( models.Model ) name Venue( models.Model ) name Team( models.Model ) name Fixture( models.Model ) date sport = models.ForeignKey(Sport) venue = models.ForeignKey(Venue) TeamFixture( Fixture ) team1 = models.ForeignKey(Team, related_name="Team 1") team2 = models.ForeignKey(Team, related_name="Team 2") admin: TeamFixture_ModelAdmin (ModelAdmin) list_display = ('date','sport','venue','team1','team2',) 

If I remove the foreign keys from list_display then it is fast. As soon as I add any foreign key, then slowly.

I fixed it using not foreign keys, but computing them in init, so this works:

 models: TeamFixture( Fixture ) team1 = models.ForeignKey(Team, related_name="Team 1") team2 = models.ForeignKey(Team, related_name="Team 2") sport_name = "" venue_name = "" team1_name = "" team2_name = "" def __init__(self, *args, **kwargs): super(TeamFixture, self).__init__(*args, **kwargs) self.sport_name = self.sport.name self.venue_name = self.venue.name self.team1_name = self.team1.name self.team2_name = self.team2.name admin: TeamFixture_ModelAdmin (ModelAdmin) list_display = ('date','sport_name','venue_name','team1_name','team2_name',) 

Administration for all other models is in order with several thousand entries at the moment, and all views on the site are functioning normally.

0
source share
3 answers

The first thing I would like to find is database calls. If you should not do this, install django-debug-toolbar . This awesome tool allows you to check all sql queries made for the current query. I suppose there are a lot of them. If you look at them, you will know where to look for the problem.

One problem that I myself ran into: when the __unicode__ method of the model uses a foreign key, this leads to one database hit per instance. I know two ways to overcome this problem:

  • use select_related , which is usually your best bet.
  • return the __unicode__ static line and override the save method to update this line accordingly.
+3
source

It drives me crazy. list_select_related is True, however, when adding a foreign key to the user in list_display, one request per line is generated in the administrator, which makes recording slow. Select_related is True, so the Django administrator should not invoke this request on every line. What's happening?

+3
source

This is a very old problem with django administrators and foreign keys. Here it happens that whenever you try to load an object, it tries to get all the objects of this foreign key. So let's say you try to load the device with some commands (say, the number of commands is about 100), and it will continue to include all 100 commands at a time. You can try to optimize them using something called raw_fields . What this will do, instead of calling everything at once, limits the number of calls and ensures that the call is only made when an event is triggered (i.e. when you select a command). If this looks like a UI clutter, you can try using this class:

 """ For Raw_id_field to optimize django performance for many to many fields """ class RawIdWidget(ManyToManyRawIdWidget): def label_for_value(self, value): values = value.split(',') str_values = [] key = self.rel.get_related_field().name for v in values: try: obj = self.rel.to._default_manager.using(self.db).get(**{key: v}) x = smart_unicode(obj) change_url = reverse( "admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()), args=(obj.pk,) ) str_values += ['<strong><a href="%s">%s</a></strong>' % (change_url, escape(x))] except self.rel.to.DoesNotExist: str_values += [u'No input or index in the db'] return u', '.join(str_values) class ImproveRawId(admin.ModelAdmin): raw_id_fields = ('created_by', 'updated_by') def formfield_for_dbfield(self, db_field, **kwargs): if db_field.name in self.raw_id_fields: kwargs.pop("request", None) type = db_field.rel.__class__.__name__ kwargs['widget'] = RawIdWidget(db_field.rel, site) return db_field.formfield(**kwargs) return super(ImproveRawId, self).formfield_for_dbfield(db_field, **kwargs) 

Just make sure you inherit the class correctly. I guess something like TeamFixture_ModelAdmin (ImproveRawIdFieldsForm) . This will most likely give you a pretty steep performance boost in your django admin.

0
source

Source: https://habr.com/ru/post/1436021/


All Articles