22

我正在使用django 文档formfield_for_manytomany中给出的内容。但是在该函数中,我需要获取正在编辑的当前父对象。

def formfield_for_manytomany(self, db_field, request, **kwargs):
    if db_field.name == "car":
        kwargs["queryset"] = Cars.objects.filter(owner=person)
    return super(myModel, self).formfield_for_manytomany(db_field, request, **kwargs)

我怎样才能得到正在编辑的人?

4

3 回答 3

24

如果person无法轻松获取request,您可能需要通过覆盖ModelAdmin.get_form()或手动传递它InlineModelAdmin.get_formset()

from functools import partial

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
        return super(MyModelAdmin, self).get_form(request, obj, **kwargs)

    def formfield_for_dbfield(self, db_field, **kwargs):
        person = kwargs.pop('obj', None)
        formfield = super(MyModelAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == "car" and person:
            formfield.queryset = Cars.objects.filter(owner=person)
        return formfield 

# or its inline
class MyInlineModelAdmin(admin.StackedInline):
    def get_formset(self, request, obj=None, **kwargs):
        kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
        return super(MyInlineModelAdmin, self).get_formset(request, obj, **kwargs)

    def formfield_for_dbfield(self, db_field, **kwargs):
        person = kwargs.pop('obj', None)
        formfield = super(MyInlineModelAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == "car" and person:
            formfield.queryset = Cars.objects.filter(owner=person)
        return formfield 

或者

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
        return super(MyModelAdmin, self).get_form(request, obj, **kwargs)

    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name != "car":
            kwargs.pop('obj', None)
        return super(MyModelAdmin, self).formfield_for_dbfield(db_field, **kwargs)

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        person = kwargs.pop('obj', None)
        if db_field.name == "car" and person:
            kwargs['queryset'] = Cars.objects.filter(owner=person)
        return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
于 2013-02-19T06:38:29.977 回答
4

为了访问 InlineModelAdmin 的父 ModelAdmin 的模型实例,我过去使用过这个 hack:

class PersonAdmin(ModelAdmin):
    def get_formsets(self, request, obj=None, *args, **kwargs):
        for inline in self.inline_instances:
            inline._parent_instance = obj
            yield inline.get_formset(request, obj)

class CarInline(TabularInline):
    _parent_instance = None

    def get_formset(self, *args, **kwargs):
        def formfield_callback(field, **kwargs):
            formfield = field.formfield(**kwargs)
            if field.name == 'car':
                formfield.queryset = Cars.objects.filter(owner=self._parent_instance)
            return formfield

        if self._parent_instance is not None:
            kwargs['formfield_callback'] = formfield_callback
        return super(CarInline, self).get_formset(*args,
                                                                 **kwargs)
于 2014-06-26T10:19:44.320 回答
4

我发现了一种更简洁的方法,而无需在get_formset()/ get_formsets()/中进行所有黑客攻击formfield_for_dbfield()。使用 Django 的 Request 对象(您有权访问)来检索,然后从匹配中request.path_info的 args 检索 PK 。resolve例子:

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)
        if parent and parent.is_active is True:
            return False
        return super(YourInlineModelInline, self).has_add_permission(request)

    def get_formset(self, request, *args, **kwargs):
        """
        Using the get_formset example from above to override the QuerySet.
        """
        def formfield_callback(field, **kwargs):
            formfield = field.formfield(**kwargs)
            if field.name == 'car':
                formfield.queryset = self.parent_model.objects.filter(
                    owner=self.get_parent_object_from_request(request)
                )
            return formfield

        if self.get_parent_object_from_request(request) is not None:
            kwargs['formfield_callback'] = formfield_callback

        return super(YourInlineModelInline, self).get_formset(*args, **kwargs)


@admin.register(YourParentModel)
class YourParentModelAdmin(admin.ModelAdmin):
    inlines = [YourInlineModelInline]
于 2016-12-09T16:07:21.240 回答