Django MPTT树作为管理员中的模型过滤器

时间:2019-03-06 20:44:40

标签: django django-models django-admin django-mptt django-admin-filters

我有一个链接到相关模型的模型,该模型是Django MPTT树模型,我希望能够在管理控制台中使用Django MPTT树过滤第一个模型。

class Tenders(models.Model):
    ...
    sector=models.ForeignKey(Sector, to_field='sectorId', null=True, blank=True,on_delete=models.CASCADE)
    ...

class Sector(MPTTModel):
    name    = models.CharField(max_length = 255)
    parent  = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,related_name='children')
    sectorId = models.IntegerField(default=0,null=True,unique=True)

在Django管理员中,我想为Tenders模型设置过滤器,以使Django-MPTT树成为过滤器。

我尝试使用以下内容:

class adminTenders(admin.ModelAdmin):    
   def linkTo(self,obj):
       return mark_safe("""<a href='{}' target="_blank" >Tender Link</a>""".format(obj.tenderLink))
   linkTo.short_description=''

   list_display=(
    'title',
    'linkTo',
    'sector',
    'region',
    'repository',
    'id',
   )
   list_filter=(
    ('sector', TreeRelatedFieldListFilter),
   )

admin.site.register(Tenders,adminTenders)

但是,尝试运行此错误时出现以下错误,我无法弄清:

  File "py36/lib/python3.6/site-packages/mptt/admin.py", line 314, in field_choices
    mptt_level_indent * levels_dict[pk])
  KeyError: 0

任何帮助将不胜感激。

编辑1:我认为我将问题隔离到以下事实:我的“行业招标书”中的外键使用to_field='sectorId而不是默认链接到{{1} }列。这样做是为了向后兼容我所坚持的旧数据库方案。

1 个答案:

答案 0 :(得分:0)

因此,事实证明,这是field_choices类中TreeRelatedFieldListFilter函数的django-mptt代码中的错误。

要解决此问题,我必须继承该函数,然后使用该函数使用我定义的to_field

这是自定义代码:

class TreeRelatedForSectors(TreeRelatedFieldListFilter):
    # Modified from django-mptt code to fix to_field problem
    def field_choices(self, field, request, model_admin):
        mptt_level_indent = getattr(model_admin, 'mptt_level_indent', self.mptt_level_indent)
        language_bidi = get_language_bidi()
        initial_choices = field.get_choices(include_blank=False)
        pks = [pk for pk, val in initial_choices]
        models = field.related_model._default_manager.filter(sectorId__in=pks)
        levels_dict = {model.sectorId: getattr(model, model._mptt_meta.level_attr) for model in models}
        choices = []
        for pk, val in initial_choices:
            padding_style = ' style="padding-%s:%spx"' % (
                'right' if language_bidi else 'left',
                mptt_level_indent * levels_dict[pk])
            choices.append((pk, val, mark_safe(padding_style)))
        return choices