Как получить текущий экземпляр модели из inlineadmin в Django
Я использую formfield_for_manytomany
, указанный в документации django.
Но внутри этой функции мне нужно отредактировать текущий родительский объект.
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)
Как я могу получить редактируемого человека?
Ответы
Ответ 1
Если 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)
Ответ 2
Чтобы получить доступ к экземпляру модели родительского элемента модели InlineModelAdmin ModelAdmin, я использовал этот хак в прошлом:
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)
Ответ 3
Я обнаружил более чистый способ без всякого взлома в get_formset()
/get_formsets()
/formfield_for_dbfield()
. Используйте объект Django Request (который у вас есть) для получения request.path_info
, затем извлеките 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]