10

Is there anyway to make the list_editable optional on a per object bases? For example the readonly fields attribute has this option, which doesn't affect the changelist_view.

class MyAdmin(admin.ModelAdmin):
    readonly_fields = ('foo',)

    def get_readonly_fields(self, request, obj=None):
        fields = super(MyAdmin, self).get_readonly_fields(request, obj=obj)

        if obj.status == 'CLOSED':
            return fields + ('bar',)
        return fields

The same can be achieved for list_display and some other attributes. It seems there isn't a method 'get_list_editable_fields'.

I want some of the rows to be immutable obviously, but other than raising a vulgar error doesn't seem to work. I didn't find any documentation about the attribute either

Would it somehow be possible to render the widget via a list_display getter?

class MyAdmin(admin.ModelAdmin):
    list_display = ('get_bar',)
    list_editable = ('get_bar',)

    def get_bar(self, obj):
        return widget or str(obj.bar)  # ???
    get_bar.allow_tags = True

update using Alasdair's feedback:

def get_changelist_formset(self, request, **kwargs):
    """
    Returns a FormSet class for use on the changelist page if list_editable
    is used.
    """
    # I run through this code for each row in the changelist, but there's nothing in kwargs, so I don't know how to use the instance as a guide to which fields should be in list_editable?

    defaults = {
        "formfield_callback": partial(self.formfield_for_dbfield, request=request),
    }
    defaults.update(kwargs)
    return modelformset_factory(
        self.model, self.get_changelist_form(request), extra=0,
        fields=self.list_editable, **defaults
    )
trb
  • 123
  • 1
  • 6

4 Answers4

4

As you say, there is no get_list_editable method.

Try overriding the get_changelist_formset method. I think you'll need to duplicate the entire method, and change the list of fields passed to modelformset_factory.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • I don't understand how to get the current instance in the method, I run through the method for each row, but kwargs is empty? see my updated question – trb Oct 30 '15 at 11:25
  • I'm not sure what the answer is, you're pretty deep inside the admin code! You might need to override `get_changelist_form` as well/instead. Good luck! – Alasdair Oct 30 '15 at 11:32
  • This set me on the right track.. I ended up registering the model on the admin twice (which requires a proxy model hack) and creating its own admin rule set. This requirement really hits the boundries of the django admin :-) – trb Nov 07 '15 at 19:31
  • @trb Thanks for this. I'm trying to accomplish the exact same thing. How does your solution look like? Would you mind sharing the code? Thank you. – André Nov 07 '15 at 20:24
  • @André I think the OP means something like this, I had the same issue, I really think django should support the common requirement at some point :-) http://stackoverflow.com/questions/2223375/multiple-modeladmins-views-for-same-model-in-django-admin – Hedde van der Heide Nov 12 '15 at 14:24
3

As said, there is not get_list_editable method in the ModelAdmin class, but it is possible to implement it easily (tested on django==2.1):

class MyAdminClass(admin.ModelAdmin):

    def get_list_editable(self, request):
        """
        get_list_editable method implementation, 
        django ModelAdmin doesn't provide it.
        """
        dynamically_editable_fields = ('name', 'published', )
        return dynamically_editable_fields

    def get_changelist_instance(self, request):
        """
        override admin method and list_editable property value 
        with values returned by our custom method implementation.
        """
        self.list_editable = self.get_list_editable(request)
        return super(MyAdminClass, self).get_changelist_instance(request)
Fabio Caccamo
  • 1,871
  • 19
  • 21
0

Also, you could override the changelist_view and do something like that:

   def changelist_view(self, request, extra_context=None):
       resp = super(CustomModelAdmin, self).changelist_view(request, extra_context)
       if something:
           resp.context_data['cl'].formset = None

       return resp
lefterisnik
  • 137
  • 1
  • 3
0

A little late but I found a way. Override the get_changelist_instance()

def get_changelist_instance(self, request):
    if request.user.is_superuser:
            self.list_editable = ('state',) # replace state with list of fields you wish to be editable
    else:
            self.list_editable = ()
    return super().get_changelist_instance(request)

It is better than overriding "get_changelist_formset" because get_changelist_formset() only runs if you have set list_editable to atleast one field. Link to Documentation

Kunal Khatri
  • 55
  • 1
  • 5