Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django inline link to model editing

I know this issue has been asked more than once, but as Django is evolving with new version, I'll ask the question again :

I am using the model User (Django User, not in my models.py) and create another model with a Foreign key to User.

models.py :

class Plan(models.Model):
    user = models.ForeignKey(User)

I can simply display every Plan in my user by doing this in admin.py :

class PlanInline(admin.TabularInline):
    model = Plan
    extra = 0

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    inlines = [PlanInline,]

admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)

But things are about to get more tricky. I want to add a model that has a foreign key pointing to Plan :

class Order(models.Model):
    plan = models.ForeignKey('Plan')

And I want to be able to see all Orders for each Plan. As of today, it is impossible to have nested inlines in Django Admin (without editing the HTML, which I want to avoid) :

User 
     -> Plan 1 
              -> Order 1
              -> Order 2

     -> Plan 2
              -> Order 3

So my idea is to display in the User Admin only A LINK for each plan, to the page to edit Plans, and put Orders as inline :

class OrderInline(admin.TabularInline):
    model = Order
    extra = 0

class PlanAdmin(admin.ModelAdmin):
    inlines = [OrderInline,]

admin.site.register(Plan, PlanAdmin)

The question is, how do I display a link to a Plan in my User Admin?

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    ??? LINK ????

I saw some solutions on this topic : Django InlineModelAdmin: Show partially an inline model and link to the complete model, but they are a bit "dirty' as they make us write HTML and absolute path into the code.

Then I saw this ticket on Djangoproject : https://code.djangoproject.com/ticket/13163. It seems exactly what I'm looking for, and the ticket is "fixed". So I tried adding like in the fix show_change_link = True :

class PlanInline(admin.TabularInline):
    model = Plan
    extra = 0
    show_change_link = True

class MyUserAdmin(UserAdmin):
    ordering = ('-date_joined', 'username')
    show_change_link = True
    inlines = [UserProfileInline, PlanInline]

But it doesn't work (and I have no log or error).

Is there any way to do this in a clean way?

like image 465
Raphael Laurent Avatar asked Aug 04 '14 13:08

Raphael Laurent


2 Answers

Update for django 1.8

show_change_link = True

https://github.com/django/django/pull/2957/files

like image 103
Renoc Avatar answered Nov 03 '22 06:11

Renoc


I suggest adding a custom PlanInline method that returns the link and see if it helps. Something along these lines:

from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse

class PlanInline(TabularInline):
   model = Plan
   readonly_fields = ('change_link',)
   ...other options here...

   def change_link(self, obj):
      return mark_safe('<a href="%s">Full edit</a>' % \
                        reverse('admin:myapp_plan_change',
                        args=(obj.id,)))

Basically all we do here is create the custom method that returns a link to the change page (this specific implementation is not tested, sorry if there is any parse error but you get the idea) and then add it to the readonly_fields as described here: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

A couple of notes for the change_link method: You need to replace 'myapp' in the view name with your actual application name. The mark_safe method just marks the text as safe for the template engine to render it as html.

like image 27
ppetrid Avatar answered Nov 03 '22 06:11

ppetrid