mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Begin to add views for part models
- List BOM items - Show category listing as linked items - Fix some pathing issues with InvenTreeTree class
This commit is contained in:
parent
77fe0dc542
commit
bd46f66d6b
@ -38,7 +38,7 @@ class InvenTreeTree(models.Model):
|
||||
abstract = True
|
||||
unique_together = ('name', 'parent')
|
||||
|
||||
name = models.CharField(max_length=100)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
description = models.CharField(max_length=250, blank=True)
|
||||
parent = models.ForeignKey('self',
|
||||
on_delete=models.CASCADE,
|
||||
@ -126,10 +126,11 @@ class InvenTreeTree(models.Model):
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
if self.parent:
|
||||
return "/".join([p.name for p in self.parentpath]) + "/" + self.name
|
||||
else:
|
||||
return self.name
|
||||
return self.parentpath + [self]
|
||||
|
||||
@property
|
||||
def pathstring(self):
|
||||
return '/'.join([item.name for item in self.path])
|
||||
|
||||
def __setattr__(self, attrname, val):
|
||||
""" Custom Attribute Setting function
|
||||
@ -174,7 +175,7 @@ class InvenTreeTree(models.Model):
|
||||
This is recursive - Make it not so.
|
||||
"""
|
||||
|
||||
return self.path
|
||||
return self.pathstring
|
||||
|
||||
|
||||
def FilterChildren(queryset, parent):
|
||||
|
@ -3,7 +3,8 @@ from django.contrib import admin
|
||||
|
||||
from rest_framework.documentation import include_docs_urls
|
||||
|
||||
from part.urls import part_urls, part_cat_urls
|
||||
from part.urls import part_api_urls, part_cat_api_urls
|
||||
from part.urls import part_urls
|
||||
from bom.urls import bom_urls
|
||||
from stock.urls import stock_urls, stock_loc_urls
|
||||
from supplier.urls import cust_urls, manu_urls, supplier_part_urls, price_break_urls, supplier_urls
|
||||
@ -13,6 +14,8 @@ from supplier.urls import cust_urls, manu_urls, supplier_part_urls, price_break_
|
||||
|
||||
from users.urls import user_urls
|
||||
|
||||
from . import views
|
||||
|
||||
admin.site.site_header = "InvenTree Admin"
|
||||
|
||||
apipatterns = [
|
||||
@ -22,8 +25,8 @@ apipatterns = [
|
||||
url(r'^stock-location/', include(stock_loc_urls)),
|
||||
|
||||
# Part URLs
|
||||
url(r'^part/', include(part_urls)),
|
||||
url(r'^part-category/', include(part_cat_urls)),
|
||||
url(r'^part/', include(part_api_urls)),
|
||||
url(r'^part-category/', include(part_cat_api_urls)),
|
||||
#url(r'^part-param/', include(part_param_urls)),
|
||||
#url(r'^part-param-template/', include(part_param_template_urls)),
|
||||
|
||||
@ -52,9 +55,12 @@ apipatterns = [
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# API URL
|
||||
url(r'^api/', include(apipatterns)),
|
||||
|
||||
url(r'^part/', include(part_urls)),
|
||||
|
||||
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
||||
|
||||
url(r'^admin/', admin.site.urls),
|
||||
|
@ -3,7 +3,7 @@ from rest_framework import serializers
|
||||
from .models import BomItem
|
||||
|
||||
|
||||
class BomItemSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class BomItemSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = BomItem
|
||||
|
@ -4,12 +4,12 @@ from .models import PartCategory, Part
|
||||
|
||||
class PartAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = ('name', 'IPN', 'stock', 'category')
|
||||
list_display = ('name', 'IPN', 'description', 'stock', 'category')
|
||||
|
||||
|
||||
class PartCategoryAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = ('name', 'path', 'description')
|
||||
list_display = ('name', 'pathstring', 'description')
|
||||
|
||||
"""
|
||||
class ParameterTemplateAdmin(admin.ModelAdmin):
|
||||
|
@ -36,7 +36,7 @@ class Part(models.Model):
|
||||
IPN = models.CharField(max_length=100, blank=True)
|
||||
|
||||
# Part category - all parts must be assigned to a category
|
||||
category = models.ForeignKey(PartCategory, on_delete=models.CASCADE)
|
||||
category = models.ForeignKey(PartCategory, on_delete=models.CASCADE, related_name='parts')
|
||||
|
||||
# Minimum "allowed" stock level
|
||||
minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)])
|
||||
@ -75,11 +75,21 @@ class Part(models.Model):
|
||||
result = stocks.aggregate(total=Sum('quantity'))
|
||||
return result['total']
|
||||
|
||||
@property
|
||||
def bomItemCount(self):
|
||||
return self.bom_items.all().count()
|
||||
|
||||
|
||||
@property
|
||||
def usedInCount(self):
|
||||
return self.used_in.all().count()
|
||||
|
||||
"""
|
||||
@property
|
||||
def projects(self):
|
||||
""" Return a list of unique projects that this part is associated with.
|
||||
" Return a list of unique projects that this part is associated with.
|
||||
A part may be used in zero or more projects.
|
||||
"""
|
||||
"
|
||||
|
||||
project_ids = set()
|
||||
project_parts = self.projectpart_set.all()
|
||||
@ -92,6 +102,6 @@ class Part(models.Model):
|
||||
projects.append(pp.project)
|
||||
|
||||
return projects
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
@ -17,7 +17,8 @@ class PartParameterSerializer(serializers.HyperlinkedModelSerializer):
|
||||
'units')
|
||||
"""
|
||||
|
||||
class PartSerializer(serializers.HyperlinkedModelSerializer):
|
||||
#class PartSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class PartSerializer(serializers.ModelSerializer):
|
||||
""" Serializer for complete detail information of a part.
|
||||
Used when displaying all details of a single component.
|
||||
"""
|
||||
@ -31,7 +32,8 @@ class PartSerializer(serializers.HyperlinkedModelSerializer):
|
||||
'category',
|
||||
'stock',
|
||||
'units',
|
||||
'trackable')
|
||||
'trackable',
|
||||
)
|
||||
|
||||
|
||||
class PartCategorySerializer(serializers.HyperlinkedModelSerializer):
|
||||
@ -42,7 +44,7 @@ class PartCategorySerializer(serializers.HyperlinkedModelSerializer):
|
||||
'name',
|
||||
'description',
|
||||
'parent',
|
||||
'path')
|
||||
'pathstring')
|
||||
|
||||
"""
|
||||
class PartTemplateSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
7
InvenTree/part/templates/cat_link.html
Normal file
7
InvenTree/part/templates/cat_link.html
Normal file
@ -0,0 +1,7 @@
|
||||
<div id="category-path" background="#99F">
|
||||
<a href="/part/list/">All</a> >
|
||||
{% for path_item in category.parentpath %}
|
||||
<a href="/part/list/?category={{ path_item.id }}">{{ path_item.name }}</a> >
|
||||
{% endfor %}
|
||||
<a href="/part/list/?category={{ category.id }}">{{ category.name }}</a>
|
||||
</div>
|
30
InvenTree/part/templates/detail.html
Normal file
30
InvenTree/part/templates/detail.html
Normal file
@ -0,0 +1,30 @@
|
||||
<h1>Part details for {{ part.name }}</h1>
|
||||
|
||||
{% include "cat_link.html" with category=part.category %}
|
||||
|
||||
<br>
|
||||
Part name: {{ part.name }}
|
||||
<br>
|
||||
Description: {{ part.description }}
|
||||
<br>
|
||||
IPN: {% if part.IPN %}{{ part.IPN }}{% else %}N/A{% endif %}
|
||||
<br>
|
||||
Stock: {{ part.stock }}
|
||||
|
||||
<br><br>
|
||||
BOM items: {{ part.bomItemCount }}<br>
|
||||
Used in {{ part.usedInCount }} other parts.<br>
|
||||
|
||||
<h2>BOM</h2>
|
||||
<ul>
|
||||
{% for bom in part.bom_items.all %}
|
||||
<li><a href="{% url 'detail' bom.sub_part.id %}">{{ bom.sub_part.name }}</a> ({{ bom.quantity }})</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h2>Used to make</h2>
|
||||
<ul>
|
||||
{% for p in part.used_in.all %}
|
||||
<li><a href="{% url 'detail' p.part.id %}">{{ p.part.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
27
InvenTree/part/templates/index.html
Normal file
27
InvenTree/part/templates/index.html
Normal file
@ -0,0 +1,27 @@
|
||||
<h1>Parts page!</h1>
|
||||
|
||||
{% if category %}
|
||||
{% include "cat_link.html" with category=category %}
|
||||
<h3>Child categories</h3>
|
||||
<ul>
|
||||
{% for child in category.children.all %}
|
||||
<li><a href="/part/list?category={{ child.id }}">{{ child.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
No category!
|
||||
{% endif %}
|
||||
|
||||
<b>Here is a list of all the parts:</b>
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
{% for part in parts %}
|
||||
<tr>
|
||||
<td><a href="{% url 'detail' part.id %}">{{ part.name }}</a></td>
|
||||
<td>{{ part.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
@ -1,8 +1,12 @@
|
||||
from django.conf.urls import url
|
||||
from django.views.generic.base import RedirectView
|
||||
|
||||
from . import views
|
||||
|
||||
part_cat_urls = [
|
||||
app_nam='part'
|
||||
|
||||
# URL list for part category API
|
||||
part_cat_api_urls = [
|
||||
|
||||
# Part category detail
|
||||
url(r'^(?P<pk>[0-9]+)/?$', views.PartCategoryDetail.as_view(), name='partcategory-detail'),
|
||||
@ -12,7 +16,9 @@ part_cat_urls = [
|
||||
url(r'^$', views.PartCategoryList.as_view())
|
||||
]
|
||||
|
||||
part_urls = [
|
||||
|
||||
# URL list for part API
|
||||
part_api_urls = [
|
||||
|
||||
# Individual part
|
||||
url(r'^(?P<pk>[0-9]+)/?$', views.PartDetail.as_view(), name='part-detail'),
|
||||
@ -22,6 +28,17 @@ part_urls = [
|
||||
url(r'^$', views.PartList.as_view()),
|
||||
]
|
||||
|
||||
# URL list for part web interface
|
||||
part_urls = [
|
||||
# Individual
|
||||
url(r'^(?P<pk>\d+)/$', views.detail, name='detail'),
|
||||
# ex: /part/
|
||||
url('list', views.index, name='index'),
|
||||
# ex: /part/5/
|
||||
|
||||
url(r'^.*$', RedirectView.as_view(url='list', permanent=False), name='index'),
|
||||
]
|
||||
|
||||
"""
|
||||
part_param_urls = [
|
||||
# Detail of a single part parameter
|
||||
|
@ -1,15 +1,72 @@
|
||||
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
|
||||
|
||||
# Template stuff (WIP)
|
||||
from django.http import HttpResponse
|
||||
from django.template import loader
|
||||
|
||||
from rest_framework import generics, permissions
|
||||
|
||||
from InvenTree.models import FilterChildren
|
||||
from .models import PartCategory, Part
|
||||
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.views import generic
|
||||
|
||||
from .serializers import PartSerializer
|
||||
from .serializers import PartCategorySerializer
|
||||
#from .serializers import PartParameterSerializer
|
||||
#from .serializers import PartTemplateSerializer
|
||||
|
||||
"""
|
||||
class IndexView(generic.ListView):
|
||||
template_name = 'index.html'
|
||||
context_object_name = 'parts'
|
||||
|
||||
def get_queryset(self):
|
||||
"Return the last five published questions."
|
||||
return Part.objects.all()
|
||||
|
||||
"""
|
||||
|
||||
def index(request):
|
||||
template = loader.get_template('index.html')
|
||||
|
||||
parts = Part.objects.all()
|
||||
|
||||
cat = None
|
||||
|
||||
if 'category' in request.GET:
|
||||
cat_id = request.GET['category']
|
||||
|
||||
cat = get_object_or_404(PartCategory, pk=cat_id)
|
||||
#cat = PartCategory.objects.get(pk=cat_id)
|
||||
parts = parts.filter(category = cat_id)
|
||||
|
||||
context = {
|
||||
'parts' : parts.order_by('category__name'),
|
||||
}
|
||||
|
||||
if cat:
|
||||
context['category'] = cat
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
|
||||
def detail(request, pk):
|
||||
#template = loader.get_template('detail.html')
|
||||
|
||||
part = get_object_or_404(Part, pk=pk)
|
||||
|
||||
return render(request, 'detail.html', {'part' : part})
|
||||
|
||||
#return HttpResponse("You're looking at part %s." % pk)
|
||||
|
||||
#def results(request, question_id):
|
||||
# response = "You're looking at the results of question %s."
|
||||
# return HttpResponse(response % question_id)
|
||||
|
||||
|
||||
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
|
@ -4,7 +4,7 @@ from .models import ProjectCategory, Project, ProjectPart, ProjectRun
|
||||
|
||||
|
||||
class ProjectCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'path', 'description')
|
||||
list_display = ('name', 'pathstring', 'description')
|
||||
|
||||
|
||||
class ProjectAdmin(admin.ModelAdmin):
|
||||
|
@ -32,7 +32,7 @@ class ProjectCategorySerializer(serializers.HyperlinkedModelSerializer):
|
||||
'name',
|
||||
'description',
|
||||
'parent',
|
||||
'path')
|
||||
'pathstring')
|
||||
|
||||
|
||||
class ProjectRunSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
@ -5,7 +5,7 @@ from .models import StockLocation, StockItem
|
||||
|
||||
|
||||
class LocationAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'path', 'description')
|
||||
list_display = ('name', 'pathstring', 'description')
|
||||
|
||||
|
||||
class StockItemAdmin(SimpleHistoryAdmin):
|
||||
|
@ -48,4 +48,4 @@ class LocationSerializer(serializers.HyperlinkedModelSerializer):
|
||||
'name',
|
||||
'description',
|
||||
'parent',
|
||||
'path')
|
||||
'pathstring')
|
||||
|
Loading…
Reference in New Issue
Block a user