如何在Django管理页面(在formfield_for_foreignkey中)中获取实际的对象ID?

dy2hfwbg  于 2023-01-21  发布在  Go
关注(0)|答案(8)|浏览(719)

我已经使用以下代码解决了获取正在编辑的对象id的问题:

class CompanyUserInline(admin.StackedInline):
    """
    Defines tabular rules for editing company users direct in company admin
    """
    model = CompanyUser

    def formfield_for_foreignkey(self, db_field, request, **kwargs):

        if db_field.name == "user":
            users = User.objects.filter( Q(is_superuser=False) )
            query = Q()
            for u in users:
                aux = CompanyUser.objects.filter(user=u)
                if aux.count() == 0:
                    query |= Q(pk=u.id)

            try:
                cpu = CompanyUser.objects.filter(company__id=int(request.path.split('/')[4]))
                for p in cpu:
                    query |= Q(pk=p.user.id)
            except:
                pass

            kwargs["queryset"] = User.objects.filter(query).order_by('username')

        return super(CompanyUserInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

但是,int(request.path.split('/')[4]) 真的很难看。我想知道我是如何从Django AdminModel中得到id的。我确信它就在里面的某个地方,有人知道吗?
先谢谢你!D级

pgpifvop

pgpifvop1#

经过一番挖掘,我们能够获取传递给admin视图的参数(在django admin的www.example.com解析之后urls.py),并使用该参数(self_pub_id)获取对象:

class PublicationAdmin(admin.ModelAdmin):

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "authors":
            #this line below got the proper primary key for our object of interest
            self_pub_id = request.resolver_match.args[0]

            #then we did some stuff you don't care about
            pub = Publication.objects.get(id=self_pub_id)
            kwargs["queryset"] = pub.authors.all()
        return super(PublicationAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

一个更优雅的解决方案是使用已接受的答案建议并利用get_form ModelAdmin成员函数。

class ProfileAdmin(admin.ModelAdmin):
    my_id_for_formfield = None
    def get_form(self, request, obj=None, **kwargs):
        if obj:
            self.my_id_for_formfield = obj.id
        return super(ProfileAdmin, self).get_form(request, obj, **kwargs)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "person":
            kwargs["queryset"] = Person.objects.filter(profile=self.my_id_for_formfield)
        return super(ProfileAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
ygya80vv

ygya80vv2#

下面的代码片段将为您提供对象ID:

request.resolver_match.kwargs['object_id']

样品使用:(我正在过滤显示的电话号码,以便仅显示客户的电话号码)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == 'preferred_contact_number':
        kwargs['queryset'] = CustomerPhone.objects.filter(customer__pk=request.resolver_match.kwargs['object_id'])
    return super().formfield_for_foreignkey(db_field, request, **kwargs)

附言:通过调试和遍历可访问变量找到它。

nxowjjhe

nxowjjhe3#

据我所知,通过formfield_for_...-方法访问当前示例是不可能的,因为只会为单个字段示例调用它们!
get_form中可以访问整个示例/表单,这是一个更好的逻辑挂钩点,也可以覆盖表单字段的queryset!

polkgigr

polkgigr4#

我通过重写change_view()使其工作

class CartAdmin(admin.ModelAdmin):

def change_view(self, request, object_id, form_url='', extra_context=None):
    self.object_id = object_id
    return self.changeform_view(request, object_id, form_url, extra_context)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    print self.object_id
    return super(CartAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

那么你可以在formfield_for_foreignkey()中调用self.object_id

s6fujrry

s6fujrry5#

一种更通用的方法是编写一个helper方法来获取模型示例(如果有的话),就像您通常对(绑定的)ModelForm所做的那样,并从该方法中检索id或任何其他属性:

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):

    def get_instance(self, request):
        try:
            object_id = request.resolver_match.kwargs['object_id']
            obj = self.get_object(request, object_id)
        except:
            obj = None
        return obj
yiytaume

yiytaume6#

简短回答

如果您"真的"需要formfield_for_foreignkey()中的对象id,可以使用request.resolver_match.kwargs.get('object_id')(docs),正如@mazyar-mk的回答中所建议的那样。
但是,如果 * 目标 * 是基于对象过滤查询集,那么最好按照formfield_for_foreignkey()文档中的建议扩展ModelForm.__init__()
参见底部的示例。

长答案(带示例)

接受的answer by @BernhardVallant建议扩展ModelAdmin.get_form(),注解中建议修改base_fields属性(注意get_form()返回的是表单 * class *,不是绑定表单)。
这是很诱人的,在某些情况下,你可能会像这样侥幸逃脱:

def get_form(self, request, obj=None, change=False, **kwargs):
    form_class = super().get_form(request, obj, change, **kwargs)
    if obj:
        form_class.base_fields['my_field'].queryset = my_queryset.filter(
            my_lookup=obj
        )
    return form_class

然而,Django的文档对此提出了警告:
请注意不要更改base_fields属性,因为此修改将影响同一Python进程中的所有后续ContactForm示例:...
另请参见例如this answer
answer by @fizxmike提供了一个使用get_form()而不修改base_fields的替代示例,但它仍然需要formfield_for_foreignkey()

文档中的解决方案

formfield_for_foreignkey()的文档建议了另一种方法(另请参见this ticket和fields docs):
对于更复杂的过滤器,您可以使用ModelForm.__init__()方法基于模型的instance进行过滤...
表单初始化后,可以访问fields属性来修改查询集,而且可以访问实际的对象(如self.instance),而不仅仅是对象id。
例如:

class MyModelAdminForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance.pk is not None:
            self.fields['my_field'].queryset = my_queryset.filter(
                my_lookup=self.instance
            )

class MyModelAdmin(admin.ModelAdmin):
    form = MyModelAdminForm
    ...

在这里,我们检查self.instance.pk以查看对象是否存在于数据库中(add vs change view)。
这种方法也适用于内联。

smtd7mpg

smtd7mpg7#

我在处理一个类似的情况,并意识到我需要从请求的id,我可以从模型它自己,因为它是一个外键到该模型,所以它将是这样的:

cpu = CompanyUser.objects.filter(company__id=self.company_id)

或者你的模型结构所要求的。

yzuktlbb

yzuktlbb8#

我在www.example.com中创建了一个属性()model.py,它返回ID
models.py:

class MyModel(models.Model):
    myfield = models.CharField(max_length=75)
    ...
    def get_id(self):
        return str(self.id)
    getid = property(get_id)

admin.py:

from myapp.models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    list_display = ['mylink',]
    def mylink(self, object):
        return '<a href="http://mywebsite/'+object.getid+'/">Edit</a>'
    mylink.allow_tags = True

admin.site.register(MyModel, MyModelAdmin)

相关问题