简体   繁体   English

如何将 django 管理更改列表导出为 csv

[英]How to export django admin changelist as csv

I want to export my changelist (fields in list_display ) as csv.我想将我的更改列表list_display字段)导出为 csv。 I used the code from https://books.agiliq.com/projects/django-admin-cookbook/en/latest/export.html But it creates csv for the model fields.我使用了https://books.agiliq.com/projects/django-admin-cookbook/en/latest/export.html 中的代码,但它为模型字段创建了 csv。 But in my case, I want to export changelist as csv, not the model fields.但就我而言,我想将更改列表导出为 csv,而不是模型字段。 Also, note that most of the fields in changelist( list_display ) are calculated fields in Admin.另请注意,changelist( list_display ) 中的大多数字段都是 Admin 中的计算字段。

This is my code这是我的代码

class ExportCsvMixin:

    def export_as_csv(self, request, queryset):

        meta = queryset.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"


class MyAdmin(admin.ModelAdmin, ExportCsvMixin):
    list_display = ('field1',
                    'field2'
           )
    list_filter = ('field2')
    actions = ["export_as_csv"]

    def field1(self, obj):
        <return logic here>

    def field2(self, obj):
        <return logic here>

NOTE:笔记:

  1. field1 and field2 are calculated fields, and not model fields. field1 和 field2 是计算字段,而不是模型字段。
  2. My model is a proxy model.我的模型是代理模型。 But I don't think it would any difference in this case.但我认为在这种情况下不会有任何区别。

I want the csv to contain data for field1 and field2 only, as they are in my changelist.我希望 csv 只包含field1field2数据,因为它们在我的更改列表中。 May be the trick would be to somehow point the queryset to that of changelist.可能的诀窍是以某种方式将查询集指向更改列表的查询集。 but how do that ?但是怎么办呢? Or if someone can suggest some other solution or even api to achieve this goal?或者,如果有人可以建议其他解决方案甚至 api 来实现这一目标?

I had the same issue and I managed to hack it this way.我有同样的问题,我设法以这种方式破解它。

  • I looked into the ModelAdmin base class and I found the function responsible for handling actions methods, it's called response_action , I looked into it and changed the queryset it return what I need.我查看了 ModelAdmin 基类,发现了负责处理操作方法的函数,它称为response_action ,我查看了它并更改了它返回我需要的查询集。

Let say you have a query set that return 'field1' and 'field2'.假设您有一个返回“field1”和“field2”的查询集。

Here is how I edited the function to return a custom queryset:以下是我如何编辑函数以返回自定义查询集:

def response_action(self, request, queryset):
        """
        Handle an admin action. This is called if a request is POSTed to the
        changelist; it returns an HttpResponse if the action was handled, and
        None otherwise.
        """

        # There can be multiple action forms on the page (at the top
        # and bottom of the change list, for example). Get the action
        # whose button was pushed.
        try:
            action_index = int(request.POST.get('index', 0))
        except ValueError:
            action_index = 0

        # Construct the action form.
        data = request.POST.copy()
        data.pop(admin.helpers.ACTION_CHECKBOX_NAME, None)
        data.pop("index", None)

        # Use the action whose button was pushed
        try:
            data.update({'action': data.getlist('action')[action_index]})
        except IndexError:
            # If we didn't get an action from the chosen form that's invalid
            # POST data, so by deleting action it'll fail the validation check
            # below. So no need to do anything here
            pass

        action_form = self.action_form(data, auto_id=None)
        action_form.fields['action'].choices = self.get_action_choices(request)

        # If the form's valid we can handle the action.
        if action_form.is_valid():
            action = action_form.cleaned_data['action']
            select_across = action_form.cleaned_data['select_across']
            func = self.get_actions(request)[action][0]

            # Get the list of selected PKs. If nothing's selected, we can't
            # perform an action on it, so bail. Except we want to perform
            # the action explicitly on all objects.
            selected = request.POST.getlist(admin.helpers.ACTION_CHECKBOX_NAME)
            if not selected and not select_across:
                # Reminder that something needs to be selected or nothing will
                # happen
                msg = _("Items must be selected in order to perform "
                        "actions on them. No items have been changed.")
                self.message_user(request, msg, messages.WARNING)
                return None

            if not select_across:
                ##### change this line with your queryset that return field one and two
                queryset = 'your_queryset_with_field'

            response = func(self, request, queryset)

            # Actions may return an HttpResponse-like object, which will be
            # used as the response from the POST. If not, we'll be a good
            # little HTTP citizen and redirect back to the changelist page.
            if isinstance(response, HttpResponseBase):
                return response
            else:
                return HttpResponseRedirect(request.get_full_path())
        else:
            msg = _("No action selected.")
            self.message_user(request, msg, messages.WARNING)
            return None

Check in this function the part I command with ##### redefine that function in the class that inherits from the model admin class在这个函数中检查我命令的部分#####在继承自模型管理类的类中重新定义该函数

The function returns a custom queryset , now you can edit your export_as_csv_function according to that.该函数返回一个自定义查询集,现在您可以根据它编辑您的 export_as_csv_function。

def export_as_csv(self, request, queryset):

        field_names = ["field_one", "field_two"]

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

        writer.writerow(field_names)
        for obj in queryset:
            writer.writerow([obj.get(field) for field in field_names])

        return response

That it and you can go and download your CSV with the customs field.它和你可以去下载你的 CSV 与海关字段。

I hope it's not too late and this helps other folks with the same issue.我希望现在还为时不晚,这可以帮助其他有同样问题的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM