Export all list_display fields to csv in django admin

Viewed 699

I'm using the recipe at https://books.agiliq.com/projects/django-admin-cookbook/en/latest/export.html

class ExportCsvMixin:
    def export_as_csv(self, request, queryset):

        meta = self.model._meta
        field_names = [field.name for field in meta.fields]

        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
        writer = csv.writer(response)

        writer.writerow(field_names)
        for obj in queryset:
            row = writer.writerow([getattr(obj, field) for field in field_names])

        return response

    export_as_csv.short_description = "Export Selected"

which works great except it doesn't export all the columns I see in the admin panel. I have added some extra columns like this

class MeetingAdmin(admin.ModelAdmin, ExportCsvMixin):
    actions = ["export_as_csv"]
    list_display = (
        "__str__",
        "expert_network",
    )

    def expert_network(self, obj):
        if obj.expert:
            return obj.expert.network.name
        else:
            return "-"

is it possible to improve the ExportCsvMixin to also export the callable list_display fields?

I'm currently trying to loop over the list_display but I don't know how to use callables

class ExportCsvMixin:
    def export_as_csv(self, request, queryset):
        meta = self.model._meta
        # field_names = [field.name for field in meta.fields]
        field_names = list(self.list_display)

        response = HttpResponse(content_type="text/csv")
        response["Content-Disposition"] = "attachment; filename={}.csv".format(meta)
        writer = csv.writer(response)

        writer.writerow(field_names)
        for obj in queryset:
            result = []
            for field in field_names:
                attr = getattr(obj, field)
                if callable(attr):
                    result.append(attr())
                else:
                    result.append(attr)
            row = writer.writerow(result)

        return response

    export_as_csv.short_description = "Export Selected"
1 Answers

came up with this

class ExportCsvMixin:
    def export_as_csv(self, request, queryset):
        meta = self.model._meta
        # field_names = [field.name for field in meta.fields]
        field_names = list(self.list_display)

        response = HttpResponse(content_type="text/csv")
        response["Content-Disposition"] = "attachment; filename={}.csv".format(meta)
        writer = csv.writer(response)

        writer.writerow(field_names)
        for obj in queryset:
            result = []
            for field in field_names:
                attr = getattr(obj, field, None)
                if attr and callable(attr):
                    result.append(attr())
                elif attr:
                    result.append(attr)
                else:
                    attr = getattr(self, field, None)
                    if attr:
                        result.append(attr(obj))
                    else:
                        result.append(attr)
            row = writer.writerow(result)

        return response

    export_as_csv.short_description = "Export Selected"

basically we look for the attribute or callable on the object, if it's not there then we look at the modelAdmin and invoke the callable with the object as the arg.

Related