diff --git a/djangoldp/admin.py b/djangoldp/admin.py index 9211d4074cf8d035f0829c82e34fbfb5bb67e5a7..673eb8c74a35313e4dac594bc492d487fc5d6805 100644 --- a/djangoldp/admin.py +++ b/djangoldp/admin.py @@ -1,6 +1,9 @@ +from csv import DictWriter from django.contrib import admin -from guardian.admin import GuardedModelAdmin from django.contrib.auth.admin import UserAdmin +from django.core.exceptions import FieldDoesNotExist +from django.http import HttpResponse +from guardian.admin import GuardedModelAdmin from djangoldp.models import Activity, ScheduledActivity, Follower from djangoldp.activities.services import ActivityQueueService @@ -10,10 +13,33 @@ class DjangoLDPAdmin(GuardedModelAdmin): An admin model representing a federated object. Inherits from GuardedModelAdmin to provide Django-Guardian object-level permissions ''' - pass - - -class DjangoLDPUserAdmin(UserAdmin, GuardedModelAdmin): + actions = ['export_csv'] + export_fields = [] + + def resolve_verbose_name(self, field_path): + field = self + for field_name in field_path.split('__'): + try: + field = field.model._meta.get_field(field_name) + except FieldDoesNotExist: + return None + return field.verbose_name + + @admin.action(description="Export CSV") + def export_csv(self, request, queryset): + response = HttpResponse(content_type="text/csv") + response['Content-Disposition'] = f'attachment; filename="{self.model.__name__}.csv"' + # only keep fields that can be resolved, keep only urlid if none + field_list = list(filter(self.resolve_verbose_name, self.export_fields or self.list_display)) or ['urlid'] + headers = {field:self.resolve_verbose_name(field) for field in field_list} + + writer = DictWriter(response, fieldnames=field_list) + writer.writerow(headers) + writer.writerows(queryset.values(*field_list)) + return response + + +class DjangoLDPUserAdmin(UserAdmin, DjangoLDPAdmin): '''An extension of UserAdmin providing the functionality of DjangoLDPAdmin''' list_display = ('urlid', 'email', 'first_name', 'last_name', 'date_joined', 'last_login', 'is_staff') diff --git a/docs/create_model.md b/docs/create_model.md index 92c0aec7642ff02d84fd20aad4eeea137b3d7258..9297ba5274fcbe142aab297e38b3c3dbdb2a1bac 100644 --- a/docs/create_model.md +++ b/docs/create_model.md @@ -217,6 +217,15 @@ LDPUser.circles = lambda self: Circle.objects.filter(members__user=self) LDPUser.circles.field = DynamicNestedField(Circle, 'circles') ``` +### Configuring CSV export + +DjangoLDP automaticallly provides CSV export on the admin site. By default, it exports the columns given in the `list_display` attribute. This can be overridden with the attribute `export_fields`. This setting can include fields of related object using `__`. + +```python +class CustomAdmin(DjangoLDPAdmin): + export_fields = ['email', 'account__slug'] +``` + ### Improving Performance On certain endpoints, you may find that you only need a subset of fields on a model, and serializing them all is expensive (e.g. if I only need the `name` and `id` of each group chat, then why serialize all of their members?). To optimise the fields serialized, you can pass a custom header in the request, `Accept-Model-Fields`, with a `list` value of desired fields e.g. `['@id', 'name']`