mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add regex IPN filter for Part API
This commit is contained in:
parent
800cb9606a
commit
376428b80b
@ -5,9 +5,10 @@ Provides a JSON API for the Part app
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import reverse
|
||||
from django.http import JsonResponse
|
||||
from django.db.models import Q, F, Count, Min, Max, Avg
|
||||
from django.db.models import Q, F, Count, Min, Max, Avg, query
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import status
|
||||
@ -15,12 +16,13 @@ from rest_framework.response import Response
|
||||
from rest_framework import filters, serializers
|
||||
from rest_framework import generics
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_filters import rest_framework as rest_filters
|
||||
|
||||
from djmoney.money import Money
|
||||
from djmoney.contrib.exchange.models import convert_money
|
||||
from djmoney.contrib.exchange.exceptions import MissingRate
|
||||
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Part, PartCategory, BomItem
|
||||
from .models import PartParameter, PartParameterTemplate
|
||||
@ -405,6 +407,74 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return response
|
||||
|
||||
|
||||
class PartFilter(rest_filters.FilterSet):
|
||||
"""
|
||||
Custom filters for the PartList endpoint.
|
||||
Uses the django_filters extension framework
|
||||
"""
|
||||
|
||||
# Exact match for IPN
|
||||
ipn = rest_filters.CharFilter(
|
||||
label='Filter by exact IPN (internal part number)',
|
||||
field_name='IPN',
|
||||
lookup_expr="iexact"
|
||||
)
|
||||
|
||||
# Regex match for IPN
|
||||
ipn_regex = rest_filters.CharFilter(
|
||||
field_name='IPN', lookup_expr='iregex'
|
||||
)
|
||||
|
||||
# low_stock filter
|
||||
low_stock = rest_filters.BooleanFilter(method='filter_low_stock')
|
||||
|
||||
def filter_low_stock(self, queryset, name, value):
|
||||
"""
|
||||
Filter by "low stock" status
|
||||
"""
|
||||
|
||||
value = str2bool(value)
|
||||
|
||||
if value:
|
||||
# Ignore any parts which do not have a specified 'minimum_stock' level
|
||||
queryset = queryset.exclude(minimum_stock=0)
|
||||
# Filter items which have an 'in_stock' level lower than 'minimum_stock'
|
||||
queryset = queryset.filter(Q(in_stock__lt=F('minimum_stock')))
|
||||
else:
|
||||
# Filter items which have an 'in_stock' level higher than 'minimum_stock'
|
||||
queryset = queryset.filter(Q(in_stock__gte=F('minimum_stock')))
|
||||
|
||||
return queryset
|
||||
|
||||
# has_stock filter
|
||||
has_stock = rest_filters.BooleanFilter(method='filter_has_stock')
|
||||
|
||||
def filter_has_stock(self, queryset, name, value):
|
||||
|
||||
value = str2bool(value)
|
||||
|
||||
if value:
|
||||
queryset = queryset.filter(Q(in_stock__gt=0))
|
||||
else:
|
||||
queryset = queryset.filter(Q(in_stock__lte=0))
|
||||
|
||||
return queryset
|
||||
|
||||
is_template = rest_filters.CharFilter()
|
||||
|
||||
assembly = rest_filters.BooleanFilter()
|
||||
|
||||
component = rest_filters.BooleanFilter()
|
||||
|
||||
trackable = rest_filters.BooleanFilter()
|
||||
|
||||
purchaseable = rest_filters.BooleanFilter()
|
||||
|
||||
salable = rest_filters.BooleanFilter()
|
||||
|
||||
active = rest_filters.BooleanFilter()
|
||||
|
||||
|
||||
class PartList(generics.ListCreateAPIView):
|
||||
""" API endpoint for accessing a list of Part objects
|
||||
|
||||
@ -427,8 +497,8 @@ class PartList(generics.ListCreateAPIView):
|
||||
"""
|
||||
|
||||
serializer_class = part_serializers.PartSerializer
|
||||
|
||||
queryset = Part.objects.all()
|
||||
filterset_class = PartFilter
|
||||
|
||||
starred_parts = None
|
||||
|
||||
@ -541,6 +611,10 @@ class PartList(generics.ListCreateAPIView):
|
||||
|
||||
params = self.request.query_params
|
||||
|
||||
# Annotate calculated data to the queryset
|
||||
# (This will be used for further filtering)
|
||||
queryset = part_serializers.PartSerializer.annotate_queryset(queryset)
|
||||
|
||||
queryset = super().filter_queryset(queryset)
|
||||
|
||||
# Filter by "uses" query - Limit to parts which use the provided part
|
||||
@ -578,6 +652,17 @@ class PartList(generics.ListCreateAPIView):
|
||||
else:
|
||||
queryset = queryset.filter(IPN='')
|
||||
|
||||
# Filter by IPN
|
||||
"""
|
||||
ipn = params.get('ipn', None)
|
||||
|
||||
if ipn is not None:
|
||||
|
||||
queryset = queryset.filter(IPN=ipn)
|
||||
|
||||
"""
|
||||
# Filter by IPN (regex support)
|
||||
|
||||
# Filter by whether the BOM has been validated (or not)
|
||||
bom_valid = params.get('bom_valid', None)
|
||||
|
||||
@ -643,36 +728,6 @@ class PartList(generics.ListCreateAPIView):
|
||||
except (ValueError, PartCategory.DoesNotExist):
|
||||
pass
|
||||
|
||||
# Annotate calculated data to the queryset
|
||||
# (This will be used for further filtering)
|
||||
queryset = part_serializers.PartSerializer.annotate_queryset(queryset)
|
||||
|
||||
# Filter by whether the part has stock
|
||||
has_stock = params.get("has_stock", None)
|
||||
|
||||
if has_stock is not None:
|
||||
has_stock = str2bool(has_stock)
|
||||
|
||||
if has_stock:
|
||||
queryset = queryset.filter(Q(in_stock__gt=0))
|
||||
else:
|
||||
queryset = queryset.filter(Q(in_stock__lte=0))
|
||||
|
||||
# If we are filtering by 'low_stock' status
|
||||
low_stock = params.get('low_stock', None)
|
||||
|
||||
if low_stock is not None:
|
||||
low_stock = str2bool(low_stock)
|
||||
|
||||
if low_stock:
|
||||
# Ignore any parts which do not have a specified 'minimum_stock' level
|
||||
queryset = queryset.exclude(minimum_stock=0)
|
||||
# Filter items which have an 'in_stock' level lower than 'minimum_stock'
|
||||
queryset = queryset.filter(Q(in_stock__lt=F('minimum_stock')))
|
||||
else:
|
||||
# Filter items which have an 'in_stock' level higher than 'minimum_stock'
|
||||
queryset = queryset.filter(Q(in_stock__gte=F('minimum_stock')))
|
||||
|
||||
# Filer by 'depleted_stock' status -> has no stock and stock items
|
||||
depleted_stock = params.get('depleted_stock', None)
|
||||
|
||||
@ -722,14 +777,7 @@ class PartList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
filter_fields = [
|
||||
'is_template',
|
||||
'variant_of',
|
||||
'assembly',
|
||||
'component',
|
||||
'trackable',
|
||||
'purchaseable',
|
||||
'salable',
|
||||
'active',
|
||||
]
|
||||
|
||||
ordering_fields = [
|
||||
|
19
InvenTree/part/migrations/0070_alter_part_variant_of.py
Normal file
19
InvenTree/part/migrations/0070_alter_part_variant_of.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.4 on 2021-07-08 07:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('part', '0069_auto_20210701_0509'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='part',
|
||||
name='variant_of',
|
||||
field=models.ForeignKey(blank=True, help_text='Is this part a variant of another part?', limit_choices_to={'is_template': True}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='variants', to='part.part', verbose_name='Variant Of'),
|
||||
),
|
||||
]
|
@ -692,7 +692,6 @@ class Part(MPTTModel):
|
||||
null=True, blank=True,
|
||||
limit_choices_to={
|
||||
'is_template': True,
|
||||
'active': True,
|
||||
},
|
||||
on_delete=models.SET_NULL,
|
||||
help_text=_('Is this part a variant of another part?'),
|
||||
|
Loading…
Reference in New Issue
Block a user