python - Django:根据相关对象限制外键选择

标签 python django foreign-keys

我不确定正确的术语来解释我需要什么,我认为最简单的方法是通过示例。

我有以下模型 - 一家公司和一项软件 Assets 。

class Company(models.Model):
    name = models.CharField(max_length=200)

class SoftwareAsset(models.Model):
    name = models.CharField(max_length=200)

然后,我想将各个公司映射到他们拥有的软件 Assets 。例如,大多数公司可能拥有“Microsoft Office” Assets ,但只有少数公司可能拥有“Adobe Photoshop”。我为此使用连接表(同样,我不确定这是否是正确的术语,或更重要的是,是否是正确的方法)。

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)

现在,除了一个异常(exception),所有这些都运行良好。当我在管理界面中向 EmployeeSoftware 表添加记录时,我可以选择公司不拥有的软件 Assets 。 SoftwareAsset 下拉列表允许我选择 SoftwareAsset 表中定义的任何软件包。我想将其限制为公司拥有的 Assets (如 CompanyAssets 中所定义)。

我的偏好是在模型中执行此操作 - 如果可以防止在数据库级别为员工分配公司不拥有的 Assets ,但从我所做的阅读来看,这是不可能的。我搞乱了ForeignKey.limit_choices_to 参数,但运气不佳。

我尝试使用 formfield_for_foreignkey 编辑 EmployeeSoftwareAdmin 类的 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)

因此,一家公司可以拥有许多软件 Assets 。现在,您可以轻松过滤自定义模型表单中的软件 Assets 。

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 模型的需要。

更新:好的,您希望 EmployeeSoftware 的每个新实例都知道它可以根据员工公司拥有哪些 Assets 。但是因为在选择员工之前你不知道它是什么,所以不可能在表单初始化上执行此操作。您必须使用 javascript 根据员工选择来过滤选择。像这样的东西(使用 JQuery):

$("#employee").change(function(){

    $.post(<your assets select url>, $("employeeform").serialize(), function (data) {
    //populate your returned JSON into the asset select
}, 'json');

})

显然,您的帖子转到的网址会根据所选员工过滤 Assets ,这应该很简单。

关于python - Django:根据相关对象限制外键选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30533948/

相关文章:

sql - 如果约束失败,则插入值或忽略行

mysql - 我们可以为一个外键引用两个不同的表吗?

python - Tensorflow 多变量逻辑回归不起作用

Python Celery Q 任务状态始终待处理或成功

Django 1.6 A.objects.all().order_by( ['field' ]) 如果 'field' 是模型中的默认顺序,django 会做什么?

python - 计算相关查询集中外键的出现次数

MySQL:在单个记录上选择多个外键字段

python - sklearn 中的 RFECV,来自 grid_scores_ 的分数

python - 使用 Ansible Python API,我如何才能访问我的代码中的任务级输出?

python - 如何从 python 数组访问 C 结构