diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index ccdca1389a..f5f5802278 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -35,6 +35,7 @@ INSTALLED_APPS = [
'django_filters',
'rest_framework',
'simple_history',
+ 'crispy_forms',
# Core django modules
'django.contrib.admin',
@@ -144,3 +145,4 @@ MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+CRISPY_TEMPLATE_PACK = 'bootstrap'
diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py
new file mode 100644
index 0000000000..deaac66d30
--- /dev/null
+++ b/InvenTree/part/forms.py
@@ -0,0 +1,31 @@
+from django import forms
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import Submit
+
+from .models import Part
+
+
+class EditPartForm(forms.ModelForm):
+
+ def __init__(self, *args, **kwargs):
+ super(EditPartForm, self).__init__(*args, **kwargs)
+ self.helper = FormHelper()
+
+ self.helper.form_id = 'id-edit-part-form'
+ self.helper.form_class = 'blueForms'
+ self.helper.form_method = 'post'
+ #self.helper.form_action = 'submit'
+
+ self.helper.add_input(Submit('submit', 'Submit'))
+
+ class Meta:
+ model = Part
+ fields = [
+ 'category',
+ 'name',
+ 'description',
+ 'IPN',
+ 'URL',
+ 'minimum_stock',
+ 'trackable',
+ ]
\ No newline at end of file
diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py
index b1c9ac214e..5b057f74c5 100644
--- a/InvenTree/part/models.py
+++ b/InvenTree/part/models.py
@@ -73,6 +73,9 @@ class Part(models.Model):
and can be combined to form other parts
"""
+ def get_absolute_url(self):
+ return '/part/{id}/'.format(id=self.id)
+
# Short name of the part
name = models.CharField(max_length=100)
diff --git a/InvenTree/part/templates/part/delete.html b/InvenTree/part/templates/part/delete.html
new file mode 100644
index 0000000000..94c5b29144
--- /dev/null
+++ b/InvenTree/part/templates/part/delete.html
@@ -0,0 +1,2 @@
+{% extends 'part/part_base.html' %}
+
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index bbed508675..dc2629ae47 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -6,5 +6,10 @@
Part details go here...
+
+
+
+
+
{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/part/templates/part/edit.html b/InvenTree/part/templates/part/edit.html
new file mode 100644
index 0000000000..d8eb692e3b
--- /dev/null
+++ b/InvenTree/part/templates/part/edit.html
@@ -0,0 +1,11 @@
+{% extends "part/part_base.html" %}
+
+{% block details %}
+
+Edit part information:
+
+{% load crispy_forms_tags %}
+
+{% crispy form %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py
index 97ee069a67..a17459b7a6 100644
--- a/InvenTree/part/urls.py
+++ b/InvenTree/part/urls.py
@@ -39,12 +39,17 @@ bom_api_urls = [
]
part_detail_urls = [
- url(r'^track/?', views.track, name='part-track'),
- url(r'^bom/?', views.bom, name='part-bom'),
- url(r'^stock/?', views.stock, name='part-stock'),
- url(r'^used/?', views.used, name='part-used-in'),
- url(r'^suppliers/?', views.suppliers, name='part-suppliers'),
- url('', views.detail, name='part-detail'),
+ url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'),
+ url(r'^delete/?', views.delete, name='part-delete'),
+ url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'),
+ url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'),
+ url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'),
+ url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'),
+ url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'),
+
+ # Any other URLs go to the part detail page
+ #url(r'^.*$', views.detail, name='part-detail'),
+ url(r'^.*$', views.PartDetail.as_view(), name='part-detail'),
]
# URL list for part web interface
@@ -52,7 +57,7 @@ part_urls = [
# Individual
url(r'^(?P\d+)/', include(part_detail_urls)),
- url('list', views.index, name='part-index'),
+ url('list', views.PartIndex.as_view(), name='part-index'),
# ex: /part/5/
url(r'^.*$', RedirectView.as_view(url='list', permanent=False), name='part-index'),
diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py
index cccd91be98..43c26d1cc5 100644
--- a/InvenTree/part/views.py
+++ b/InvenTree/part/views.py
@@ -1,76 +1,50 @@
-
-# Template stuff (WIP)
-from django.http import HttpResponse
-from django.template import loader
-
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
-def index(request):
- template = loader.get_template('part/index.html')
+from django.views.generic import DetailView, ListView
+from django.views.generic.edit import UpdateView
- parts = Part.objects.all()
+from .forms import EditPartForm
- cat = None
+class PartIndex(ListView):
+ model = Part
+ template_name = 'part/index.html'
+ context_object_name = 'parts'
- if 'category' in request.GET:
- cat_id = request.GET['category']
+ def get_queryset(self):
+ self.category = self.request.GET.get('category', None)
- cat = get_object_or_404(PartCategory, pk=cat_id)
+ return Part.objects.filter(category=self.category)
- parts = parts.filter(category = cat_id)
- children = PartCategory.objects.filter(parent = cat_id)
+ def get_context_data(self, **kwargs):
- else:
- parts = parts.filter(category__isnull=True)
- children = PartCategory.objects.filter(parent__isnull=True)
+ context = super(PartIndex, self).get_context_data(**kwargs)
- context = {
- 'parts' : parts.order_by('category__name'),
- 'category' : cat,
- 'children' : children,
- }
+ children = PartCategory.objects.filter(parent=self.category)
- return HttpResponse(template.render(context, request))
+ context['children'] = children
+
+ if self.category:
+ context['category'] = get_object_or_404(PartCategory, pk=self.category)
+
+ return context
-def detail(request, pk):
- #template = loader.get_template('detail.html')
-
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/detail.html', {'part' : part})
-
- #return HttpResponse("You're looking at part %s." % pk)
+class PartDetail(DetailView):
+ context_object_name = 'part'
+ queryset = Part.objects.all()
+ template_name = 'part/detail.html'
-def bom(request, pk):
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/bom.html', {'part': part})
-
-def used(request, pk):
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/used_in.html', {'part': part})
-
-def stock(request, pk):
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/stock.html', {'part': part})
-
-def track(request, pk):
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/track.html', {'part': part})
+class PartEdit(UpdateView):
+ model = Part
+ form_class = EditPartForm
+ template_name = 'part/edit.html'
-def suppliers(request, pk):
- part = get_object_or_404(Part, pk=pk)
-
- return render(request, 'part/supplier.html', {'part' : part})
+def delete(request, pk):
+ return HttpResponseRedirect('/part/{pk}/'.format(pk=pk))
diff --git a/requirements/base.txt b/requirements/base.txt
index d9c16d5ecc..f471d3db94 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -4,3 +4,4 @@ django_filter==1.0.2
django-simple-history==1.8.2
coreapi==2.3.0
pygments==2.2.0
+django-crispy-forms==1.7.2
\ No newline at end of file