Merge pull request #39 from SchrodingersGat/master

Added hyperlinks and docs to API
This commit is contained in:
Oliver 2017-04-15 00:56:27 +10:00 committed by GitHub
commit 150e1bb34c
24 changed files with 281 additions and 210 deletions

View File

@ -12,7 +12,7 @@ class Company(models.Model):
abstract = True
name = models.CharField(max_length=100)
URL = models.URLField(blank=True)
website = models.URLField(blank=True)
address = models.CharField(max_length=200,
blank=True)
phone = models.CharField(max_length=50,
@ -35,6 +35,7 @@ class InvenTreeTree(models.Model):
class Meta:
abstract = True
unique_together = ('name', 'parent')
name = models.CharField(max_length=100)
description = models.CharField(max_length=250, blank=True)
@ -184,7 +185,7 @@ def FilterChildren(queryset, parent):
if not parent:
return queryset
elif isinstance(parent, str) and parent.lower() in ['none', 'false', 'null', 'top', '0']:
elif str(parent).lower() in ['none', 'false', 'null', 'top', '0']:
return queryset.filter(parent=None)
else:
try:

View File

@ -1,30 +1,29 @@
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.documentation import include_docs_urls
admin.site.site_header = "InvenTree Admin"
@api_view()
def Inventree404(self):
""" Supplied URL is invalid
"""
content = {'detail': 'Malformed API URL'}
return Response(content, status=status.HTTP_404_NOT_FOUND)
apipatterns = [
url(r'^stock/', include('stock.urls')),
url(r'^stock-location/', include('stock.location_urls')),
url(r'^part/', include('part.urls')),
url(r'^supplier/', include('supplier.urls')),
url(r'^supplier-part/', include('supplier.part_urls')),
url(r'^price-break/', include('supplier.price_urls')),
url(r'^manufacturer/', include('supplier.manufacturer_urls')),
url(r'^customer/', include('supplier.customer_urls')),
url(r'^track/', include('track.urls')),
url(r'^project/', include('project.urls')),
]
urlpatterns = [
url(r'^stock/?', include('stock.urls')),
url(r'^part/?', include('part.urls')),
url(r'^supplier/?', include('supplier.urls')),
url(r'^track/?', include('track.urls')),
url(r'^project/?', include('project.urls')),
url(r'^admin/?', admin.site.urls),
url(r'^auth/?', include('rest_framework.urls', namespace='rest_framework')),
# API URL
url(r'^api/', include(apipatterns)),
# Any other URL
url(r'', Inventree404)
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
url(r'^admin/', admin.site.urls),
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
]

View File

@ -17,14 +17,14 @@ class PartParameterSerializer(serializers.ModelSerializer):
'units')
class PartSerializer(serializers.ModelSerializer):
class PartSerializer(serializers.HyperlinkedModelSerializer):
""" Serializer for complete detail information of a part.
Used when displaying all details of a single component.
"""
class Meta:
model = Part
fields = ('pk',
fields = ('url',
'name',
'IPN',
'description',
@ -32,21 +32,15 @@ class PartSerializer(serializers.ModelSerializer):
'stock')
class PartCategorySerializer(serializers.ModelSerializer):
children = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
parts = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class PartCategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = PartCategory
fields = ('pk',
fields = ('url',
'name',
'description',
'parent',
'path',
'children',
'parts')
'path')
class PartTemplateSerializer(serializers.ModelSerializer):

View File

@ -10,25 +10,28 @@ from . import views
categorypatterns = [
# Part category detail
url(r'^(?P<pk>[0-9]+)/?$', views.PartCategoryDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.PartCategoryDetail.as_view(), name='partcategory-detail'),
# List of top-level categories
url(r'^\?*[^/]*/?$', views.PartCategoryList.as_view())
url(r'^\?*.*/?$', views.PartCategoryList.as_view()),
url(r'^$', views.PartCategoryList.as_view())
]
partparampatterns = [
# Detail of a single part parameter
url(r'^(?P<pk>[0-9]+)/?$', views.PartParamDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.PartParamDetail.as_view(), name='partparameter-detail'),
# Parameters associated with a particular part
url(r'^\?*[^/]*/?$', views.PartParamList.as_view()),
url(r'^\?.*/?$', views.PartParamList.as_view()),
url(r'^$', views.PartParamList.as_view()),
]
parttemplatepatterns = [
# Detail of a single part field template
url(r'^(?P<pk>[0-9]+)/?$', views.PartTemplateDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.PartTemplateDetail.as_view(), name='partparametertemplate-detail'),
# List all part field templates
url(r'^\?.*/?$', views.PartTemplateList.as_view()),
url(r'^$', views.PartTemplateList.as_view())
]
@ -39,18 +42,19 @@ parttemplatepatterns = [
/part/category -> (refer to categorypatterns)
"""
urlpatterns = [
# Individual part
url(r'^(?P<pk>[0-9]+)/?$', views.PartDetail.as_view()),
# Part categories
url(r'^category/?', include(categorypatterns)),
url(r'^category/', include(categorypatterns)),
# Part parameters
url(r'^parameters/?', include(partparampatterns)),
url(r'^parameter/', include(partparampatterns)),
# Part templates
url(r'^templates/?', include(parttemplatepatterns)),
url(r'^template/', include(parttemplatepatterns)),
# Individual part
url(r'^(?P<pk>[0-9]+)/?$', views.PartDetail.as_view(), name='part-detail'),
# List parts with optional filters
url(r'^\?*[^/]*/?$', views.PartList.as_view()),
url(r'^\?.*/?$', views.PartList.as_view()),
url(r'^$', views.PartList.as_view()),
]

View File

@ -3,41 +3,33 @@ from rest_framework import serializers
from .models import ProjectCategory, Project, ProjectPart
class ProjectPartSerializer(serializers.ModelSerializer):
class ProjectPartSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ProjectPart
fields = ('pk',
fields = ('url',
'part',
'project',
'quantity',
'output')
class ProjectSerializer(serializers.ModelSerializer):
""" Serializer for displaying brief overview of a project
"""
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Project
fields = ('pk',
fields = ('url',
'name',
'description',
'category')
class ProjectCategorySerializer(serializers.ModelSerializer):
children = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
projects = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class ProjectCategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ProjectCategory
fields = ('pk',
fields = ('url',
'name',
'description',
'parent',
'path',
'children',
'projects')
'path')

View File

@ -2,41 +2,35 @@ from django.conf.urls import url, include
from . import views
""" URL patterns associated with project
/project/<pk> -> Detail view of single project
/project/<pk>/parts -> Detail all parts associated with project
"""
projectdetailpatterns = [
# Single project detail
url(r'^$', views.ProjectDetail.as_view()),
]
projectpartpatterns = [
# Detail of a single project part
url(r'^(?P<pk>[0-9]+)/?$', views.ProjectPartDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.ProjectPartDetail.as_view(), name='projectpart-detail'),
# List project parts, with optional filters
url(r'^\?*[^/]*/?$', views.ProjectPartsList.as_view()),
url(r'^\?.*/?$', views.ProjectPartsList.as_view()),
url(r'^$', views.ProjectPartsList.as_view()),
]
projectcategorypatterns = [
# Detail of a single project category
url(r'^(?P<pk>[0-9]+)/?$', views.ProjectCategoryDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.ProjectCategoryDetail.as_view(), name='projectcategory-detail'),
# List of project categories, with filters
url(r'^\?*[^/]*/?$', views.ProjectCategoryList.as_view()),
url(r'^\?.*/?$', views.ProjectCategoryList.as_view()),
url(r'^$', views.ProjectCategoryList.as_view()),
]
urlpatterns = [
# Individual project URL
url(r'^(?P<pk>[0-9]+)/?', include(projectdetailpatterns)),
url(r'^(?P<pk>[0-9]+)/?$', views.ProjectDetail.as_view(), name='project-detail'),
# List of all projects
url(r'^\?.*/?$', views.ProjectList.as_view()),
url(r'^$', views.ProjectList.as_view()),
# Project parts
url(r'^parts/?', include(projectpartpatterns)),
url(r'^parts/', include(projectpartpatterns)),
# Project categories
url(r'^category/?', include(projectcategorypatterns)),
url(r'^category/', include(projectcategorypatterns)),
]

View File

@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.LocationDetail.as_view(), name='stocklocation-detail'),
url(r'^\?.*/?$', views.LocationList.as_view()),
url(r'^$', views.LocationList.as_view())
]

View File

@ -3,13 +3,13 @@ from rest_framework import serializers
from .models import StockItem, StockLocation
class StockItemSerializer(serializers.ModelSerializer):
class StockItemSerializer(serializers.HyperlinkedModelSerializer):
""" Serializer for a StockItem
"""
class Meta:
model = StockItem
fields = ('pk',
fields = ('url',
'part',
'location',
'quantity',
@ -20,24 +20,13 @@ class StockItemSerializer(serializers.ModelSerializer):
'expected_arrival')
class LocationBriefSerializer(serializers.ModelSerializer):
""" Brief information about a stock location
"""
class Meta:
model = StockLocation
fields = ('pk',
'name',
'description')
class LocationDetailSerializer(serializers.ModelSerializer):
class LocationSerializer(serializers.HyperlinkedModelSerializer):
""" Detailed information about a stock location
"""
class Meta:
model = StockLocation
fields = ('pk',
fields = ('url',
'name',
'description',
'parent',

View File

@ -1,20 +1,12 @@
from django.conf.urls import url, include
from django.conf.urls import url
from . import views
locpatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.LocationDetail.as_view()),
url(r'^\?*[^/]*/?$', views.LocationList.as_view())
]
urlpatterns = [
# Stock location urls
url(r'^location/?', include(locpatterns)),
# Detail for a single stock item
url(r'^(?P<pk>[0-9]+)$', views.StockDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.StockDetail.as_view(), name='stockitem-detail'),
# List all stock items, with optional filters
url(r'^\?*[^/]*/?$', views.StockList.as_view()),
url(r'^\?.*/?$', views.StockList.as_view()),
url(r'^$', views.StockList.as_view()),
]

View File

@ -1,9 +1,12 @@
from rest_framework import generics, permissions
import django_filters
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
from django_filters import NumberFilter
from InvenTree.models import FilterChildren
from rest_framework import generics, permissions
# from InvenTree.models import FilterChildren
from .models import StockLocation, StockItem
from .serializers import StockItemSerializer, LocationDetailSerializer
from .serializers import StockItemSerializer, LocationSerializer
class StockDetail(generics.RetrieveUpdateDestroyAPIView):
@ -14,60 +17,50 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView):
class StockFilter(django_filters.rest_framework.FilterSet):
min_stock = django_filters.NumberFilter(name='quantity', lookup_expr='gte')
max_stock = django_filters.NumberFilter(name='quantity', lookup_expr='lte')
min_stock = NumberFilter(name='quantity', lookup_expr='gte')
max_stock = NumberFilter(name='quantity', lookup_expr='lte')
part = NumberFilter(name='part', lookup_expr='exact')
location = NumberFilter(name='location', lookup_expr='exact')
class Meta:
model = StockItem
fields = ['quantity']
fields = ['quantity', 'part', 'location']
class StockList(generics.ListCreateAPIView):
queryset = StockItem.objects.all()
serializer_class = StockItemSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
filter_backends = (DjangoFilterBackend,)
filter_class = StockFilter
def get_queryset(self):
items = StockItem.objects.all()
# Specify a particular part
part_id = self.request.query_params.get('part', None)
if part_id:
items = items.filter(part=part_id)
# Specify a particular location
loc_id = self.request.query_params.get('location', None)
if loc_id:
items = items.filter(location=loc_id)
return items
class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
""" Return information on a specific stock location
"""
queryset = StockLocation.objects.all()
serializer_class = LocationDetailSerializer
serializer_class = LocationSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class StockLocationFilter(FilterSet):
parent = NumberFilter(name='parent', lookup_expr='exact')
class Meta:
model = StockLocation
fields = ['parent']
class LocationList(generics.ListCreateAPIView):
""" Return a list of top-level locations
Locations are considered "top-level" if they do not have a parent
"""
def get_queryset(self):
params = self.request.query_params
locations = StockLocation.objects.all()
locations = FilterChildren(locations, params.get('parent', None))
return locations
serializer_class = LocationDetailSerializer
queryset = StockLocation.objects.all()
serializer_class = LocationSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
filter_backends = (DjangoFilterBackend,)
filter_class = StockLocationFilter

View File

@ -4,7 +4,7 @@ from .models import Supplier, SupplierPart, Customer, Manufacturer
class CompanyAdmin(admin.ModelAdmin):
list_display = ('name', 'URL', 'contact')
list_display = ('name', 'website', 'contact')
admin.site.register(Customer, CompanyAdmin)

View File

@ -0,0 +1,12 @@
from django.conf.urls import url
from . import views
urlpatterns = [
# Customer detail
url(r'^(?P<pk>[0-9]+)/?$', views.CustomerDetail.as_view(), name='customer-detail'),
# List customers
url(r'^\?.*/?$', views.CustomerList.as_view()),
url(r'^$', views.CustomerList.as_view())
]

View File

@ -0,0 +1,12 @@
from django.conf.urls import url
from . import views
urlpatterns = [
# Manufacturer detail
url(r'^(?P<pk>[0-9]+)/?$', views.ManufacturerDetail.as_view(), name='manufacturer-detail'),
# List manufacturers
url(r'^\?.*/?$', views.ManufacturerList.as_view()),
url(r'^$', views.ManufacturerList.as_view())
]

View File

@ -31,6 +31,9 @@ class SupplierPart(models.Model):
- A Part may be available from multiple suppliers
"""
class Meta:
unique_together = ('part', 'supplier', 'SKU')
part = models.ForeignKey(Part, null=True, blank=True, on_delete=models.CASCADE)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
SKU = models.CharField(max_length=100)

View File

@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierPartDetail.as_view(), name='supplierpart-detail'),
url(r'^\?.*/?$', views.SupplierPartList.as_view()),
url(r'^$', views.SupplierPartList.as_view())
]

View File

@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierPriceBreakDetail.as_view(), name='supplierpricebreak-detail'),
url(r'^\?.*/?$', views.SupplierPriceBreakList.as_view()),
url(r'^$', views.SupplierPriceBreakList.as_view())
]

View File

@ -1,22 +1,51 @@
from rest_framework import serializers
from part.models import Part
from .models import Supplier, SupplierPart, SupplierPriceBreak
from .models import Manufacturer
from .models import Customer
class SupplierSerializer(serializers.ModelSerializer):
class SupplierSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Supplier
fields = '__all__'
class ManufacturerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Manufacturer
fields = '__all__'
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Customer
fields = '__all__'
class SupplierPartSerializer(serializers.ModelSerializer):
price_breaks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
price_breaks = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='supplierpricebreak-detail')
part = serializers.HyperlinkedRelatedField(view_name='part-detail',
queryset=Part.objects.all())
supplier = serializers.HyperlinkedRelatedField(view_name='supplier-detail',
queryset=Supplier.objects.all())
manufacturer = serializers.HyperlinkedRelatedField(view_name='manufacturer-detail',
queryset=Manufacturer.objects.all())
class Meta:
model = SupplierPart
fields = ['pk',
fields = ['url',
'part',
'supplier',
'SKU',
@ -32,11 +61,11 @@ class SupplierPartSerializer(serializers.ModelSerializer):
'lead_time']
class SupplierPriceBreakSerializer(serializers.ModelSerializer):
class SupplierPriceBreakSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = SupplierPriceBreak
fields = ['pk',
fields = ['url',
'part',
'quantity',
'cost']

View File

@ -1,30 +1,20 @@
from django.conf.urls import url, include
from django.conf.urls import url
from . import views
partpatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierPartDetail.as_view()),
url(r'^\?*[^/]*/?$', views.SupplierPartList.as_view())
]
pricepatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierPriceBreakDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierPriceBreakDetail.as_view(), name='supplierpricebreak-detail'),
url(r'^\?*[^/]*/?$', views.SupplierPriceBreakList.as_view())
url(r'^\?.*/?$', views.SupplierPriceBreakList.as_view()),
url(r'^$', views.SupplierPriceBreakList.as_view())
]
urlpatterns = [
# Supplier part information
url(r'part/?', include(partpatterns)),
# Supplier price information
url(r'price/?', include(pricepatterns)),
# Display details of a supplier
url(r'^(?P<pk>[0-9]+)/?$', views.SupplierDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/$', views.SupplierDetail.as_view(), name='supplier-detail'),
# List suppliers
url(r'^\?*[^/]*/?$', views.SupplierList.as_view())
url(r'^\?.*/?$', views.SupplierList.as_view()),
url(r'^$', views.SupplierList.as_view())
]

View File

@ -1,9 +1,43 @@
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
from django_filters import NumberFilter
from rest_framework import generics, permissions
from .models import Supplier, SupplierPart, SupplierPriceBreak
from .models import Manufacturer, Customer
from .serializers import SupplierSerializer
from .serializers import SupplierPartSerializer
from .serializers import SupplierPriceBreakSerializer
from .serializers import ManufacturerSerializer
from .serializers import CustomerSerializer
class ManufacturerDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Manufacturer.objects.all()
serializer_class = ManufacturerSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ManufacturerList(generics.ListCreateAPIView):
queryset = Manufacturer.objects.all()
serializer_class = ManufacturerSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class CustomerDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class CustomerList(generics.ListCreateAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class SupplierDetail(generics.RetrieveUpdateDestroyAPIView):
@ -27,28 +61,27 @@ class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class SupplierPartFilter(FilterSet):
supplier = NumberFilter(name='supplier', lookup_expr='exact')
part = NumberFilter(name='part', lookup_expr='exact')
manufacturer = NumberFilter(name='manufacturer', lookup_expr='exact')
class Meta:
model = SupplierPart
fields = ['supplier', 'part', 'manufacturer']
class SupplierPartList(generics.ListCreateAPIView):
queryset = SupplierPart.objects.all()
serializer_class = SupplierPartSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self):
parts = SupplierPart.objects.all()
params = self.request.query_params
supplier_id = params.get('supplier', None)
if supplier_id:
parts = parts.filter(supplier=supplier_id)
part_id = params.get('part', None)
if part_id:
parts = parts.filter(part=part_id)
manu_id = params.get('manufacturer', None)
if manu_id:
parts = parts.filter(manufacturer=manu_id)
return parts
filter_backends = (DjangoFilterBackend,)
filter_class = SupplierPartFilter
class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView):
@ -58,17 +91,20 @@ class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class PriceBreakFilter(FilterSet):
part = NumberFilter(name='part', lookup_expr='exact')
class Meta:
model = SupplierPriceBreak
fields = ['part']
class SupplierPriceBreakList(generics.ListCreateAPIView):
def get_queryset(self):
prices = SupplierPriceBreak.objects.all()
params = self.request.query_params
part_id = params.get('part', None)
if part_id:
prices = prices.filter(part=part_id)
return prices
queryset = SupplierPriceBreak.objects.all()
serializer_class = SupplierPriceBreakSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
filter_backends = (DjangoFilterBackend,)
filter_class = PriceBreakFilter

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.db import models
from django.contrib.auth.models import User
# from django.contrib.auth.models import User
from supplier.models import Customer
from part.models import Part, PartRevision
@ -37,6 +37,10 @@ class UniquePart(models.Model):
and tracking all events in the life of a part
"""
class Meta:
# Cannot have multiple parts with same serial number
unique_together = ('part', 'serial')
objects = UniquePartManager()
part = models.ForeignKey(Part, on_delete=models.CASCADE)
@ -50,7 +54,7 @@ class UniquePart(models.Model):
editable=False)
serial = models.IntegerField()
createdBy = models.ForeignKey(User)
# createdBy = models.ForeignKey(User)
customer = models.ForeignKey(Customer, blank=True, null=True)
@ -76,17 +80,6 @@ class UniquePart(models.Model):
def __str__(self):
return self.part.name
def save(self, *args, **kwargs):
# Disallow saving a serial number that already exists
matches = UniquePart.objects.filter(serial=self.serial, part=self.part)
matches = matches.filter(~models.Q(id=self.id))
if len(matches) > 0:
raise ValidationError(_("Matching serial number already exists"))
super(UniquePart, self).save(*args, **kwargs)
class PartTrackingInfo(models.Model):
""" Single data-point in the life of a UniquePart

View File

@ -3,24 +3,24 @@ from rest_framework import serializers
from .models import UniquePart, PartTrackingInfo
class UniquePartSerializer(serializers.ModelSerializer):
class UniquePartSerializer(serializers.HyperlinkedModelSerializer):
tracking_info = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = UniquePart
fields = ['pk',
fields = ['url',
'part',
'revision',
'creation_date',
'serial',
'createdBy',
# 'createdBy',
'customer',
'status',
'tracking_info']
class PartTrackingInfoSerializer(serializers.ModelSerializer):
class PartTrackingInfoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = PartTrackingInfo

View File

@ -3,17 +3,19 @@ from django.conf.urls import url, include
from . import views
infopatterns = [
url(r'^(?P<pk>[0-9]+)/?$', views.PartTrackingDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.PartTrackingDetail.as_view(), name='parttrackinginfo-detail'),
url(r'^\?*[^/]*/?$', views.PartTrackingList.as_view())
url(r'^\?.*/?$', views.PartTrackingList.as_view()),
url(r'^$', views.PartTrackingList.as_view())
]
urlpatterns = [
url(r'info/?', include(infopatterns)),
url(r'info/', include(infopatterns)),
# Detail for a single unique part
url(r'^(?P<pk>[0-9]+)$', views.UniquePartDetail.as_view()),
url(r'^(?P<pk>[0-9]+)/?$', views.UniquePartDetail.as_view(), name='uniquepart-detail'),
# List all unique parts, with optional filters
url(r'^\?*[^/]*/?$', views.UniquePartList.as_view()),
url(r'^\?.*/?$', views.UniquePartList.as_view()),
url(r'^$', views.UniquePartList.as_view()),
]

View File

@ -15,7 +15,11 @@ test:
python InvenTree/manage.py test --noinput
migrate:
python InvenTree/manage.py makemigrations
python InvenTree/manage.py makemigrations part
python InvenTree/manage.py makemigrations project
python InvenTree/manage.py makemigrations stock
python InvenTree/manage.py makemigrations supplier
python InvenTree/manage.py makemigrations track
python InvenTree/manage.py migrate --run-syncdb
python InvenTree/manage.py check

View File

@ -1,3 +1,5 @@
Django==1.11
djangorestframework==3.6.2
django_filter==1.0.2
coreapi==2.3.0
pygments==2.2.0