Django:从内联模型管理访问父示例

vohkndzv  于 2022-12-14  发布在  Go
关注(0)|答案(7)|浏览(165)

如何从内联模型管理访问父示例?
我的目标是根据父示例的状态覆盖has_add_permission函数。如果父示例的状态不是1,我不想允许添加子示例。

class ChildInline(admin.TabularInline):
    model = Child
    form = ChildForm

    fields = (
        ...
    )
    extra = 0

    def has_add_permission(self, request):
        # Return True only if the parent has status == 1
        # How to get to the parent instance?
        #return True

class ParentAdmin(admin.ModelAdmin):
    inlines = [ChildInline,]
uajslkp6

uajslkp61#

BaseInlineFormSet具有属性self.instance,该属性是对父对象的引用。
在构造函数中,使用这个示例初始化和过滤queryset,如果需要调整,可以更改构造函数的queryset参数,或者根据需要使用inlineformset_factory设置表单集。

class BaseInlineFormSet(BaseModelFormSet):
    """A formset for child objects related to a parent."""
    def __init__(self, data=None, files=None, instance=None,
                 save_as_new=False, prefix=None, queryset=None, **kwargs):
        if instance is None:
            self.instance = self.fk.remote_field.model()
        else:
            self.instance = instance
        self.save_as_new = save_as_new
        if queryset is None:
            queryset = self.model._default_manager
        if self.instance.pk is not None:
            qs = queryset.filter(**{self.fk.name: self.instance})
        else:
            qs = queryset.none()
        self.unique_fields = {self.fk.name}
        super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs)

请参阅https://docs.djangoproject.com/en/3.2/_modules/django/forms/models/
如果您从这里扩展,请确保在访问self.instance之前运行super().__init__()

kfgdxczn

kfgdxczn2#

您只需要添加obj参数并检查父模型状态

class ChildInline(admin.TabularInline):
   model = Child
   form = ChildForm

   fields = (
    ...
    )
   extra = 0
   #You only need to add obj parameter 
   #obj is parent object now you can easily check parent object status
   def has_add_permission(self, request, obj=None):
        if obj.status == 1:
           return True
        else:
           return False

   class ParentAdmin(admin.ModelAdmin):
         inlines = [ChildInline,]
prdp8dxp

prdp8dxp3#

如果路径中不需要数字,也可以使用re module从请求路径中检索它。
例如:

import re

def get_queryset(self, request):
    instance_id = re.sub(r"\D+", "", request.path)

def get_parent_object_from_request(self, request):
    instance_id = re.sub(r"\D+", "", request.path)
muk1a3rh

muk1a3rh4#

将以下内容放置在父管理模型上,以便父模型示例可用于父模型下的任何内联对象:

def get_form(self, request, obj=None, **kwargs):
    request._obj = obj
    return super().get_form(request, obj, **kwargs)

然后,在行内(以customers字段为例):

def formfield_for_manytomany(self, db_field, request, **kwargs):
    if db_field.name == "customers":
        if request._obj is not None:
            kwargs["queryset"] = request._obj.customers
        else:
            kwargs["queryset"] = Customer.objects.none()            
    return super().formfield_for_manytomany(db_field, request, **kwargs)
nlejzf6q

nlejzf6q5#

Django〈2.0答案:

使用Django的Request对象(您可以访问)来获取request.path_info,然后从resolve匹配的参数中获取PK。

from django.contrib import admin
from django.core.urlresolvers import resolve
from app.models import YourParentModel, YourInlineModel

class YourInlineModelInline(admin.StackedInline):
    model = YourInlineModel

    def get_parent_object_from_request(self, request):
        """
        Returns the parent object from the request or None.

        Note that this only works for Inlines, because the `parent_model`
        is not available in the regular admin.ModelAdmin as an attribute.
        """
        resolved = resolve(request.path_info)
        if resolved.args:
            return self.parent_model.objects.get(pk=resolved.args[0])
        return None

    def has_add_permission(self, request):
        parent = self.get_parent_object_from_request(request)

        # Validate that the parent status is active (1)
        if parent:
            return parent.status == 1

        # No parent - return original has_add_permission() check
        return super(YourInlineModelInline, self).has_add_permission(request)

@admin.register(YourParentModel)
class YourParentModelAdmin(admin.ModelAdmin):
    inlines = [YourInlineModelInline]

Django〉= 2.0答案:

Mark Chackerian获得以下更新:
使用Django的Request对象(您可以访问它)来检索request.path_info,然后从resolve匹配中的参数中检索PK。例如:

from django.contrib import admin
from django.urls import resolve
from app.models import YourParentModel, YourInlineModel

class YourInlineModelInline(admin.StackedInline):
    model = YourInlineModel

    def get_parent_object_from_request(self, request):
        """
        Returns the parent object from the request or None.

        Note that this only works for Inlines, because the `parent_model`
        is not available in the regular admin.ModelAdmin as an attribute.
        """
        resolved = resolve(request.path_info)
        if resolved.args:
            return self.parent_model.objects.get(pk=resolved.args[0])
        return None

    def has_add_permission(self, request):
        parent = self.get_parent_object_from_request(request)

        # Validate that the parent status is active (1)
        if parent:
            return parent.status == 1

        # No parent - return original has_add_permission() check
        return super(YourInlineModelInline, self).has_add_permission(request)

@admin.register(YourParentModel)
class YourParentModelAdmin(admin.ModelAdmin):
    inlines = [YourInlineModelInline]
b5buobof

b5buobof6#

我认为这是一种在内联模型中获取父示例的更简洁的方法。

class ChildInline(admin.TabularInline):
    model = Child
    form = ChildForm

    fields = (...)
    extra = 0

    def get_formset(self, request, obj=None, **kwargs):
        self.parent_obj = obj
        return super(ChildInline, self).get_formset(request, obj, **kwargs)

    def has_add_permission(self, request):
        # Return True only if the parent has status == 1
        return self.parent_obj.status == 1

class ParentAdmin(admin.ModelAdmin):
    inlines = [ChildInline, ]
gpfsuwkq

gpfsuwkq7#

我尝试了解决方案的迈克尔B,但不为我工作,我不得不使用这个代替(一个小修改,使用kwargs):

def get_parent_object_from_request(self, request):
        """
        Returns the parent object from the request or None.

        Note that this only works for Inlines, because the `parent_model`
        is not available in the regular admin.ModelAdmin as an attribute.
        """
        resolved = resolve(request.path_info)
        if resolved.kwargs:
            return self.parent_model.objects.get(pk=resolved.kwargs["object_id"])
        return None

相关问题