Python Django admin在使用get_form()时缺少添加/编辑按钮

Python Django admin在使用get_form()时缺少添加/编辑按钮,python,django,django-forms,django-admin,Python,Django,Django Forms,Django Admin,在ModelAdmin类中重写get_form()方法时,“添加”和“编辑”(加号和铅笔)图标不会出现在管理页面上的任何字段旁边,即使权限正确。当我删除覆盖的get\u form()方法时,图标就会出现。我正在使用表单工厂呈现ModelForm类,以便根据当前用户执行一些queryset筛选,因此我无法在管理中使用form=(表单需要捕获HttpRequest对象) (使用Django 2.1和Python 3.6) admin.py @admin.register(Reservation) c

在ModelAdmin类中重写
get_form()
方法时,“添加”和“编辑”(加号和铅笔)图标不会出现在管理页面上的任何字段旁边,即使权限正确。当我删除覆盖的
get\u form()
方法时,图标就会出现。我正在使用表单工厂呈现ModelForm类,以便根据当前用户执行一些queryset筛选,因此我无法在管理中使用
form=
(表单需要捕获
HttpRequest
对象)

(使用Django 2.1和Python 3.6)

admin.py

@admin.register(Reservation)
class ReservationAdmin(admin.ModelAdmin):
    list_display = ('room', 'check_in_date', 'check_out_date', 'guest', 'reserved_by', 'reserved_on')
    inlines = (RoomChangeInline,)


    fieldsets = ( 
    (None, {
        'fields': (
            ('room', 'guest'),
            ('check_in_date', 'check_out_date'),
            ('adults', 'children'),
            ('subtotal', 'taxes', 'deposit'),
            ('reserved_by', 'reserved_on')
        )
    }),)   

    def get_form(self, request, obj=None, **kwargs):
        return reservation_admin_form_factory(request)
def reservation_admin_form_factory(request):
    class ReservationAdminForm(forms.ModelForm):
        class Meta: 
            model = Reservation
            exclude = []
            widgets = {
                'check_in_date': forms.DateInput(attrs={'type': 'date'}),
                'check_out_date': forms.DateInput(attrs={'type': 'date'})
            }

        """ I have an __init__() method, but even if I remove it 
        the problem remains, so I am not showing it here. """

    return ReservationAdminForm
from django import forms
from django.conf import settings
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
from django.db.models.fields.reverse_related import ManyToOneRel

def reservation_admin_form_factory(request, admin_site):
    class ReservationAdminForm(forms.ModelForm):
        class Meta:
            model = Reservation
            exclude = []

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            rel = ManyToOneRel(Reservation.guest, Guest, 'id')
            self.fields['guest'].widget = RelatedFieldWidgetWrapper(
                 self.fields['guest'].widget, rel, admin_site, 
                     can_change_related=True)
forms.py

@admin.register(Reservation)
class ReservationAdmin(admin.ModelAdmin):
    list_display = ('room', 'check_in_date', 'check_out_date', 'guest', 'reserved_by', 'reserved_on')
    inlines = (RoomChangeInline,)


    fieldsets = ( 
    (None, {
        'fields': (
            ('room', 'guest'),
            ('check_in_date', 'check_out_date'),
            ('adults', 'children'),
            ('subtotal', 'taxes', 'deposit'),
            ('reserved_by', 'reserved_on')
        )
    }),)   

    def get_form(self, request, obj=None, **kwargs):
        return reservation_admin_form_factory(request)
def reservation_admin_form_factory(request):
    class ReservationAdminForm(forms.ModelForm):
        class Meta: 
            model = Reservation
            exclude = []
            widgets = {
                'check_in_date': forms.DateInput(attrs={'type': 'date'}),
                'check_out_date': forms.DateInput(attrs={'type': 'date'})
            }

        """ I have an __init__() method, but even if I remove it 
        the problem remains, so I am not showing it here. """

    return ReservationAdminForm
from django import forms
from django.conf import settings
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
from django.db.models.fields.reverse_related import ManyToOneRel

def reservation_admin_form_factory(request, admin_site):
    class ReservationAdminForm(forms.ModelForm):
        class Meta:
            model = Reservation
            exclude = []

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            rel = ManyToOneRel(Reservation.guest, Guest, 'id')
            self.fields['guest'].widget = RelatedFieldWidgetWrapper(
                 self.fields['guest'].widget, rel, admin_site, 
                     can_change_related=True)

要在覆盖ModelAdmin的
get\u form()
时显示Django admin change\u form页面上的添加/编辑按钮,需要将字段的小部件包装在
RelatedFieldWidgetWrapper
中,如下所示:

forms.py

@admin.register(Reservation)
class ReservationAdmin(admin.ModelAdmin):
    list_display = ('room', 'check_in_date', 'check_out_date', 'guest', 'reserved_by', 'reserved_on')
    inlines = (RoomChangeInline,)


    fieldsets = ( 
    (None, {
        'fields': (
            ('room', 'guest'),
            ('check_in_date', 'check_out_date'),
            ('adults', 'children'),
            ('subtotal', 'taxes', 'deposit'),
            ('reserved_by', 'reserved_on')
        )
    }),)   

    def get_form(self, request, obj=None, **kwargs):
        return reservation_admin_form_factory(request)
def reservation_admin_form_factory(request):
    class ReservationAdminForm(forms.ModelForm):
        class Meta: 
            model = Reservation
            exclude = []
            widgets = {
                'check_in_date': forms.DateInput(attrs={'type': 'date'}),
                'check_out_date': forms.DateInput(attrs={'type': 'date'})
            }

        """ I have an __init__() method, but even if I remove it 
        the problem remains, so I am not showing it here. """

    return ReservationAdminForm
from django import forms
from django.conf import settings
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
from django.db.models.fields.reverse_related import ManyToOneRel

def reservation_admin_form_factory(request, admin_site):
    class ReservationAdminForm(forms.ModelForm):
        class Meta:
            model = Reservation
            exclude = []

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            rel = ManyToOneRel(Reservation.guest, Guest, 'id')
            self.fields['guest'].widget = RelatedFieldWidgetWrapper(
                 self.fields['guest'].widget, rel, admin_site, 
                     can_change_related=True)
请注意,上面使用了表单工厂(
reservation\u admin\u form\u factory
)来捕获
admin\u站点
对象,这是
RelatedFieldWidgetWrapper
所需的

admin.py*

@admin.register(Reservation)
class ReservationAdmin(admin.ModelAdmin):
    list_display = ('check_in_date', 'check_out_date')

    def get_form(self, request, obj=None, **kwargs):
        self.form = reservation_admin_form_factory(request, admin.site)
        return super().get_form(request, obj, **kwargs)

如果您只是在
ReservationAdmin
中说
form=ReservationAdminForm
并删除
get\u form()
方法(而不是使用表单工厂),是否会发生同样的情况,我看到管理员更改表单上出现了预期的按钮。可能原始的
get\u表单
返回一个表单,指向一些HTML字段模板,其中包括这些按钮?谢谢Raydel。根据您的建议,我查看了get_form()的源代码。该方法调用modelform\u factory(),它接受多个参数,关键参数是
formfield\u callback
。因此,我的新代码看起来是这样的(抱歉,无法在注释中获得正确的格式,因此我使用了pastebin):好的,这不起作用。最初,它似乎在工作,正如图标所示,但事实上Django正在完成忽略我的自定义
ModelForm
对象。修复方法是在
RelatedFieldWidgetWrapper
调用中包装字段的小部件(参见答案)。这对我来说几乎是可行的。只是弹出窗口不会打开,而是加载到当前选项卡/页面中。事实上,我正在使用一个修改过的版本作为dajngo管理操作的中间页面,该操作带有一个自定义模板。我还尝试在模板中添加
{{form.media}
,因为我认为弹出窗口是使用JS调用的。但这对我也不起作用。