2012-07-24 68 views
1

我在我的models.py具有一个ForeignKey主体材料一个CarType:过滤ForeignKey的

class BodyMaterial(models.Model): 
    location    = models.ForeignKey('CarType') 
    name     = models.CharField(max_length=255) 

class CarType(models.Model): 
    name     = models.CharField(max_length=255) 
    default_body_material = models.ForeignKey(BodyMaterial, null = True, blank = True, default = "", limit_choices_to={'location__exact': 1}) 

主体材料是在CarType内联在我admin.py:

class BodyMaterial_Inline(admin.StackedInline): 
    model = BodyMaterial 
    extra = 1 

class CarType_Admin(admin.ModelAdmin): 
    inlines = [BodyMaterial_Inline] 

admin.site.register(CarType, CarType_Admin) 

我想过滤default_body_material的ForeignKey以仅显示相关的BodyMaterials(在同一个管理页面上出现/添加的BodyMaterials)。例如,我创建了2个座位的CarType,并在同一个页面中添加了一些BodyMaterials。然后我创建一个SVU CarType和一些其他BodyMaterials。当我回到2个座位的CarType时,我只想在default_body_material的下拉列表中看到相关的BodyMaterials。

我尝试使用id上的limit_choices_to进行过滤。所以我使用post_init来做这件事,因为在运行时确定了对象的ID:

def setID(**kwargs): 
    instance = kwargs.get('instance') 
    default_body_material = instance._meta.get_field_by_name('default_body_material')[0] 
    default_body_material.limit_choices_to = {'location__exact': instance.id} 

post_init.connect(setID, CarType) 

不幸的是,那什么都不做。我错过了什么?有没有一个为什么我的目的过滤ForeignKey(这可能是非常基本的)?

请注意,此问题仅适用于管理界面。

回答

0

只需使用自定义ModelForm

class CarTypeAdminForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(CarTypeAdminForm, self).__init__(*args, **kwargs) 
     # Can't limit it until instance has been saved at least once 
     if self.instance.pk: 
      self.fields['default_body_material'].queryset = \ 
       self.fields['default_body_material'].queryset \ 
        .filter(location=self.instance) 

class CarTypeAdmin(admin.ModelAdmin): 
    form = CarTypeAdminForm 
    ... 
+0

太好了。这工作! – user1549769 2012-07-25 14:45:30

+0

我确实有一个问题。当我运行instance.bodymaterial_set.all()时,即使没有你建议的代码,它也会打印出正确的foregnkeys。我不太熟悉Django,以便了解Django如何在没有明确声明查询集的情况下知道,但它确实如此。我想知道是否有一种更简单的方法可以在不使用queryset的情况下完成上述操作。 – user1549769 2012-07-25 15:02:43

+0

关键是你必须实际存储一个新的过滤的查询集来代替当前查询集的字段。你可以轻松地做self.fields ['default_body_material']。queryset = self.instance.bodymaterial_set.all()'。但是,正如我所做的那样,过滤已分配的查询集更加稳健,因为它会从窗体的任何子类中进行更改等,而使用此代码将会取代它。 – 2012-07-25 15:07:50

0

你想看看重写查询集功能为您在线。