Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django get instance in inline form admin

Have a inline form class:

class ItemColorSelectForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ItemColorSelectForm, self).__init__(*args, **kwargs)
        #here i need current object

Inline class:

class ItemColorSelectInline(generic.GenericTabularInline):
    model = ColorSelect
    extra = 1
    form = ItemColorSelectForm

Admin class

class ItemAdmin(admin.ModelAdmin):
    inlines = [ItemColorInline,]

Question: how can a get current object in ItemColorSelectForm.

print kwargs return:

{'auto_id': u'id_%s', 'prefix': u'catalog-colorselect-content_type-object_id-__prefix__', 'empty_permitted': True}
like image 637
Arti Avatar asked Mar 17 '14 22:03

Arti


People also ask

What is Django inline formset?

Django formset allows you to edit a collection of the same forms on the same page. It basically allows you to bulk edit a collection of objects at the same time.

How do I access my Django admin page?

To login to the site, open the /admin URL (e.g. http://127.0.0.1:8000/admin ) and enter your new superuser userid and password credentials (you'll be redirected to the login page, and then back to the /admin URL after you've entered your details).

What is Inlines in Django?

django-inline-actions provides a handy templatetag render_inline_action_fields , which adds these information as hidden fields to a form. As the action does not know that an intermediate form is used, we have to include some special handling.

What is admin panel in Django?

One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin's recommended use is limited to an organization's internal management tool.


2 Answers

Currently accepted solution is not thread safe. If you care about thread safety, never, ever assign an instance to a static class property.

Thread safe solutions are:

For Django 1.7 < 1.9 (possibly earlier versions, unclear):

from django.utils.functional import cached_property

def get_formset(self, *args, **kwargs):
    FormSet = super(InlineAdmin, self).get_formset(*args, **kwargs)

    class ProxyFormSet(FormSet):
        def __init__(self, *args, **kwargs):
            self.instance = kwargs['instance']
            super(ProxyFormSet, self).__init__(*args, **kwargs)

        @cached_property
        def forms(self):
            kwargs = {'instance': self.instance}
            forms = [self._construct_form(i, **kwargs) 
                    for i in xrange(self.total_form_count())]
            return forms
    return ProxyFormSet

As of Django >= 1.9 it's also possible to pass form_kwargs:

def get_formset(self, *args, **kwargs):
    FormSet = super(InlineAdmin, self).get_formset(*args, **kwargs)

    class ProxyFormSet(FormSet):
        def __init__(self, *args, **kwargs):
            form_kwargs = kwargs.pop('form_kwargs', {})
            form_kwargs['instance'] = kwargs['instance']
            super(ProxyFormSet, self).__init__(
                *args, form_kwargs=form_kwargs, **kwargs)
    return ProxyFormSet

Above solutions will make an instance kwarg available in the model form:

class InlineForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(InlineForm, self).__init__(*args, **kwargs)
        print('instance', kwargs['instance'])
like image 63
Elwin Arens Avatar answered Sep 21 '22 09:09

Elwin Arens


Solution: Override the formset method in Inline class

def get_formset(self, request, obj=None, **kwargs):
        InlineForm.obj = obj
        return super(InlineAdmin, self).get_formset(request, obj, **kwargs)
like image 29
Arti Avatar answered Sep 22 '22 09:09

Arti