Replace "edit part category" form

This commit is contained in:
Oliver 2021-06-30 01:04:39 +10:00
parent c425f36a35
commit 621f47e46c
8 changed files with 62 additions and 13 deletions

View File

@ -10,11 +10,13 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.db.models.signals import pre_delete from django.db.models.signals import pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from mptt.exceptions import InvalidMove
from .validators import validate_tree_name from .validators import validate_tree_name
@ -91,6 +93,15 @@ class InvenTreeTree(MPTTModel):
parent: The item immediately above this one. An item with a null parent is a top-level item parent: The item immediately above this one. An item with a null parent is a top-level item
""" """
def save(self, *args, **kwargs):
try:
super().save(*args, **kwargs)
except InvalidMove:
raise ValidationError({
'parent': _("Invalid choice"),
})
class Meta: class Meta:
abstract = True abstract = True

View File

@ -110,6 +110,19 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
return initials return initials
def save(self, **kwargs):
"""
Catch any django ValidationError thrown at the moment save() is called,
and re-throw as a DRF ValidationError
"""
try:
super().save(**kwargs)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=serializers.as_serializer_error(exc))
return self.instance
def run_validation(self, data=empty): def run_validation(self, data=empty):
""" """
Perform serializer validation. Perform serializer validation.

View File

@ -127,7 +127,10 @@ class CategoryList(generics.ListCreateAPIView):
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single PartCategory object """ """
API endpoint for detail view of a single PartCategory object
"""
serializer_class = part_serializers.CategorySerializer serializer_class = part_serializers.CategorySerializer
queryset = PartCategory.objects.all() queryset = PartCategory.objects.all()

View File

@ -39,6 +39,7 @@ class CategorySerializer(InvenTreeModelSerializer):
'name', 'name',
'description', 'description',
'default_location', 'default_location',
'default_keywords',
'pathstring', 'pathstring',
'url', 'url',
'parent', 'parent',

View File

@ -268,13 +268,23 @@
{% if category %} {% if category %}
$("#cat-edit").click(function () { $("#cat-edit").click(function () {
launchModalForm(
"{% url 'category-edit' category.id %}", constructForm(
'{% url "api-part-category-detail" category.pk %}',
{ {
fields: {
name: {},
description: {},
parent: {},
default_location: {},
default_keywords: {
icon: 'fa-key',
}
},
title: '{% trans "Edit Part Category" %}',
reload: true reload: true
}, }
); );
return false;
}); });
{% if category.parent %} {% if category.parent %}

View File

@ -294,11 +294,6 @@ class CategoryTest(PartViewTestCase):
# Form should still return OK # Form should still return OK
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_edit(self):
""" Retrieve the part category editing form """
response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_set_category(self): def test_set_category(self):
""" Test that the "SetCategory" view works """ """ Test that the "SetCategory" view works """

View File

@ -104,7 +104,6 @@ category_urls = [
# Category detail views # Category detail views
url(r'(?P<pk>\d+)/', include([ url(r'(?P<pk>\d+)/', include([
url(r'^edit/', views.CategoryEdit.as_view(), name='category-edit'),
url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'), url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'),
url(r'^parameters/', include(category_parameter_urls)), url(r'^parameters/', include(category_parameter_urls)),

View File

@ -388,8 +388,13 @@ function constructFormBody(fields, options) {
function submitFormData(fields, options) { function submitFormData(fields, options) {
// Form data to be uploaded to the server // Form data to be uploaded to the server
// Only used if file / image upload is required
var form_data = new FormData(); var form_data = new FormData();
var data = {};
var has_files = false;
// Extract values for each field // Extract values for each field
options.field_names.forEach(function(name) { options.field_names.forEach(function(name) {
@ -411,20 +416,31 @@ function submitFormData(fields, options) {
var file = field_files[0]; var file = field_files[0];
form_data.append(name, file); form_data.append(name, file);
has_files = true;
} }
} else { } else {
// Normal field (not a file or image) // Normal field (not a file or image)
form_data.append(name, value); form_data.append(name, value);
data[name] = value;
} }
} else { } else {
console.log(`WARNING: Could not find field matching '${name}'`); console.log(`WARNING: Could not find field matching '${name}'`);
} }
}); });
var upload_func = inventreePut;
if (has_files) {
upload_func = inventreeFormDataUpload;
data = form_data;
}
// Submit data // Submit data
inventreeFormDataUpload( upload_func(
options.url, options.url,
form_data, data,
{ {
method: options.method, method: options.method,
success: function(response, status) { success: function(response, status) {
@ -708,6 +724,7 @@ function initializeRelatedField(name, field, options) {
ajax: { ajax: {
url: field.api_url, url: field.api_url,
dataType: 'json', dataType: 'json',
placeholder: '',
allowClear: !field.required, allowClear: !field.required,
dropdownParent: $(options.modal), dropdownParent: $(options.modal),
dropdownAutoWidth: false, dropdownAutoWidth: false,