mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Filter queryset updates (#4571)
* Update build API filters * Update company API filetrs * Update unit tests
This commit is contained in:
parent
5ad4152270
commit
7656f30d02
@ -18,13 +18,22 @@ from InvenTree.mixins import CreateAPI, RetrieveUpdateDestroyAPI, ListCreateAPI
|
||||
import build.admin
|
||||
import build.serializers
|
||||
from build.models import Build, BuildItem, BuildOrderAttachment
|
||||
|
||||
import part.models
|
||||
from users.models import Owner
|
||||
|
||||
|
||||
class BuildFilter(rest_filters.FilterSet):
|
||||
"""Custom filterset for BuildList API endpoint."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options"""
|
||||
model = Build
|
||||
fields = [
|
||||
'parent',
|
||||
'sales_order',
|
||||
'part',
|
||||
]
|
||||
|
||||
status = rest_filters.NumberFilter(label='Status')
|
||||
|
||||
active = rest_filters.BooleanFilter(label='Build is active', method='filter_active')
|
||||
@ -32,22 +41,18 @@ class BuildFilter(rest_filters.FilterSet):
|
||||
def filter_active(self, queryset, name, value):
|
||||
"""Filter the queryset to either include or exclude orders which are active."""
|
||||
if str2bool(value):
|
||||
queryset = queryset.filter(status__in=BuildStatus.ACTIVE_CODES)
|
||||
return queryset.filter(status__in=BuildStatus.ACTIVE_CODES)
|
||||
else:
|
||||
queryset = queryset.exclude(status__in=BuildStatus.ACTIVE_CODES)
|
||||
|
||||
return queryset
|
||||
return queryset.exclude(status__in=BuildStatus.ACTIVE_CODES)
|
||||
|
||||
overdue = rest_filters.BooleanFilter(label='Build is overdue', method='filter_overdue')
|
||||
|
||||
def filter_overdue(self, queryset, name, value):
|
||||
"""Filter the queryset to either include or exclude orders which are overdue."""
|
||||
if str2bool(value):
|
||||
queryset = queryset.filter(Build.OVERDUE_FILTER)
|
||||
return queryset.filter(Build.OVERDUE_FILTER)
|
||||
else:
|
||||
queryset = queryset.exclude(Build.OVERDUE_FILTER)
|
||||
|
||||
return queryset
|
||||
return queryset.exclude(Build.OVERDUE_FILTER)
|
||||
|
||||
assigned_to_me = rest_filters.BooleanFilter(label='assigned_to_me', method='filter_assigned_to_me')
|
||||
|
||||
@ -59,11 +64,9 @@ class BuildFilter(rest_filters.FilterSet):
|
||||
owners = Owner.get_owners_matching_user(self.request.user)
|
||||
|
||||
if value:
|
||||
queryset = queryset.filter(responsible__in=owners)
|
||||
return queryset.filter(responsible__in=owners)
|
||||
else:
|
||||
queryset = queryset.exclude(responsible__in=owners)
|
||||
|
||||
return queryset
|
||||
return queryset.exclude(responsible__in=owners)
|
||||
|
||||
assigned_to = rest_filters.NumberFilter(label='responsible', method='filter_responsible')
|
||||
|
||||
@ -75,9 +78,7 @@ class BuildFilter(rest_filters.FilterSet):
|
||||
if len(owners) > 0 and owners[0].label() == 'user':
|
||||
owners = Owner.get_owners_matching_user(User.objects.get(pk=owners[0].owner_id))
|
||||
|
||||
queryset = queryset.filter(responsible__in=owners)
|
||||
|
||||
return queryset
|
||||
return queryset.filter(responsible__in=owners)
|
||||
|
||||
# Exact match for reference
|
||||
reference = rest_filters.CharFilter(
|
||||
@ -171,18 +172,6 @@ class BuildList(APIDownloadMixin, ListCreateAPI):
|
||||
except (ValueError, Build.DoesNotExist):
|
||||
pass
|
||||
|
||||
# Filter by "parent"
|
||||
parent = params.get('parent', None)
|
||||
|
||||
if parent is not None:
|
||||
queryset = queryset.filter(parent=parent)
|
||||
|
||||
# Filter by sales_order
|
||||
sales_order = params.get('sales_order', None)
|
||||
|
||||
if sales_order is not None:
|
||||
queryset = queryset.filter(sales_order=sales_order)
|
||||
|
||||
# Filter by "ancestor" builds
|
||||
ancestor = params.get('ancestor', None)
|
||||
|
||||
@ -199,12 +188,6 @@ class BuildList(APIDownloadMixin, ListCreateAPI):
|
||||
except (ValueError, Build.DoesNotExist):
|
||||
pass
|
||||
|
||||
# Filter by associated part?
|
||||
part = params.get('part', None)
|
||||
|
||||
if part is not None:
|
||||
queryset = queryset.filter(part=part)
|
||||
|
||||
# Filter by 'date range'
|
||||
min_date = params.get('min_date', None)
|
||||
max_date = params.get('max_date', None)
|
||||
@ -373,6 +356,34 @@ class BuildItemDetail(RetrieveUpdateDestroyAPI):
|
||||
serializer_class = build.serializers.BuildItemSerializer
|
||||
|
||||
|
||||
class BuildItemFilter(rest_filters.FilterSet):
|
||||
"""Custom filterset for the BuildItemList API endpoint"""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass option"""
|
||||
model = BuildItem
|
||||
fields = [
|
||||
'build',
|
||||
'stock_item',
|
||||
'bom_item',
|
||||
'install_into',
|
||||
]
|
||||
|
||||
part = rest_filters.ModelChoiceFilter(
|
||||
queryset=part.models.Part.objects.all(),
|
||||
field_name='stock_item__part',
|
||||
)
|
||||
|
||||
tracked = rest_filters.BooleanFilter(label='Tracked', method='filter_tracked')
|
||||
|
||||
def filter_tracked(self, queryset, name, value):
|
||||
"""Filter the queryset based on whether build items are tracked"""
|
||||
if str2bool(value):
|
||||
return queryset.exclude(install_into=None)
|
||||
else:
|
||||
return queryset.filter(install_into=None)
|
||||
|
||||
|
||||
class BuildItemList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of BuildItem objects.
|
||||
|
||||
@ -381,6 +392,7 @@ class BuildItemList(ListCreateAPI):
|
||||
"""
|
||||
|
||||
serializer_class = build.serializers.BuildItemSerializer
|
||||
filterset_class = BuildItemFilter
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
"""Returns a BuildItemSerializer instance based on the request."""
|
||||
@ -418,24 +430,6 @@ class BuildItemList(ListCreateAPI):
|
||||
|
||||
params = self.request.query_params
|
||||
|
||||
# Does the user wish to filter by part?
|
||||
part_pk = params.get('part', None)
|
||||
|
||||
if part_pk:
|
||||
queryset = queryset.filter(stock_item__part=part_pk)
|
||||
|
||||
# Filter by "tracked" status
|
||||
# Tracked means that the item is "installed" into a build output (stock item)
|
||||
tracked = params.get('tracked', None)
|
||||
|
||||
if tracked is not None:
|
||||
tracked = str2bool(tracked)
|
||||
|
||||
if tracked:
|
||||
queryset = queryset.exclude(install_into=None)
|
||||
else:
|
||||
queryset = queryset.filter(install_into=None)
|
||||
|
||||
# Filter by output target
|
||||
output = params.get('output', None)
|
||||
|
||||
@ -452,13 +446,6 @@ class BuildItemList(ListCreateAPI):
|
||||
DjangoFilterBackend,
|
||||
]
|
||||
|
||||
filterset_fields = [
|
||||
'build',
|
||||
'stock_item',
|
||||
'bom_item',
|
||||
'install_into',
|
||||
]
|
||||
|
||||
|
||||
class BuildAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
"""API endpoint for listing (and creating) BuildOrderAttachment objects."""
|
||||
|
@ -37,49 +37,50 @@ class TestBuildAPI(InvenTreeAPITestCase):
|
||||
def test_get_build_list(self):
|
||||
"""Test that we can retrieve list of build objects."""
|
||||
url = reverse('api-build-list')
|
||||
response = self.client.get(url, format='json')
|
||||
|
||||
response = self.get(url, expected_code=200)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
self.assertEqual(len(response.data), 5)
|
||||
|
||||
# Filter query by build status
|
||||
response = self.client.get(url, {'status': 40}, format='json')
|
||||
response = self.get(url, {'status': 40}, expected_code=200)
|
||||
|
||||
self.assertEqual(len(response.data), 4)
|
||||
|
||||
# Filter by "active" status
|
||||
response = self.client.get(url, {'active': True}, format='json')
|
||||
response = self.get(url, {'active': True}, expected_code=200)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
self.assertEqual(response.data[0]['pk'], 1)
|
||||
|
||||
response = self.client.get(url, {'active': False}, format='json')
|
||||
response = self.get(url, {'active': False}, expected_code=200)
|
||||
self.assertEqual(len(response.data), 4)
|
||||
|
||||
# Filter by 'part' status
|
||||
response = self.client.get(url, {'part': 25}, format='json')
|
||||
response = self.get(url, {'part': 25}, expected_code=200)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
# Filter by an invalid part
|
||||
response = self.client.get(url, {'part': 99999}, format='json')
|
||||
self.assertEqual(len(response.data), 0)
|
||||
response = self.get(url, {'part': 99999}, expected_code=400)
|
||||
self.assertIn('Select a valid choice', str(response.data))
|
||||
|
||||
# Get a certain reference
|
||||
response = self.client.get(url, {'reference': 'BO-0001'}, format='json')
|
||||
response = self.get(url, {'reference': 'BO-0001'}, expected_code=200)
|
||||
self.assertEqual(len(response.data), 1)
|
||||
|
||||
# Get a certain reference
|
||||
response = self.client.get(url, {'reference': 'BO-9999XX'}, format='json')
|
||||
response = self.get(url, {'reference': 'BO-9999XX'}, expected_code=200)
|
||||
self.assertEqual(len(response.data), 0)
|
||||
|
||||
def test_get_build_item_list(self):
|
||||
"""Test that we can retrieve list of BuildItem objects."""
|
||||
url = reverse('api-build-item-list')
|
||||
|
||||
response = self.client.get(url, format='json')
|
||||
response = self.get(url, expected_code=200)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Test again, filtering by park ID
|
||||
response = self.client.get(url, {'part': '1'}, format='json')
|
||||
response = self.get(url, {'part': '1'}, expected_code=200)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
|
@ -242,11 +242,30 @@ class ManufacturerPartAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI
|
||||
serializer_class = ManufacturerPartAttachmentSerializer
|
||||
|
||||
|
||||
class ManufacturerPartParameterFilter(rest_filters.FilterSet):
|
||||
"""Custom filterset for the ManufacturerPartParameterList API endpoint"""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options"""
|
||||
model = ManufacturerPartParameter
|
||||
fields = [
|
||||
'name',
|
||||
'value',
|
||||
'units',
|
||||
'manufacturer_part',
|
||||
]
|
||||
|
||||
manufacturer = rest_filters.ModelChoiceFilter(queryset=Company.objects.all(), field_name='manufacturer_part__manufacturer')
|
||||
|
||||
part = rest_filters.ModelChoiceFilter(queryset=part.models.Part.objects.all(), field_name='manufacturer_part__part')
|
||||
|
||||
|
||||
class ManufacturerPartParameterList(ListCreateDestroyAPIView):
|
||||
"""API endpoint for list view of ManufacturerPartParamater model."""
|
||||
|
||||
queryset = ManufacturerPartParameter.objects.all()
|
||||
serializer_class = ManufacturerPartParameterSerializer
|
||||
filterset_class = ManufacturerPartParameterFilter
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
"""Return serializer instance for this endpoint"""
|
||||
@ -268,39 +287,12 @@ class ManufacturerPartParameterList(ListCreateDestroyAPIView):
|
||||
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
"""Custom filtering for the queryset."""
|
||||
queryset = super().filter_queryset(queryset)
|
||||
|
||||
params = self.request.query_params
|
||||
|
||||
# Filter by manufacturer?
|
||||
manufacturer = params.get('manufacturer', None)
|
||||
|
||||
if manufacturer is not None:
|
||||
queryset = queryset.filter(manufacturer_part__manufacturer=manufacturer)
|
||||
|
||||
# Filter by part?
|
||||
part = params.get('part', None)
|
||||
|
||||
if part is not None:
|
||||
queryset = queryset.filter(manufacturer_part__part=part)
|
||||
|
||||
return queryset
|
||||
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
InvenTreeSearchFilter,
|
||||
filters.OrderingFilter,
|
||||
]
|
||||
|
||||
filterset_fields = [
|
||||
'name',
|
||||
'value',
|
||||
'units',
|
||||
'manufacturer_part',
|
||||
]
|
||||
|
||||
search_fields = [
|
||||
'name',
|
||||
'value',
|
||||
|
Loading…
Reference in New Issue
Block a user