Django:根据相关对象限制外键选择
Django: Limiting foreign key choices based on related object
我不确定解释我需要什么的正确术语,我认为最简单的方法是举例。
我有以下模型 - 一个公司和一个软件资产。
class Company(models.Model):
name = models.CharField(max_length=200)
class SoftwareAsset(models.Model):
name = models.CharField(max_length=200)
然后我想将各个公司映射到他们拥有的软件资产。例如,大多数公司可能拥有 'Microsoft Office' 资产,但只有少数公司可能拥有 'Adobe Photoshop'。为此,我使用了 join table(同样,我不确定这是否是正确的术语,或者更重要的是,是否是处理此问题的正确方法)。
class CompanyAssets(models.Model):
company = models.ForeignKey(Company)
asset = models.ForeignKey(SoftwareAsset)
然后我需要定义员工以及他们受雇于的公司:
class Employee(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company)
最后,我需要定义每个员工可以访问哪些应用程序:
class EmployeeSoftware(models.Model):
employee = models.ForeignKey(Employee)
asset = models.ForeignKey(SoftwareAsset)
现在,一切正常,只有一个例外。当我在管理界面中时,我将记录添加到 EmployeeSoftware table,我能够 select 公司不拥有的 SoftwareAssets。 SoftwareAsset 下拉列表允许我 select SoftwareAsset table 中定义的任何软件包。我想将其限制为公司拥有的资产,如 CompanyAssets 中所定义。
我的偏好是在模型中执行此操作 - 如果可以防止向员工分配公司在数据库级别不拥有的资产,但从我读过的资料来看,这是不可能的。我搞砸了 ForeignKey.limit_choices_to 论点,但运气不佳。
我尝试使用 formfield_for_foreignkey:
为 EmployeeSoftwareAdmin class 编辑 admin.py
class EmployeeSoftwareAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'asset':
kwargs['queryset'] = CompanyAssets.objects.filter(company__name="XXXXX") #works but is obviously static
return super(EmployeeSoftwareAdmin,self).formfield_for_foreignkey(db_field,request,**kwargs)
我无法找到一种方法来访问 formfield_for_foreignkey 方法中的任何对象,从而允许进行正确的过滤。
将 SoftwareAsset FK 授予公司。
class SoftwareAsset(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company)
所以一家公司可以拥有很多软件资产。现在您可以轻松过滤自定义模型中的软件资产。
EmployeeSoftwareForm(forms.ModelForm):
class Meta:
model = EmployeeSoftware
def __init(self, *args, **kwargs):
super(EmployeeSoftwareForm, self).__init__(*args, **kwargs)
if 'instance' in kwargs:
self.fields['assets'].queryset = SoftwareAsset.objects.filter(company = kwargs['instance'].employee.company)
最终为 EmployeeSoftware 模型管理员使用此自定义表单:
class EmployeeSoftwareAdmin(admin.ModelAdmin):
form = EmployeeSoftwareForm
这消除了对 CompanyAsset 模型的需求。
UPDATE:好的,您希望 EmployeeSoftware 的每个新实例都知道它可以根据员工公司拥有哪些资产。但是因为在 select 之前你不知道你的员工是什么,所以不可能在 form init 上做。您必须使用 javascript 根据员工选择过滤 select。像这样(使用 JQuery):
$("#employee").change(function(){
$.post(<your assets select url>, $("employeeform").serialize(), function (data) {
//populate your returned JSON into the asset select
}, 'json');
})
显然,url 您的 post 会根据 selected 员工过滤资产,这应该很简单。
我不确定解释我需要什么的正确术语,我认为最简单的方法是举例。
我有以下模型 - 一个公司和一个软件资产。
class Company(models.Model):
name = models.CharField(max_length=200)
class SoftwareAsset(models.Model):
name = models.CharField(max_length=200)
然后我想将各个公司映射到他们拥有的软件资产。例如,大多数公司可能拥有 'Microsoft Office' 资产,但只有少数公司可能拥有 'Adobe Photoshop'。为此,我使用了 join table(同样,我不确定这是否是正确的术语,或者更重要的是,是否是处理此问题的正确方法)。
class CompanyAssets(models.Model):
company = models.ForeignKey(Company)
asset = models.ForeignKey(SoftwareAsset)
然后我需要定义员工以及他们受雇于的公司:
class Employee(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company)
最后,我需要定义每个员工可以访问哪些应用程序:
class EmployeeSoftware(models.Model):
employee = models.ForeignKey(Employee)
asset = models.ForeignKey(SoftwareAsset)
现在,一切正常,只有一个例外。当我在管理界面中时,我将记录添加到 EmployeeSoftware table,我能够 select 公司不拥有的 SoftwareAssets。 SoftwareAsset 下拉列表允许我 select SoftwareAsset table 中定义的任何软件包。我想将其限制为公司拥有的资产,如 CompanyAssets 中所定义。
我的偏好是在模型中执行此操作 - 如果可以防止向员工分配公司在数据库级别不拥有的资产,但从我读过的资料来看,这是不可能的。我搞砸了 ForeignKey.limit_choices_to 论点,但运气不佳。
我尝试使用 formfield_for_foreignkey:
为 EmployeeSoftwareAdmin class 编辑 admin.pyclass EmployeeSoftwareAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'asset':
kwargs['queryset'] = CompanyAssets.objects.filter(company__name="XXXXX") #works but is obviously static
return super(EmployeeSoftwareAdmin,self).formfield_for_foreignkey(db_field,request,**kwargs)
我无法找到一种方法来访问 formfield_for_foreignkey 方法中的任何对象,从而允许进行正确的过滤。
将 SoftwareAsset FK 授予公司。
class SoftwareAsset(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company)
所以一家公司可以拥有很多软件资产。现在您可以轻松过滤自定义模型中的软件资产。
EmployeeSoftwareForm(forms.ModelForm):
class Meta:
model = EmployeeSoftware
def __init(self, *args, **kwargs):
super(EmployeeSoftwareForm, self).__init__(*args, **kwargs)
if 'instance' in kwargs:
self.fields['assets'].queryset = SoftwareAsset.objects.filter(company = kwargs['instance'].employee.company)
最终为 EmployeeSoftware 模型管理员使用此自定义表单:
class EmployeeSoftwareAdmin(admin.ModelAdmin):
form = EmployeeSoftwareForm
这消除了对 CompanyAsset 模型的需求。
UPDATE:好的,您希望 EmployeeSoftware 的每个新实例都知道它可以根据员工公司拥有哪些资产。但是因为在 select 之前你不知道你的员工是什么,所以不可能在 form init 上做。您必须使用 javascript 根据员工选择过滤 select。像这样(使用 JQuery):
$("#employee").change(function(){
$.post(<your assets select url>, $("employeeform").serialize(), function (data) {
//populate your returned JSON into the asset select
}, 'json');
})
显然,url 您的 post 会根据 selected 员工过滤资产,这应该很简单。