一尘不染

在admin中以内联形式限制select中的外键选择

django

该模型的逻辑是:

  • 一个Building有很多Rooms
  • A Room可能在另一个内部Room(例如壁橱-“ self”上的ForeignKey)
  • A Room只能Room位于同一建筑物的另一个内部(这是棘手的部分)

这是我的代码:

#spaces/models.py
from django.db import models    

class Building(models.Model):
    name=models.CharField(max_length=32)
    def __unicode__(self):
        return self.name

class Room(models.Model):
    number=models.CharField(max_length=8)
    building=models.ForeignKey(Building)
    inside_room=models.ForeignKey('self',blank=True,null=True)
    def __unicode__(self):
        return self.number

和:

#spaces/admin.py
from ex.spaces.models import Building, Room
from django.contrib import admin

class RoomAdmin(admin.ModelAdmin):
    pass

class RoomInline(admin.TabularInline):
    model = Room
    extra = 2

class BuildingAdmin(admin.ModelAdmin):
    inlines=[RoomInline]

admin.site.register(Building, BuildingAdmin)
admin.site.register(Room)

内联将仅显示当前建筑物中的房间(这就是我想要的)。但是,问题在于,对于inside_room下拉菜单,它显示了“房间”表中的所有房间(包括其他建筑物中的房间)。

在的内联中rooms,我需要将inside_room选择限制为rooms当前的选项building(当前正在由主BuildingAdmin窗体更改的建筑记录)。

我既无法找出limit_choices_to在模型中使用的方法,也无法找出如何正确地正确覆盖管理员的内联表单集(我觉得我应该以某种方式创建自定义内联表单,并传递的building_id将主表单设置为自定义内联,然后根据该字段将查询集限制为该字段的选择-但我只是无法将精力集中在如何做上)。

也许这对于管理站点来说太复杂了,但是似乎总会有用…


阅读 353

收藏
2020-03-27

共1个答案

一尘不染

将请求实例用作obj的临时容器。重写内联方法formfield_for_foreignkey来修改查询集。这至少在Django 1.2.3上有效。

class RoomInline(admin.TabularInline):

    model = Room

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):

        field = super(RoomInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

        if db_field.name == 'inside_room':
            if request._obj_ is not None:
                field.queryset = field.queryset.filter(building__exact = request._obj_)  
            else:
                field.queryset = field.queryset.none()

        return field



class BuildingAdmin(admin.ModelAdmin):

    inlines = (RoomInline,)

    def get_form(self, request, obj=None, **kwargs):
        # just save obj reference for future processing in Inline
        request._obj_ = obj
        return super(BuildingAdmin, self).get_form(request, obj, **kwargs)
2020-03-27