получение родительского объекта в Django Admin Inline

Основной текст заметки

первый способ

самый красивый способ - это из get_formset в который передается родительский объект

def get_formset(self, request, obj=None, **kwargs):

    # можно просто сохранить 
    self.instance = obj

    # а можно подменить обработчик 'formfield_callback', добавляя в его вызов параметр obj
    kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)

    return super(FosterParentsInlineAdmin, self).get_formset(request, obj, **kwargs)

def formfield_for_dbfield(self, db_field, **kwargs):
    print('self.instance', self.instance)

    #теперь можно получить объект так
    #запоминание кажется более универсальным
    form_obj = self.instance

    # или так
    form_obj = kwargs.pop('obj', None)

    formfield = super(FosterParentsInlineAdmin, self).formfield_for_dbfield(db_field, **kwargs)

    # и использовать его "по назначению"
    if db_field.name == "parent" and form_obj:
        formfield.queryset = form_obj.possible_parents_qs()
    return formfield

второй способ который я нашел - это парсить запрос

def get_parent_object_id_from_request(self, request):
    """это  функция которая вытаскивает (и кеширует)  id объекта"""
    if self.parent_object_id:
        return self.parent_object_id
    resolved = resolve(request.path_info)
    if resolved:
        self.parent_object_id = resolved.kwargs.get('object_id')
        return self.parent_object_id
    return None

def get_parent_object_from_request(self, request):
    """это  функция которая вытаскивает (и кеширует)  уже сам объект"""
    if self.parent_object:
        return self.parent_object
    self.get_parent_object_id_from_request(request)
    if self.parent_object_id:
        self.parent_object = self.parent_model.objects.get(pk=self.parent_object_id)
        return self.parent_object
    return None

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == "parent":
        # вот тут я получаю id объекта который мне нужен
        self.get_parent_object_id_from_request(request)
        if self.parent_object_id:
            kwargs["queryset"] = Category.objects.exclude(pk=self.parent_object_id)
    return super(FosterParentsInlineAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Программный код
вот пример класса

class FosterParentsInlineAdmin(SortableStackedInline):
    model = Category.foster_parents.through
    fk_name = "child"
    can_delete = True
    extra = 1
    formset = FosterParentsInlineFormSet

    # def __init__(self, *args, **kwargs):
    #     super(FosterParentsInlineAdmin, self).__init__(*args, **kwargs)
    #     self.parent_object_id = None
    #     self.parent_object = None
    #
    # #
    # def formfield_for_foreignkey(self, db_field, request, **kwargs):
    #     if db_field.name == "parent":
    #         self.get_parent_object_id_from_request(request)
    #         if self.parent_object_id:
    #             kwargs["queryset"] = Category.objects.exclude(pk=self.parent_object_id)
    #     return super(FosterParentsInlineAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
    #
    #
    # def get_parent_object_id_from_request(self, request):
    #     if self.parent_object_id:
    #         return self.parent_object_id
    #     resolved = resolve(request.path_info)
    #     if resolved:
    #         self.parent_object_id = resolved.kwargs.get('object_id')
    #         return self.parent_object_id
    #     return None
    #
    #
    # def get_parent_object_from_request(self, request):
    #     if self.parent_object:
    #         return self.parent_object
    #     self.get_parent_object_id_from_request(request)
    #     if self.parent_object_id:
    #         self.parent_object = self.parent_model.objects.get(pk=self.parent_object_id)
    #         return self.parent_object
    #     return None


    def get_formset(self, request, obj=None, **kwargs):
        print('get_formset!!!!')
        self.instance = obj
        kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
        return super(FosterParentsInlineAdmin, self).get_formset(request, obj, **kwargs)

    def formfield_for_dbfield(self, db_field, **kwargs):
        print('---- formfield_for_dbfield db_field=',db_field)
        form_obj = kwargs.pop('obj', None)
        print('form_obj_v1',form_obj)
        print('form_obj_v2', self.instance)
        formfield = super(FosterParentsInlineAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == "parent" and form_obj:
            formfield.queryset = form_obj.possible_parents_qs()
        return formfield

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        print('---- formfield_for_foreignkey db_field=',db_field)
        form_obj = kwargs.pop('obj', None)
        print('form_obj_v1',form_obj)
        print('form_obj_v2', self.instance)
        return super(FosterParentsInlineAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

#формирует такой результат

formfield_for_foreignkey db_field store.Category.parent
get_field_queryset db_field store.Category.parent
get_formset!!!!
get_formset!!!!
---- formfield_for_dbfield db_field= store.FosterParentPivot.id
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.child
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.child
form_obj_v1 None
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.parent
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.parent
form_obj_v1 None
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.child
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.child
form_obj_v1 None
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.parent
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.parent
form_obj_v1 None
form_obj_v2 третья
FosterParentsInlineFormSet.instance третья
get_formset!!!!
---- formfield_for_dbfield db_field= store.FosterParentPivot.id
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.child
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.child
form_obj_v1 None
form_obj_v2 третья
---- formfield_for_dbfield db_field= store.FosterParentPivot.parent
form_obj_v1 третья
form_obj_v2 третья
---- formfield_for_foreignkey db_field= store.FosterParentPivot.parent
form_obj_v1 None
form_obj_v2 третья

Заметка написана: 27.05.2020

Теги заметки: Django, Django admin