Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add link to change page using raw_id_fields in django admin

Is there any chance to add link to change page of a Foreign key object next to 'raw_id_fields' in django admin? I use raw_id_fields to reduce number of queries to mysql. I could edit or add a foreign key object when I didn't use raw_id_fields.

How to do it with raw_id_fields?

@AntoinePinsard, I've tried the second solution. The field 'Edit My FK' was created but there is nothing except for a hyphen.

That's my modeladmin.

class FlatAdmin(admin.ModelAdmin):
    inlines = [NeedInline]
    readonly_fields = ('flat_house_edit_link',)
    raw_id_fields = ('flat_house',)
    list_display = ('show_date','show_block','show_house','show_rooms','show_price','show_stage')
    list_filter = ('flat_house__house_block','flat_rooms')
    search_fields = ('flat_house__id',)

    field = ['flat_house','flat_house_edit_link','flat_owner','flat_price','flat_rooms','flat_total_sq','flat_life_sq','flat_kitchen_sq','flat_floors']

    def flat_house_edit_link(self, instance):
        if instance:
            fk_id = instance.user_id
        else:
            fk_id = None
        if fk_id:
            opts = instance._meta.get_field('flat_house').rel.model._meta
            related_url = reverse(
                'admin:{}_{}_change/?_to_field=id&_popup=1'.format(
                     opts.ha,
                     opts.house,
                ),
                args=[fk_id],
            )
            return format_html(
                 '<a target=_blank href="{}">Go!</a>', related_url)
        else:
            return "No related object"
    flat_house_edit_link.short_description = "Change house"
admin.site.register(Flat,FlatAdmin)
like image 332
mailman_73 Avatar asked Mar 14 '16 13:03

mailman_73


1 Answers

Note This behavior is now built-in since Django 1.10.

You can create a custom widget to render this field as you would like to.

from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django.core.urlresolvers import reverse, NoReverseMatch
from django.utils.html import format_html

class ForeignKeyLinkedRawIdWidget(ForeignKeyRawIdWidget):
    def render(self, name, value, attrs=None):
        output = super().render(name, value, attrs)
        try:
            related_url = reverse(
                'admin:{}_{}_change'.format(
                    self.rel.model._meta.app_label,
                    self.rel.model._meta.model_name,
                ),
                args=[value],
            )
        except NoReverseMatch:
            return output
        return format_html('{output} <a href="{url}">edit</a>',
                           output=output, url=related_url)

And use this widget in your form, rather than using raw_id_fields:

from myapp.forms.widgets import ForeignKeyLinkedRawIdWidget

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = '__all__'
        widgets = {
            'my_foreignkey': ForeignKeyLinkedRawIdWidget(),
        }

class MyModelAdmin(admin.ModelAdmin):
    form = MyForm

However, it would be much simpler to add it as a "fake" readonly_field below the actual field:

from django.core.urlresolvers import reverse
from django.utils.html import format_html

class MyModelAdmin(admin.ModelAdmin):
    readonly_fields = ['my_foreignkey_link']
    raw_id_fields = ['my_foreignkey']
    fields = [..., 'my_foreignkey', 'my_foreignkey_link', ...]

    def my_foreignkey_link(self, instance):
        if instance:
            fk_id = instance.my_foreignkey_id
        else:
            fk_id = None
        if fk_id:
            opts = instance._meta.get_field('my_foreignkey').rel.model._meta
            related_url = reverse(
                'admin:{}_{}_change'.format(
                     opts.app_label,
                     opts.model_name,
                ),
                args=[fk_id],
            )
            return format_html(
                 '<a target=_blank href="{}">Go!</a>', related_url)
        else:
            return "No related object"
    my_foreignkey_link.short_description = "Edit My FK"

Further reading: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

like image 95
Antoine Pinsard Avatar answered Nov 15 '22 08:11

Antoine Pinsard