Django: доступ к экземпляру модели из ModelAdmin?

у меня есть модель для заказов в приложении webshop с автоматически увеличивающимся первичным ключом и внешним ключом к себе, так как заказы могут быть разделены на несколько заказов, но отношение к исходному заказу должно поддерживаться.

class Order(models.Model):
    ordernumber = models.AutoField(primary_key=True)
    parent_order = models.ForeignKey('self', null=True, blank=True, related_name='child_orders')
    # .. other fields not relevant here

Я зарегистрировал класс OrderAdmin для сайта администратора. Для подробного просмотра я включил parent_order на . Конечно, по умолчанию в этом списке перечислены все заказы в поле выбора, но это не то, что нужно поведение. Вместо этого для заказов, которые не имеют родительского заказа (т. е. не были разделены от другого заказа;parent_order равно NULL / None), заказы не должны отображаться. Для заказов, которые были разделены, это должно отображать только один родительский заказ.

существует довольно новый метод ModelAdmin,formfield_for_foreignkey, это кажется идеальным для этого, так как queryset может быть отфильтрован внутри него. Представьте, что мы смотрим на подробный вид заказа № 11234, который был разделен от заказа №11208. Код ниже

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == 'parent_order':
        # kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=11234)
        return db_field.formfield(**kwargs)
    return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

строка комментариев работает при запуске в оболочке Python, возвращая одноэлементный набор запросов, содержащий заказ #11208 для #11234 и все другие заказы, которые могли быть разделены от него.

конечно, мы не можем жестко есть номер заказа. Нам нужна ссылка на ordernumber поле экземпляра заказа, на странице сведений о котором мы смотрим. Вот так:

kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=?????)

Я не нашел рабочего способа заменить ????? со ссылкой на экземпляр" текущего " заказа, и я копнул довольно глубоко. self внутри formfield_for_foreignkey относится к экземпляру ModelAdmin, и хотя это имеет model атрибут, это не экземпляр модели заказа (это ссылка ModelBase; self.model () возвращает экземпляр, но его порядковый номер равен None).

одним из решений может быть вытащить номер заказа из запроса.путь (/admin/orders/order/ 11234/), но это действительно уродливо. Я действительно хочу, чтобы был лучший способ.

3 ответов


Я думаю, вам может потребоваться подойти к этому немного по - другому-путем изменения ModelForm, а не класса admin. Что-то вроде этого:--2-->

class OrderForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(OrderForm, self).__init__(*args, **kwargs)
        self.fields['parent_order'].queryset = Order.objects.filter(
            child_orders__ordernumber__exact=self.instance.pk)

class OrderAdmin(admin.ModelAdmin):
    form = OrderForm

я смоделировал свой встроенный класс таким образом. Это немного уродливо, как он получает идентификатор родительской формы для фильтрации встроенных данных, но он работает. Он фильтрует единицы по компаниям из родительской формы.

оригинальная концепция объясняется здесь http://www.stereoplex.com/blog/filtering-dropdown-lists-in-the-django-admin

class CompanyOccupationInline(admin.TabularInline):

    model = Occupation
    # max_num = 1
    extra = 0
    can_delete = False
    formset = RequiredInlineFormSet

    def formfield_for_dbfield(self, field, **kwargs):

        if field.name == 'unit':
            parent_company = self.get_object(kwargs['request'], Company)
            units = Unit.objects.filter(company=parent_company)
            return forms.ModelChoiceField(queryset=units)
        return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs)

    def get_object(self, request, model):
        object_id = resolve(request.path).args[0]
        try:
            object_id = int(object_id)
        except ValueError:
            return None
        return model.objects.get(pk=object_id)

приведенный выше ответ от Эрвина Джулиуса работал для меня, за исключением того, что я обнаружил, что имя "get_object" конфликтует с функцией Django, поэтому назовите функцию "my_get_object".

class CompanyOccupationInline(admin.TabularInline):

    model = Occupation
    # max_num = 1
    extra = 0
    can_delete = False
    formset = RequiredInlineFormSet

    def formfield_for_dbfield(self, field, **kwargs):

        if field.name == 'unit':
            parent_company = self.my_get_object(kwargs['request'], Company)
            units = Unit.objects.filter(company=parent_company)
            return forms.ModelChoiceField(queryset=units)
        return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs)

    def my_get_object(self, request, model):
        object_id = request.META['PATH_INFO'].strip('/').split('/')[-1]
        try:
            object_id = int(object_id)
        except ValueError:
            return None
        return model.objects.get(pk=object_id)

Он сказал мне не " отвечать "на ответы других, но мне пока не разрешено" отвечать", и я искал это некоторое время, поэтому надеюсь, что это будет полезно для других. Мне также не разрешено поднимать голос, или я бы полностью!