xadmin外键数据多了特别慢的解决方案 2022年2月28日 1412 代码厨子 在一个项目中,必然有很多的外键关联需求,但是数据多了之后,会特别慢。xadmin几乎打不开,终于解决了。 # 问题描述 xadmin处理外键时候,如果数据特别多,会很慢,第一时间想到用ajax方式来异步查询数据,于是使用了relfield_style ='fk-ajax'的方式,可是没有效果,经过多方查询后,发现xadmin本身的兼容性有问题,而且我的使用也有问题,具体解决方案如下: #下拉框搜索 ```python relfield_style ='fk-ajax' ``` 当有外键指向他,会以ajax方式加载 数据量过大时很有用 #实际情况 我的环境是python3.6+Django3+xadmin 除了过滤器中加入的字段有效果,在表单录入界面并没有什么用 这个问题的原因是Django2中ForeignKey和Django1不一样造成的 #解决办法 修改 xadmin/views/edit.py ```python if hasattr(db_field, "rel") and db_field.rel: related_modeladmin = self.admin_site._registry.get(db_field.rel.to) ``` 改为: ```python # if hasattr(db_field, "rel") and db_field.rel: if hasattr(db_field, "remote_field") and db_field.remote_field: related_modeladmin = self.admin_site._registry.get(db_field.remote_field.model) ``` 修改 xadmin/plugins/relfield.py ```python def label_for_value(self, value): key = self.rel.get_related_field().name try: obj = self.rel.to._default_manager.using( self.db).get(**{key: value}) return '%s' % escape(Truncator(obj).words(14, truncate='...')) except (ValueError, self.rel.to.DoesNotExist): ... ... def get_field_style(self, attrs, db_field, style, **kwargs): # search able fk field if style in ('fk-ajax', 'fk-select') and isinstance(db_field, models.ForeignKey): if (db_field.remote_field.to in self.admin_view.admin_site._registry) and \ self.has_model_perm(db_field.remote_field.to, 'view'): db = kwargs.get('using') return dict(attrs or {}, widget=(style == 'fk-ajax' and ForeignKeySearchWidget or ForeignKeySelectWidget)(db_field.remote_field, self.admin_view, using=db)) ``` 改为: ```python def label_for_value(self, value): key = self.rel.get_related_field().name try: # obj = self.rel.to._default_manager.using( obj = self.rel.model._default_manager.using( self.db).get(**{key: value}) return '%s' % escape(Truncator(obj).words(14, truncate='...')) except (ValueError, self.rel.model.DoesNotExist): ... ... def get_field_style(self, attrs, db_field, style, **kwargs): # search able fk field if style in ('fk-ajax', 'fk-select') and isinstance(db_field, models.ForeignKey): if (db_field.remote_field.model in self.admin_view.admin_site._registry) and \ self.has_model_perm(db_field.remote_field.model, 'view'): db = kwargs.get('using') return dict(attrs or {}, widget=(style == 'fk-ajax' and ForeignKeySearchWidget or ForeignKeySelectWidget)(db_field.remote_field, self.admin_view, using=db)) ``` #补充说明 我按照这个改了之后,还是不行,后来发现有个地方我理解错了 比如A模型里有外键到B模型,并不是在A模型的adminx里增加relfield_style ='fk-ajax'就可以了,一定要在B模型的adminx里也加上relfield_style ='fk-ajax' 切记!切记!