From e06121ebdac6063c8d0608b694ba11b7e136330b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 11 Apr 2017 09:41:03 +1000 Subject: [PATCH] Updated API URLs --- InvenTree/InvenTree/api_urls.py | 12 ++++++ InvenTree/InvenTree/models.py | 69 ++++++++++++++++++--------------- InvenTree/InvenTree/urls.py | 17 +------- InvenTree/part/api_urls.py | 17 ++++++++ InvenTree/part/models.py | 6 +++ InvenTree/part/serializers.py | 48 +++++++++++++++++++++-- InvenTree/part/urls.py | 16 +++----- InvenTree/part/views.py | 24 +++++++----- InvenTree/project/api_urls.py | 6 +++ 9 files changed, 144 insertions(+), 71 deletions(-) create mode 100644 InvenTree/InvenTree/api_urls.py create mode 100644 InvenTree/part/api_urls.py create mode 100644 InvenTree/project/api_urls.py diff --git a/InvenTree/InvenTree/api_urls.py b/InvenTree/InvenTree/api_urls.py new file mode 100644 index 0000000000..0a742f2fe5 --- /dev/null +++ b/InvenTree/InvenTree/api_urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import url, include +from django.contrib import admin + +admin.site.site_header = "InvenTree Admin" + +urlpatterns = [ + url(r'^stock/', include('stock.urls')), + url(r'^part/', include('part.api_urls')), + url(r'^supplier/', include('supplier.urls')), + url(r'^track/', include('track.urls')), + url(r'^project/', include('project.api_urls')) +] diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 7e06b1a183..0de4d636bb 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -8,10 +8,10 @@ from django.contrib.contenttypes.models import ContentType class Company(models.Model): """ Abstract model representing an external company """ - + class Meta: abstract = True - + name = models.CharField(max_length=100) URL = models.URLField(blank=True) address = models.CharField(max_length=200, @@ -33,10 +33,10 @@ class InvenTreeTree(models.Model): - Each Category has one parent Category, which can be blank (for a top-level Category). - Each Category can have zero-or-more child Categor(y/ies) """ - + class Meta: abstract = True - + name = models.CharField(max_length=100) description = models.CharField(max_length=250, blank=True) parent = models.ForeignKey('self', @@ -44,95 +44,102 @@ class InvenTreeTree(models.Model): blank=True, null=True, related_name='children') - + def getUniqueParents(self, unique=None): """ Return a flat set of all parent items that exist above this node. If any parents are repeated (which would be very bad!), the process is halted """ - + if unique is None: unique = set() else: unique.add(self.id) - + if self.parent and self.parent.id not in unique: self.parent.getUniqueParents(unique) - + return unique - + def getUniqueChildren(self, unique=None): """ Return a flat set of all child items that exist under this node. If any child items are repeated, the repetitions are omitted. """ - + if unique is None: unique = set() - + if self.id in unique: return unique - + unique.add(self.id) - + # Some magic to get around the limitations of abstract models contents = ContentType.objects.get_for_model(type(self)) children = contents.get_all_objects_for_this_type(parent=self.id) - + return unique - + + @property + def children(self): + contents = ContentType.objects.get_for_model(type(self)) + children = contents.get_all_objects_for_this_type(parent=self.id) + + return children + def getAcceptableParents(self): """ Returns a list of acceptable parent items within this model Acceptable parents are ones which are not underneath this item. Setting the parent of an item to its own child results in recursion. """ contents = ContentType.objects.get_for_model(type(self)) - + available = contents.get_all_objects_for_this_type() - + # List of child IDs childs = getUniqueChildren() - + acceptable = [None] - + for a in available: if a.id not in childs: acceptable.append(a) - + return acceptable - + @property def parentpath(self): """ Return the parent path of this category - + Todo: This function is recursive and expensive. It should be reworked such that only a single db call is required """ - + if self.parent: return self.parent.parentpath + [self.parent] else: return [] - + @property def path(self): if self.parent: return "/".join([p.name for p in self.parentpath]) + "/" + self.name else: return self.name - + def __setattr__(self, attrname, val): """ Custom Attribute Setting function - + Parent: Setting the parent of an item to its own child results in an infinite loop. The parent of an item cannot be set to: a) Its own ID b) The ID of any child items that exist underneath it - + Name: Tree node names are limited to a reduced character set """ - + if attrname == 'parent_id': # If current ID is None, continue # - This object is just being created @@ -153,14 +160,14 @@ class InvenTreeTree(models.Model): # Prohibit certain characters from tree node names elif attrname == 'name': val = val.translate({ord(c): None for c in "!@#$%^&*'\"\\/[]{}<>,|+=~`"}) - + super(InvenTreeTree, self).__setattr__(attrname, val) def __str__(self): """ String representation of a category is the full path to that category - + Todo: This is recursive - Make it not so. """ - + return self.path diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 52b69c4a95..b00372d97b 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -1,25 +1,10 @@ -"""InvenTree URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.10/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" - from django.conf.urls import url, include from django.contrib import admin admin.site.site_header = "InvenTree Admin" urlpatterns = [ + url(r'^api/', include('InvenTree.api_urls')), url(r'^stock/', include('stock.urls')), url(r'^part/', include('part.urls')), url(r'^supplier/', include('supplier.urls')), diff --git a/InvenTree/part/api_urls.py b/InvenTree/part/api_urls.py new file mode 100644 index 0000000000..c220617154 --- /dev/null +++ b/InvenTree/part/api_urls.py @@ -0,0 +1,17 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + # Display part detail + url(r'^(?P[0-9]+)/$', views.PartDetail.as_view()), + + # Display a single part category + url(r'^category/(?P[0-9]+)/$', views.PartCategoryDetail.as_view()), + + # Display a list of top-level categories + url(r'^category/$', views.PartCategoryList.as_view()), + + # Display list of all parts + url(r'^$', views.PartList.as_view()) +] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index e9473d06dc..9ba26149ae 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -15,6 +15,12 @@ class PartCategory(InvenTreeTree): verbose_name = "Part Category" verbose_name_plural = "Part Categories" + @property + def parts(self): + parts_list = self.part_set.all() + print(parts_list) + return parts_list + class Part(models.Model): """ Represents a """ diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 9dea0f0231..523b55f9eb 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -4,14 +4,21 @@ from .models import Part, PartCategory, PartParameter class ParameterSerializer(serializers.ModelSerializer): + """ Serializer for a PartParameter + """ + class Meta: model = PartParameter - fields = ('name', + fields = ('pk', + 'name', 'value', 'units') -class PartSerializer(serializers.ModelSerializer): +class PartDetailSerializer(serializers.ModelSerializer): + """ Serializer for complete detail information of a part. + Used when displaying all details of a single component. + """ params = ParameterSerializer(source='parameters', many=True) @@ -26,11 +33,44 @@ class PartSerializer(serializers.ModelSerializer): 'params') -class PartCategorySerializer(serializers.ModelSerializer): +class PartBriefSerializer(serializers.ModelSerializer): + """ Serializer for displaying overview of a part. + Used e.g. for displaying list of parts in a category. + """ + + class Meta: + model = Part + fields = ('pk', + 'name', + 'IPN', + 'description', + 'category', + 'stock') + + +class PartCategoryBriefSerializer(serializers.ModelSerializer): + + class Meta: + model = PartCategory + fields = ('pk', + 'name', + 'description') + + +class PartCategoryDetailSerializer(serializers.ModelSerializer): + + # List of parts in this category + parts = PartBriefSerializer(many=True) + + # List of child categories under this one + children = PartCategoryBriefSerializer(many=True) + class Meta: model = PartCategory fields = ('pk', 'name', 'description', 'parent', - 'path') + 'path', + 'children', + 'parts') diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 01ebb11cbf..f14151b51a 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -3,15 +3,9 @@ from django.conf.urls import url from . import views urlpatterns = [ - # Display part detail - url(r'^(?P[0-9]+)/$', views.PartDetail.as_view()), - - # Display a single part category - url(r'^category/(?P[0-9]+)/$', views.PartCategoryDetail.as_view()), - - # Display a list of top-level categories - url(r'^category/$', views.PartCategoryList.as_view()), - - # Display list of parts - url(r'^$', views.PartList.as_view()) + # part landing page + url(r'^$', views.part_index), + + # part category landing page + url(r'^category/$', views.category_index) ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 28d447303e..37b59486ca 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -4,32 +4,38 @@ from django.http import HttpResponse, Http404 from rest_framework import generics from .models import PartCategory, Part -from .serializers import PartSerializer, PartCategorySerializer +from .serializers import PartBriefSerializer, PartDetailSerializer +from .serializers import PartCategoryBriefSerializer, PartCategoryDetailSerializer -def index(request): +def part_index(request): return HttpResponse("Hello world. This is the parts page") +def category_index(request): + return HttpResponse("This is the category page") class PartDetail(generics.RetrieveAPIView): queryset = Part.objects.all() - serializer_class = PartSerializer + serializer_class = PartDetailSerializer class PartList(generics.ListAPIView): queryset = Part.objects.all() - serializer_class = PartSerializer + serializer_class = PartBriefSerializer class PartCategoryDetail(generics.RetrieveAPIView): - + """ Return information on a single PartCategory + """ queryset = PartCategory.objects.all() - serializer_class = PartCategorySerializer + serializer_class = PartCategoryDetailSerializer class PartCategoryList(generics.ListAPIView): - - queryset = PartCategory.objects.all() - serializer_class = PartCategorySerializer + """ Return a list of all top-level part categories. + Categories are considered "top-level" if they do not have a parent + """ + queryset = PartCategory.objects.filter(parent=None) + serializer_class = PartCategoryBriefSerializer diff --git a/InvenTree/project/api_urls.py b/InvenTree/project/api_urls.py new file mode 100644 index 0000000000..65b34d128c --- /dev/null +++ b/InvenTree/project/api_urls.py @@ -0,0 +1,6 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ +]