mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-26 00:30:51 +00:00
Relation update (#8524)
* Add "note" field to PartRelated model * Improved API * Add field to serializer * Implement in RelatedPartTable * Bump API version
This commit is contained in:
src
backend
InvenTree
frontend
src
tables
@ -1,13 +1,16 @@
|
||||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 282
|
||||
INVENTREE_API_VERSION = 283
|
||||
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v283 - 2024-11-20 : https://github.com/inventree/InvenTree/pull/8524
|
||||
- Adds "note" field to the PartRelated API endpoint
|
||||
|
||||
v282 - 2024-11-19 : https://github.com/inventree/InvenTree/pull/8487
|
||||
- Remove the "test statistics" API endpoints
|
||||
- This is now provided via a custom plugin
|
||||
|
@ -1427,37 +1427,50 @@ class PartDetail(PartMixin, RetrieveUpdateDestroyAPI):
|
||||
return response
|
||||
|
||||
|
||||
class PartRelatedList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartRelated objects."""
|
||||
class PartRelatedFilter(rest_filters.FilterSet):
|
||||
"""FilterSet for PartRelated objects."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
model = PartRelated
|
||||
fields = ['part_1', 'part_2']
|
||||
|
||||
part = rest_filters.ModelChoiceFilter(
|
||||
queryset=Part.objects.all(), method='filter_part', label=_('Part')
|
||||
)
|
||||
|
||||
def filter_part(self, queryset, name, part):
|
||||
"""Filter queryset to include only PartRelated objects which reference the specified part."""
|
||||
return queryset.filter(Q(part_1=part) | Q(part_2=part)).distinct()
|
||||
|
||||
|
||||
class PartRelatedMixin:
|
||||
"""Mixin class for PartRelated API endpoints."""
|
||||
|
||||
queryset = PartRelated.objects.all()
|
||||
serializer_class = part_serializers.PartRelationSerializer
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
"""Custom queryset filtering."""
|
||||
queryset = super().filter_queryset(queryset)
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
"""Return an annotated queryset for the PartRelatedDetail endpoint."""
|
||||
queryset = super().get_queryset(*args, **kwargs)
|
||||
|
||||
params = self.request.query_params
|
||||
|
||||
# Add a filter for "part" - we can filter either part_1 or part_2
|
||||
part = params.get('part', None)
|
||||
|
||||
if part is not None:
|
||||
try:
|
||||
part = Part.objects.get(pk=part)
|
||||
queryset = queryset.filter(Q(part_1=part) | Q(part_2=part)).distinct()
|
||||
|
||||
except (ValueError, Part.DoesNotExist):
|
||||
pass
|
||||
queryset = queryset.prefetch_related('part_1', 'part_2')
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class PartRelatedDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for accessing detail view of a PartRelated object."""
|
||||
class PartRelatedList(PartRelatedMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartRelated objects."""
|
||||
|
||||
queryset = PartRelated.objects.all()
|
||||
serializer_class = part_serializers.PartRelationSerializer
|
||||
filterset_class = PartRelatedFilter
|
||||
filter_backends = SEARCH_ORDER_FILTER
|
||||
|
||||
search_fields = ['part_1__name', 'part_2__name']
|
||||
|
||||
|
||||
class PartRelatedDetail(PartRelatedMixin, RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for accessing detail view of a PartRelated object."""
|
||||
|
||||
|
||||
class PartParameterTemplateFilter(rest_filters.FilterSet):
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.16 on 2024-11-19 12:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('part', '0130_alter_parttesttemplate_part'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='partrelated',
|
||||
name='note',
|
||||
field=models.CharField(blank=True, help_text='Note for this relationship', max_length=500, verbose_name='Note'),
|
||||
),
|
||||
]
|
@ -4680,6 +4680,13 @@ class PartRelated(InvenTree.models.InvenTreeMetadataModel):
|
||||
help_text=_('Select Related Part'),
|
||||
)
|
||||
|
||||
note = models.CharField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
verbose_name=_('Note'),
|
||||
help_text=_('Note for this relationship'),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
"""Return a string representation of this Part-Part relationship."""
|
||||
return f'{self.part_1} <--> {self.part_2}'
|
||||
|
@ -1505,7 +1505,7 @@ class PartRelationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||
"""Metaclass defining serializer fields."""
|
||||
|
||||
model = PartRelated
|
||||
fields = ['pk', 'part_1', 'part_1_detail', 'part_2', 'part_2_detail']
|
||||
fields = ['pk', 'part_1', 'part_1_detail', 'part_2', 'part_2_detail', 'note']
|
||||
|
||||
part_1_detail = PartSerializer(source='part_1', read_only=True, many=False)
|
||||
part_2_detail = PartSerializer(source='part_2', read_only=True, many=False)
|
||||
|
Reference in New Issue
Block a user