在管理员的内联表单中限制选择中的外键选择 [英] Limit foreign key choices in select in an inline form in admin
问题描述
模型的逻辑是:
- 一个
Building
有很多Rooms
- 一个
Room
可能在另一个Room
内(例如一个壁橱——ForeignKey on 'self') - 一个
Room
只能在同一个建筑物内的另一个Room
内(这是棘手的部分)
这是我的代码:
#spaces/models.py从 django.db 导入模型类建筑(模型.模型):名称=models.CharField(max_length=32)def __unicode__(self):返回 self.name教室(模型.模型):number=models.CharField(max_length=8)建筑=models.ForeignKey(建筑)inside_room=models.ForeignKey('self',blank=True,null=True)def __unicode__(self):返回self.number
和:
#spaces/admin.py从 ex.spaces.models 导入建筑物,房间从 django.contrib 导入管理员类 RoomAdmin(admin.ModelAdmin):经过类 RoomInline(admin.TabularInline):模型 = 房间额外 = 2类 BuildingAdmin(admin.ModelAdmin):内联=[房间内联]admin.site.register(建筑物,建筑物管理员)admin.site.register(房间)
内联将仅显示当前建筑物中的房间(这是我想要的).但是,问题在于对于 inside_room
下拉菜单,它会显示 Rooms 表中的所有房间(包括其他建筑物中的房间).
在rooms
的内联中,我需要将inside_room
选择限制为仅在当前building<中的
rooms
/code>(当前正在由主 BuildingAdmin
表单更改的建筑记录).
我无法在模型中使用 limit_choices_to
找到一种方法,也无法弄清楚如何正确覆盖管理员的内联表单集(我觉得我应该以某种方式创建一个自定义内联表单,将主表单的 building_id 传递给自定义内联表单,然后基于此限制字段选择的查询集 - 但我无法理解如何去做).>
也许这对于管理站点来说太复杂了,但它似乎是一种普遍有用的东西......
使用请求实例作为 obj 的临时容器.重写的内联方法 formfield_for_foreignkey修改查询集.这至少适用于 django 1.2.3.
class RoomInline(admin.TabularInline):模型 = 房间def formfield_for_foreignkey(self, db_field, request=None, **kwargs):field = super(RoomInline, self).formfield_for_foreignkey(db_field, request, **kwargs)如果 db_field.name == 'inside_room':如果 request._obj_ 不是 None:field.queryset = field.queryset.filter(building__exact = request._obj_)别的:field.queryset = field.queryset.none()返回字段类 BuildingAdmin(admin.ModelAdmin):内联 = (RoomInline,)def get_form(self, request, obj=None, **kwargs):# 只保存 obj 引用以供将来在 Inline 中处理request._obj_ = obj返回 super(BuildingAdmin, self).get_form(request, obj, **kwargs)
The logic is of the model is:
- A
Building
has manyRooms
- A
Room
may be inside anotherRoom
(a closet, for instance--ForeignKey on 'self') - A
Room
can only be inside anotherRoom
in the same building (this is the tricky part)
Here's the code I have:
#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
and:
#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)
The inline will display only rooms in the current building (which is what I want). The problem, though, is that for the inside_room
drop down, it displays all of the rooms in the Rooms table (including those in other buildings).
In the inline of rooms
, I need to limit the inside_room
choices to only rooms
which are in the current building
(the building record currently being altered by the main BuildingAdmin
form).
I can't figure out a way to do it with either a limit_choices_to
in the model, nor can I figure out how exactly to override the admin's inline formset properly (I feel like I should be somehow create a custom inline form, pass the building_id of the main form to the custom inline, then limit the queryset for the field's choices based on that--but I just can't wrap my head around how to do it).
Maybe this is too complex for the admin site, but it seems like something that would be generally useful...
Used request instance as temporary container for obj. Overrided Inline method formfield_for_foreignkey to modify queryset. This works at least on 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)
这篇关于在管理员的内联表单中限制选择中的外键选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!