mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
commit
d7c67fbaa4
12
InvenTree/InvenTree/api_urls.py
Normal file
12
InvenTree/InvenTree/api_urls.py
Normal file
@ -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'))
|
||||||
|
]
|
@ -8,10 +8,10 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
class Company(models.Model):
|
class Company(models.Model):
|
||||||
""" Abstract model representing an external company
|
""" Abstract model representing an external company
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
URL = models.URLField(blank=True)
|
URL = models.URLField(blank=True)
|
||||||
address = models.CharField(max_length=200,
|
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 has one parent Category, which can be blank (for a top-level Category).
|
||||||
- Each Category can have zero-or-more child Categor(y/ies)
|
- Each Category can have zero-or-more child Categor(y/ies)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
description = models.CharField(max_length=250, blank=True)
|
description = models.CharField(max_length=250, blank=True)
|
||||||
parent = models.ForeignKey('self',
|
parent = models.ForeignKey('self',
|
||||||
@ -44,95 +44,102 @@ class InvenTreeTree(models.Model):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
related_name='children')
|
related_name='children')
|
||||||
|
|
||||||
def getUniqueParents(self, unique=None):
|
def getUniqueParents(self, unique=None):
|
||||||
""" Return a flat set of all parent items that exist above this node.
|
""" 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 any parents are repeated (which would be very bad!), the process is halted
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if unique is None:
|
if unique is None:
|
||||||
unique = set()
|
unique = set()
|
||||||
else:
|
else:
|
||||||
unique.add(self.id)
|
unique.add(self.id)
|
||||||
|
|
||||||
if self.parent and self.parent.id not in unique:
|
if self.parent and self.parent.id not in unique:
|
||||||
self.parent.getUniqueParents(unique)
|
self.parent.getUniqueParents(unique)
|
||||||
|
|
||||||
return unique
|
return unique
|
||||||
|
|
||||||
def getUniqueChildren(self, unique=None):
|
def getUniqueChildren(self, unique=None):
|
||||||
""" Return a flat set of all child items that exist under this node.
|
""" Return a flat set of all child items that exist under this node.
|
||||||
If any child items are repeated, the repetitions are omitted.
|
If any child items are repeated, the repetitions are omitted.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if unique is None:
|
if unique is None:
|
||||||
unique = set()
|
unique = set()
|
||||||
|
|
||||||
if self.id in unique:
|
if self.id in unique:
|
||||||
return unique
|
return unique
|
||||||
|
|
||||||
unique.add(self.id)
|
unique.add(self.id)
|
||||||
|
|
||||||
# Some magic to get around the limitations of abstract models
|
# Some magic to get around the limitations of abstract models
|
||||||
contents = ContentType.objects.get_for_model(type(self))
|
contents = ContentType.objects.get_for_model(type(self))
|
||||||
children = contents.get_all_objects_for_this_type(parent=self.id)
|
children = contents.get_all_objects_for_this_type(parent=self.id)
|
||||||
|
|
||||||
return unique
|
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):
|
def getAcceptableParents(self):
|
||||||
""" Returns a list of acceptable parent items within this model
|
""" Returns a list of acceptable parent items within this model
|
||||||
Acceptable parents are ones which are not underneath this item.
|
Acceptable parents are ones which are not underneath this item.
|
||||||
Setting the parent of an item to its own child results in recursion.
|
Setting the parent of an item to its own child results in recursion.
|
||||||
"""
|
"""
|
||||||
contents = ContentType.objects.get_for_model(type(self))
|
contents = ContentType.objects.get_for_model(type(self))
|
||||||
|
|
||||||
available = contents.get_all_objects_for_this_type()
|
available = contents.get_all_objects_for_this_type()
|
||||||
|
|
||||||
# List of child IDs
|
# List of child IDs
|
||||||
childs = getUniqueChildren()
|
childs = getUniqueChildren()
|
||||||
|
|
||||||
acceptable = [None]
|
acceptable = [None]
|
||||||
|
|
||||||
for a in available:
|
for a in available:
|
||||||
if a.id not in childs:
|
if a.id not in childs:
|
||||||
acceptable.append(a)
|
acceptable.append(a)
|
||||||
|
|
||||||
return acceptable
|
return acceptable
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parentpath(self):
|
def parentpath(self):
|
||||||
""" Return the parent path of this category
|
""" Return the parent path of this category
|
||||||
|
|
||||||
Todo:
|
Todo:
|
||||||
This function is recursive and expensive.
|
This function is recursive and expensive.
|
||||||
It should be reworked such that only a single db call is required
|
It should be reworked such that only a single db call is required
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.parent:
|
if self.parent:
|
||||||
return self.parent.parentpath + [self.parent]
|
return self.parent.parentpath + [self.parent]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
if self.parent:
|
if self.parent:
|
||||||
return "/".join([p.name for p in self.parentpath]) + "/" + self.name
|
return "/".join([p.name for p in self.parentpath]) + "/" + self.name
|
||||||
else:
|
else:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __setattr__(self, attrname, val):
|
def __setattr__(self, attrname, val):
|
||||||
""" Custom Attribute Setting function
|
""" Custom Attribute Setting function
|
||||||
|
|
||||||
Parent:
|
Parent:
|
||||||
Setting the parent of an item to its own child results in an infinite loop.
|
Setting the parent of an item to its own child results in an infinite loop.
|
||||||
The parent of an item cannot be set to:
|
The parent of an item cannot be set to:
|
||||||
a) Its own ID
|
a) Its own ID
|
||||||
b) The ID of any child items that exist underneath it
|
b) The ID of any child items that exist underneath it
|
||||||
|
|
||||||
Name:
|
Name:
|
||||||
Tree node names are limited to a reduced character set
|
Tree node names are limited to a reduced character set
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if attrname == 'parent_id':
|
if attrname == 'parent_id':
|
||||||
# If current ID is None, continue
|
# If current ID is None, continue
|
||||||
# - This object is just being created
|
# - This object is just being created
|
||||||
@ -153,14 +160,14 @@ class InvenTreeTree(models.Model):
|
|||||||
# Prohibit certain characters from tree node names
|
# Prohibit certain characters from tree node names
|
||||||
elif attrname == 'name':
|
elif attrname == 'name':
|
||||||
val = val.translate({ord(c): None for c in "!@#$%^&*'\"\\/[]{}<>,|+=~`"})
|
val = val.translate({ord(c): None for c in "!@#$%^&*'\"\\/[]{}<>,|+=~`"})
|
||||||
|
|
||||||
super(InvenTreeTree, self).__setattr__(attrname, val)
|
super(InvenTreeTree, self).__setattr__(attrname, val)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" String representation of a category is the full path to that category
|
""" String representation of a category is the full path to that category
|
||||||
|
|
||||||
Todo:
|
Todo:
|
||||||
This is recursive - Make it not so.
|
This is recursive - Make it not so.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self.path
|
return self.path
|
||||||
|
@ -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.conf.urls import url, include
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
admin.site.site_header = "InvenTree Admin"
|
admin.site.site_header = "InvenTree Admin"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
url(r'^api/', include('InvenTree.api_urls')),
|
||||||
url(r'^stock/', include('stock.urls')),
|
url(r'^stock/', include('stock.urls')),
|
||||||
url(r'^part/', include('part.urls')),
|
url(r'^part/', include('part.urls')),
|
||||||
url(r'^supplier/', include('supplier.urls')),
|
url(r'^supplier/', include('supplier.urls')),
|
||||||
|
17
InvenTree/part/api_urls.py
Normal file
17
InvenTree/part/api_urls.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
# Display part detail
|
||||||
|
url(r'^(?P<pk>[0-9]+)/$', views.PartDetail.as_view()),
|
||||||
|
|
||||||
|
# Display a single part category
|
||||||
|
url(r'^category/(?P<pk>[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())
|
||||||
|
]
|
@ -15,6 +15,12 @@ class PartCategory(InvenTreeTree):
|
|||||||
verbose_name = "Part Category"
|
verbose_name = "Part Category"
|
||||||
verbose_name_plural = "Part Categories"
|
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):
|
class Part(models.Model):
|
||||||
""" Represents a """
|
""" Represents a """
|
||||||
|
@ -4,14 +4,21 @@ from .models import Part, PartCategory, PartParameter
|
|||||||
|
|
||||||
|
|
||||||
class ParameterSerializer(serializers.ModelSerializer):
|
class ParameterSerializer(serializers.ModelSerializer):
|
||||||
|
""" Serializer for a PartParameter
|
||||||
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PartParameter
|
model = PartParameter
|
||||||
fields = ('name',
|
fields = ('pk',
|
||||||
|
'name',
|
||||||
'value',
|
'value',
|
||||||
'units')
|
'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)
|
params = ParameterSerializer(source='parameters', many=True)
|
||||||
|
|
||||||
@ -26,11 +33,44 @@ class PartSerializer(serializers.ModelSerializer):
|
|||||||
'params')
|
'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:
|
class Meta:
|
||||||
model = PartCategory
|
model = PartCategory
|
||||||
fields = ('pk',
|
fields = ('pk',
|
||||||
'name',
|
'name',
|
||||||
'description',
|
'description',
|
||||||
'parent',
|
'parent',
|
||||||
'path')
|
'path',
|
||||||
|
'children',
|
||||||
|
'parts')
|
||||||
|
@ -3,15 +3,9 @@ from django.conf.urls import url
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Display part detail
|
# part landing page
|
||||||
url(r'^(?P<pk>[0-9]+)/$', views.PartDetail.as_view()),
|
url(r'^$', views.part_index),
|
||||||
|
|
||||||
# Display a single part category
|
# part category landing page
|
||||||
url(r'^category/(?P<pk>[0-9]+)/$', views.PartCategoryDetail.as_view()),
|
url(r'^category/$', views.category_index)
|
||||||
|
|
||||||
# Display a list of top-level categories
|
|
||||||
url(r'^category/$', views.PartCategoryList.as_view()),
|
|
||||||
|
|
||||||
# Display list of parts
|
|
||||||
url(r'^$', views.PartList.as_view())
|
|
||||||
]
|
]
|
||||||
|
@ -4,32 +4,38 @@ from django.http import HttpResponse, Http404
|
|||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
|
||||||
from .models import PartCategory, Part
|
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")
|
return HttpResponse("Hello world. This is the parts page")
|
||||||
|
|
||||||
|
def category_index(request):
|
||||||
|
return HttpResponse("This is the category page")
|
||||||
|
|
||||||
class PartDetail(generics.RetrieveAPIView):
|
class PartDetail(generics.RetrieveAPIView):
|
||||||
|
|
||||||
queryset = Part.objects.all()
|
queryset = Part.objects.all()
|
||||||
serializer_class = PartSerializer
|
serializer_class = PartDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
class PartList(generics.ListAPIView):
|
class PartList(generics.ListAPIView):
|
||||||
|
|
||||||
queryset = Part.objects.all()
|
queryset = Part.objects.all()
|
||||||
serializer_class = PartSerializer
|
serializer_class = PartBriefSerializer
|
||||||
|
|
||||||
|
|
||||||
class PartCategoryDetail(generics.RetrieveAPIView):
|
class PartCategoryDetail(generics.RetrieveAPIView):
|
||||||
|
""" Return information on a single PartCategory
|
||||||
|
"""
|
||||||
queryset = PartCategory.objects.all()
|
queryset = PartCategory.objects.all()
|
||||||
serializer_class = PartCategorySerializer
|
serializer_class = PartCategoryDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
class PartCategoryList(generics.ListAPIView):
|
class PartCategoryList(generics.ListAPIView):
|
||||||
|
""" Return a list of all top-level part categories.
|
||||||
queryset = PartCategory.objects.all()
|
Categories are considered "top-level" if they do not have a parent
|
||||||
serializer_class = PartCategorySerializer
|
"""
|
||||||
|
queryset = PartCategory.objects.filter(parent=None)
|
||||||
|
serializer_class = PartCategoryBriefSerializer
|
||||||
|
6
InvenTree/project/api_urls.py
Normal file
6
InvenTree/project/api_urls.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user