我如何将管理员表单集中的外键选择限制为仅在Django中的相关对象

时间:2019-02-08 23:26:51

标签: django django-forms django-admin

如何根据AdminForm中的选定对象来限制Django Admin中InlineForm的ForeignKeyField的选择。

问题是InlineForm对相关的管理表单不了解有关该对象的任何信息。

1 个答案:

答案 0 :(得分:0)

您必须将父对象从InlineAdmin传递到FormSet,再传递给实际的Form。花了我好一会儿才知道。 在下面的示例中,CalibrationCertificateDataCalibrationCertificate有关,我只想显示与SensorCategory相关的Quantities

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,
    )