2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-01 04:56:45 +00:00

Exporting data from a Part table now uses the API too

- Makes use of the existing table filters
- Exported data matches exactly what you see in the table!
This commit is contained in:
Oliver 2022-03-03 17:42:31 +11:00
parent 73a32f66c8
commit 4f74a27e1a
5 changed files with 23 additions and 81 deletions

View File

@ -26,6 +26,8 @@ from djmoney.contrib.exchange.exceptions import MissingRate
from decimal import Decimal, InvalidOperation from decimal import Decimal, InvalidOperation
from part.admin import PartResource
from .models import Part, PartCategory, PartRelated from .models import Part, PartCategory, PartRelated
from .models import BomItem, BomItemSubstitute from .models import BomItem, BomItemSubstitute
from .models import PartParameter, PartParameterTemplate from .models import PartParameter, PartParameterTemplate
@ -43,6 +45,7 @@ from build.models import Build
from . import serializers as part_serializers from . import serializers as part_serializers
from InvenTree.helpers import str2bool, isNull, increment from InvenTree.helpers import str2bool, isNull, increment
from InvenTree.helpers import DownloadFile
from InvenTree.api import AttachmentMixin from InvenTree.api import AttachmentMixin
from InvenTree.status_codes import BuildStatus from InvenTree.status_codes import BuildStatus
@ -726,6 +729,22 @@ class PartList(generics.ListCreateAPIView):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
# Check if we wish to export the queried data to a file.
# If so, skip pagination!
export_format = request.query_params.get('export', None)
if export_format:
export_format = str(export_format).strip().lower()
if export_format in ['csv', 'tsv', 'xls', 'xlsx']:
dataset = PartResource().export(queryset=queryset)
filedata = dataset.export(export_format)
filename = f"InvenTree_Parts.{export_format}"
return DownloadFile(filedata, filename)
page = self.paginate_queryset(queryset) page = self.paginate_queryset(queryset)
if page is not None: if page is not None:

View File

@ -153,9 +153,6 @@
<h4>{% trans "Parts" %}</h4> <h4>{% trans "Parts" %}</h4>
{% include "spacer.html" %} {% include "spacer.html" %}
<div class='btn-group' role='group'> <div class='btn-group' role='group'>
<button type='button' class='btn btn-outline-secondary' id='part-export' title='{% trans "Export Part Data" %}'>
<span class='fas fa-file-download'></span> {% trans "Export" %}
</button>
{% if roles.part.add %} {% if roles.part.add %}
<button type='button' class='btn btn-success' id='part-create' title='{% trans "Create new part" %}'> <button type='button' class='btn btn-success' id='part-create' title='{% trans "Create new part" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Part" %} <span class='fas fa-plus-circle'></span> {% trans "New Part" %}
@ -167,6 +164,9 @@
<div id='part-button-toolbar'> <div id='part-button-toolbar'>
<div class='btn-group' role='group'> <div class='btn-group' role='group'>
<div class='btn-group' role='group'> <div class='btn-group' role='group'>
<button id='part-export' class='btn btn-outline-secondary' type='button' title='{% trans "Export part data" %}'>
<span class='fas fa-file-download'></span>
</button>
<button id='part-options' class='btn btn-primary dropdown-toggle' type='button' data-bs-toggle="dropdown"> <button id='part-options' class='btn btn-primary dropdown-toggle' type='button' data-bs-toggle="dropdown">
{% trans "Options" %} {% trans "Options" %}
</button> </button>
@ -291,10 +291,7 @@
}); });
$("#part-export").click(function() { $("#part-export").click(function() {
downloadTableData($('#part-table'));
var url = "{% url 'part-export' %}?category={{ category.id }}";
location.href = url;
}); });
{% if roles.part.add %} {% if roles.part.add %}

View File

@ -58,14 +58,6 @@ class PartListTest(PartViewTestCase):
self.assertIn('parts', keys) self.assertIn('parts', keys)
self.assertIn('user', keys) self.assertIn('user', keys)
def test_export(self):
""" Export part data to CSV """
response = self.client.get(reverse('part-export'), {'parts': '1,2,3,4,5,6,7,8,9,10'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
self.assertIn('streaming_content', dir(response))
class PartDetailTest(PartViewTestCase): class PartDetailTest(PartViewTestCase):

View File

@ -80,9 +80,6 @@ part_urls = [
# Download a BOM upload template # Download a BOM upload template
url(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'), url(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'),
# Export data for multiple parts
url(r'^export/', views.PartExport.as_view(), name='part-export'),
# Individual part using pk # Individual part using pk
url(r'^(?P<pk>\d+)/', include(part_detail_urls)), url(r'^(?P<pk>\d+)/', include(part_detail_urls)),

View File

@ -709,69 +709,6 @@ class BomUpload(InvenTreeRoleMixin, DetailView):
template_name = 'part/upload_bom.html' template_name = 'part/upload_bom.html'
class PartExport(AjaxView):
""" Export a CSV file containing information on multiple parts """
role_required = 'part.view'
def get_parts(self, request):
""" Extract part list from the POST parameters.
Parts can be supplied as:
- Part category
- List of part PK values
"""
# Filter by part category
cat_id = request.GET.get('category', None)
part_list = None
if cat_id is not None:
try:
category = PartCategory.objects.get(pk=cat_id)
part_list = category.get_parts()
except (ValueError, PartCategory.DoesNotExist):
pass
# Backup - All parts
if part_list is None:
part_list = Part.objects.all()
# Also optionally filter by explicit list of part IDs
part_ids = request.GET.get('parts', '')
parts = []
for pk in part_ids.split(','):
try:
parts.append(int(pk))
except ValueError:
pass
if len(parts) > 0:
part_list = part_list.filter(pk__in=parts)
# Prefetch related fields to reduce DB hits
part_list = part_list.prefetch_related(
'category',
'used_in',
'builds',
'supplier_parts__purchase_order_line_items',
'stock_items__allocations',
)
return part_list
def get(self, request, *args, **kwargs):
parts = self.get_parts(request)
dataset = PartResource().export(queryset=parts)
csv = dataset.export('csv')
return DownloadFile(csv, 'InvenTree_Parts.csv')
class BomUploadTemplate(AjaxView): class BomUploadTemplate(AjaxView):
""" """
Provide a BOM upload template file for download. Provide a BOM upload template file for download.