mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-01 13:06: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:
parent
73a32f66c8
commit
4f74a27e1a
@ -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:
|
||||||
|
@ -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 %}
|
||||||
|
@ -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):
|
||||||
|
|
||||||
|
@ -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)),
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user