首页 > 解决方案 > How do I restrict foreign keys choices in admin formset to related objects only in django

问题描述

How do I limit choices of a ForeignKeyField of an InlineForm in Django Admin, depended on the selected object in the AdminForm.

The problem is that InlineForm does not know anything about the object from the related Admin Form.

标签: djangodjango-formsdjango-admin

解决方案


您必须将父对象从 InlineAdmin 传递到 FormSet 到实际的 Form。我花了很长时间才弄清楚这一点。在下面的示例中CalibrationCertificateData与SensorCategory 相关CalibrationCertificate,我只想展示Quantities与 SensorCategory 相关的。

from django.contrib import admin
from django.forms import ModelForm, BaseInlineFormSet
from src.admin import site_wm
from . import models
from quantity_management.models import QuantitySensor

# Register your models here.
site_wm.register(models.CalibrationInstitute, site=site_wm)


class CertDataAdminForm(ModelForm):
    class Meta:
        model = models.CalibrationCertificateData
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        """
        Make sure that we only show the Quantites that are related to the selected Cert>Sensor>Category
        """
        self.parent_obj = None
        if 'parent_obj' in kwargs:
            self.parent_obj = kwargs['parent_obj']
            del kwargs['parent_obj']
        super().__init__(*args, **kwargs)
        if self.parent_obj:
            # Do the actual filtering according to the parent object
            category_id = self.parent_obj.Sensor.Category_id
            self.fields['Quantity'].queryset = QuantitySensor.objects.filter(Sensor_id=category_id)


class CertDataAdminFormSet(BaseInlineFormSet):
    form = CertDataAdminForm

    def get_form_kwargs(self, index):
        """
        Make sure the form knows about the parent object
        """
        kwargs = super().get_form_kwargs(index)
        if hasattr(self, 'parent_obj') and self.parent_obj:
            kwargs['parent_obj'] = self.parent_obj
        return kwargs


class CalibrationDataAdmin(admin.StackedInline):
    model = models.CalibrationCertificateData
    extra = 0
    form = CertDataAdminForm
    formset = CertDataAdminFormSet

    def get_formset(self, request, obj=None, **kwargs):
        """
        give the formset the current object, so it can limit the selection choices according to it
        """
        formset = super().get_formset(request, obj, **kwargs)
        if formset is not None:
            formset.parent_obj = obj
        return formset

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        print(self.parent_model)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(models.CalibrationCertificate, site=site_wm)
class CalibrationCertificateAdmin(admin.ModelAdmin):
    inlines = (
        CalibrationDataAdmin,
    )

推荐阅读