Merge pull request #34 from SchrodingersGat/master

Lots of API improvements
This commit is contained in:
Oliver 2017-04-13 00:32:49 +10:00 committed by GitHub
commit b7ab2fa59e
9 changed files with 115 additions and 59 deletions

View File

@ -10,4 +10,5 @@ urlpatterns = [
url(r'^track/', include('track.urls')), url(r'^track/', include('track.urls')),
url(r'^project/', include('project.urls')), url(r'^project/', include('project.urls')),
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework'))
] ]

View File

@ -44,10 +44,10 @@ class PartCategoryBriefSerializer(serializers.ModelSerializer):
class PartCategoryDetailSerializer(serializers.ModelSerializer): class PartCategoryDetailSerializer(serializers.ModelSerializer):
# List of parts in this category # List of parts in this category
parts = PartSerializer(many=True) parts = PartSerializer(many=True, read_only=True)
# List of child categories under this one # List of child categories under this one
children = PartCategoryBriefSerializer(many=True) children = PartCategoryBriefSerializer(many=True, read_only=True)
class Meta: class Meta:
model = PartCategory model = PartCategory

View File

@ -1,19 +1,45 @@
from django.conf.urls import url from django.conf.urls import url, include
from . import views from . import views
urlpatterns = [ """ URL patterns associated with part categories:
# Single part detail /category -> List all top-level categories
url(r'^(?P<pk>[0-9]+)/$', views.PartDetail.as_view()), /category/<pk> -> Detail view of given category
/category/new -> Create a new category
# Part parameters list """
url(r'^(?P<pk>[0-9]+)/parameters/$', views.PartParameters.as_view()), categorypatterns = [
# Part category detail # Part category detail
url(r'^category/(?P<pk>[0-9]+)/$', views.PartCategoryDetail.as_view()), url(r'^category/(?P<pk>[0-9]+)/$', views.PartCategoryDetail.as_view()),
# List of top-level categories # List of top-level categories
url(r'^category/$', views.PartCategoryList.as_view()), url(r'^$', views.PartCategoryList.as_view())
]
""" URL patterns associated with a particular part:
/part/<pk> -> Detail view of a given part
/part/<pk>/parameters -> List parameters associated with a part
"""
partdetailpatterns = [
# Single part detail
url(r'^$', views.PartDetail.as_view()),
# View part parameters
url(r'parameters/$', views.PartParameters.as_view())
]
""" Top-level URL patterns for the Part app:
/part/ -> List all parts
/part/new -> Create a new part
/part/<pk> -> (refer to partdetailpatterns)
/part/category -> (refer to categorypatterns)
"""
urlpatterns = [
# Individual part
url(r'^(?P<pk>[0-9]+)/', include(partdetailpatterns)),
# Part categories
url(r'^category/', views.PartCategoryList.as_view()),
# List of all parts # List of all parts
url(r'^$', views.PartList.as_view()) url(r'^$', views.PartList.as_view())

View File

@ -1,4 +1,4 @@
from rest_framework import generics from rest_framework import generics, permissions
from .models import PartCategory, Part, PartParameter from .models import PartCategory, Part, PartParameter
from .serializers import PartSerializer from .serializers import PartSerializer
@ -6,37 +6,44 @@ from .serializers import PartCategoryDetailSerializer
from .serializers import PartParameterSerializer from .serializers import PartParameterSerializer
class PartDetail(generics.RetrieveAPIView): class PartDetail(generics.RetrieveUpdateDestroyAPIView):
""" Return information on a single part
"""
queryset = Part.objects.all() queryset = Part.objects.all()
serializer_class = PartSerializer serializer_class = PartSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class PartParameters(generics.ListAPIView): class PartParameters(generics.ListCreateAPIView):
""" Return all parameters associated with a particular part
"""
def get_queryset(self): def get_queryset(self):
part_id = self.kwargs['pk'] part_id = self.kwargs['pk']
return PartParameter.objects.filter(part=part_id) return PartParameter.objects.filter(part=part_id)
serializer_class = PartParameterSerializer serializer_class = PartParameterSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class PartList(generics.ListAPIView): class PartList(generics.ListCreateAPIView):
queryset = Part.objects.all() queryset = Part.objects.all()
serializer_class = PartSerializer serializer_class = PartSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class PartCategoryDetail(generics.RetrieveAPIView): class PartCategoryDetail(generics.RetrieveUpdateAPIView):
""" Return information on a single PartCategory """ Return information on a single PartCategory
""" """
queryset = PartCategory.objects.all() queryset = PartCategory.objects.all()
serializer_class = PartCategoryDetailSerializer serializer_class = PartCategoryDetailSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class PartCategoryList(generics.ListAPIView): class PartCategoryList(generics.ListCreateAPIView):
""" Return a list of all top-level part categories. """ Return a list of all top-level part categories.
Categories are considered "top-level" if they do not have a parent Categories are considered "top-level" if they do not have a parent
""" """
queryset = PartCategory.objects.filter(parent=None) queryset = PartCategory.objects.filter(parent=None)
serializer_class = PartCategoryDetailSerializer serializer_class = PartCategoryDetailSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

View File

@ -1,5 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils.translation import ugettext as _ # from django.utils.translation import ugettext as _
from django.db import models from django.db import models
@ -47,6 +47,13 @@ class ProjectPart(models.Model):
The overage is the number of extra parts that are generally used for a single run. The overage is the number of extra parts that are generally used for a single run.
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
"""
# TODO - Add overage model fields
# Overage types # Overage types
OVERAGE_PERCENT = 0 OVERAGE_PERCENT = 0
OVERAGE_ABSOLUTE = 1 OVERAGE_ABSOLUTE = 1
@ -56,13 +63,11 @@ class ProjectPart(models.Model):
OVERAGE_ABSOLUTE: _("Absolute") OVERAGE_ABSOLUTE: _("Absolute")
} }
part = models.ForeignKey(Part, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
overage = models.FloatField(default=0) overage = models.FloatField(default=0)
overage_type = models.PositiveIntegerField( overage_type = models.PositiveIntegerField(
default=OVERAGE_ABSOLUTE, default=OVERAGE_ABSOLUTE,
choices=OVARAGE_CODES.items()) choices=OVARAGE_CODES.items())
"""
# Set if the part is generated by the project, # Set if the part is generated by the project,
# rather than being consumed by the project # rather than being consumed by the project

View File

@ -11,12 +11,10 @@ class ProjectPartSerializer(serializers.ModelSerializer):
'part', 'part',
'project', 'project',
'quantity', 'quantity',
'overage',
'overage_type',
'output') 'output')
class ProjectBriefSerializer(serializers.ModelSerializer): class ProjectSerializer(serializers.ModelSerializer):
""" Serializer for displaying brief overview of a project """ Serializer for displaying brief overview of a project
""" """
@ -28,18 +26,6 @@ class ProjectBriefSerializer(serializers.ModelSerializer):
'category') 'category')
class ProjectDetailSerializer(serializers.ModelSerializer):
""" Serializer for detailed project information
"""
class Meta:
model = Project
fields = ('pk',
'name',
'description',
'category')
class ProjectCategoryBriefSerializer(serializers.ModelSerializer): class ProjectCategoryBriefSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -49,9 +35,9 @@ class ProjectCategoryBriefSerializer(serializers.ModelSerializer):
class ProjectCategoryDetailSerializer(serializers.ModelSerializer): class ProjectCategoryDetailSerializer(serializers.ModelSerializer):
projects = ProjectBriefSerializer(many=True) projects = ProjectSerializer(many=True, read_only=True)
children = ProjectCategoryBriefSerializer(many=True) children = ProjectCategoryBriefSerializer(many=True, read_only=True)
class Meta: class Meta:
model = ProjectCategory model = ProjectCategory

View File

@ -1,20 +1,39 @@
from django.conf.urls import url from django.conf.urls import url, include
from . import views from . import views
urlpatterns = [ """ 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 # Single project detail
url(r'^(?P<pk>[0-9]+)/$', views.ProjectDetail.as_view()), url(r'^$', views.ProjectDetail.as_view()),
# Parts associated with a project # Parts associated with a project
url(r'^(?P<pk>[0-9]+)/parts$', views.ProjectPartsList.as_view()), url(r'^parts/$', views.ProjectPartsList.as_view()),
]
projectcategorypatterns = [
# List of top-level project categories
url(r'^$', views.ProjectCategoryList.as_view()),
# Detail of a single project category
url(r'^(?P<pk>[0-9]+)/$', views.ProjectCategoryDetail.as_view()),
# Create a new category
url(r'^new/$', views.NewProjectCategory.as_view())
]
urlpatterns = [
# Individual project URL
url(r'^(?P<pk>[0-9]+)/', include(projectdetailpatterns)),
# List of all projects # List of all projects
url(r'^$', views.ProjectList.as_view()), url(r'^$', views.ProjectList.as_view()),
# List of top-level project categories # Project categories
url(r'^category/$', views.ProjectCategoryList.as_view()), url(r'^category/', include(projectcategorypatterns)),
# Detail of a single project category
url(r'^category/(?P<pk>[0-9]+)/$', views.ProjectCategoryDetail.as_view())
] ]

View File

@ -1,38 +1,50 @@
from rest_framework import generics from rest_framework import generics, permissions
from .models import ProjectCategory, Project, ProjectPart from .models import ProjectCategory, Project, ProjectPart
from .serializers import ProjectBriefSerializer, ProjectDetailSerializer from .serializers import ProjectSerializer
from .serializers import ProjectCategoryDetailSerializer from .serializers import ProjectCategoryDetailSerializer
from .serializers import ProjectPartSerializer from .serializers import ProjectPartSerializer
class ProjectDetail(generics.RetrieveAPIView): class ProjectDetail(generics.RetrieveUpdateAPIView):
queryset = Project.objects.all() queryset = Project.objects.all()
serializer_class = ProjectDetailSerializer serializer_class = ProjectSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ProjectList(generics.ListAPIView): class ProjectList(generics.ListCreateAPIView):
queryset = Project.objects.all() queryset = Project.objects.all()
serializer_class = ProjectBriefSerializer serializer_class = ProjectSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ProjectCategoryDetail(generics.RetrieveAPIView): class NewProjectCategory(generics.CreateAPIView):
""" Create a new Project Category
"""
serializer_class = ProjectCategoryDetailSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ProjectCategoryDetail(generics.RetrieveUpdateAPIView):
queryset = ProjectCategory.objects.all() queryset = ProjectCategory.objects.all()
serializer_class = ProjectCategoryDetailSerializer serializer_class = ProjectCategoryDetailSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ProjectCategoryList(generics.ListAPIView): class ProjectCategoryList(generics.ListCreateAPIView):
queryset = ProjectCategory.objects.filter(parent=None) queryset = ProjectCategory.objects.filter(parent=None)
serializer_class = ProjectCategoryDetailSerializer serializer_class = ProjectCategoryDetailSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class ProjectPartsList(generics.ListAPIView): class ProjectPartsList(generics.ListCreateAPIView):
serializer_class = ProjectPartSerializer serializer_class = ProjectPartSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self): def get_queryset(self):
project_id = self.kwargs['pk'] project_id = self.kwargs['pk']

View File

@ -36,10 +36,10 @@ class LocationDetailSerializer(serializers.ModelSerializer):
""" """
# List of all stock items in this location # List of all stock items in this location
items = StockItemSerializer(many=True) items = StockItemSerializer(many=True, read_only=True)
# List of all child locations under this one # List of all child locations under this one
children = LocationBriefSerializer(many=True) children = LocationBriefSerializer(many=True, read_only=True)
class Meta: class Meta:
model = StockLocation model = StockLocation