diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index ac06f79d3e..412b001cdd 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -2,6 +2,18 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +from django.db import models + +from collections import OrderedDict + +from django.core.exceptions import PermissionDenied +from django.http import Http404 +from django.utils.encoding import force_str + +from rest_framework import exceptions, serializers, fields +from rest_framework.request import clone_request +from rest_framework.utils.field_mapping import ClassLookupDict + from rest_framework.metadata import SimpleMetadata import users.models @@ -17,6 +29,9 @@ class InvenTreeMetadata(SimpleMetadata): Thus when a client send an OPTIONS request to an API endpoint, it will only receive a list of actions which it is allowed to perform! + Additionally, we include some extra information about database models, + so we can perform lookup for ForeignKey related fields. + """ def determine_metadata(self, request, view): @@ -73,3 +88,58 @@ class InvenTreeMetadata(SimpleMetadata): pass return metadata + + def get_field_info(self, field): + """ + Given an instance of a serializer field, return a dictionary + of metadata about it. + """ + + field_info = OrderedDict() + + field_info['type'] = self.label_lookup[field] + field_info['required'] = getattr(field, 'required', False) + + if field_info['type'] == 'field': + + # If the field is a 'ForeignKey' field + if isinstance(field, serializers.ModelSerializer): # or isinstance(field, serializers.PrimaryKeyRelatedField): + model = field.Meta.model + + # Construct the 'table name' from the model + app_label = model._meta.app_label + tbl_label = model._meta.model_name + + table = f"{app_label}_{tbl_label}" + field_info['model'] = table + + print(field_info['type'], field, type(field)) + + attrs = [ + 'read_only', 'label', 'help_text', + 'min_length', 'max_length', + 'min_value', 'max_value' + ] + + for attr in attrs: + value = getattr(field, attr, None) + if value is not None and value != '': + field_info[attr] = force_str(value, strings_only=True) + + if getattr(field, 'child', None): + field_info['child'] = self.get_field_info(field.child) + elif getattr(field, 'fields', None): + field_info['children'] = self.get_serializer_info(field) + + if (not field_info.get('read_only') and + not isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField)) and + hasattr(field, 'choices')): + field_info['choices'] = [ + { + 'value': choice_value, + 'display_name': force_str(choice_name, strings_only=True) + } + for choice_value, choice_name in field.choices.items() + ] + + return field_info \ No newline at end of file diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 47e3337a20..ffc7dc8de8 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -1,3 +1,6 @@ +{% load i18n %} +{% load inventree_extras %} + /** * This file contains code for rendering (and managing) HTML forms * which are served via the django-drf API. @@ -229,16 +232,24 @@ function constructFormBody(url, fields, options={}) { html += f; } + // TODO: Dynamically create the modals, + // so that we can have an infinite number of stacks! var modal = '#modal-form'; modalEnable(modal, true); + var title = options.title || '{% trans "Form Title" %}'; + + modalSetTitle(modal, title); + $(modal).find('.modal-form-content').html(html); $(modal).modal('show'); attachToggle(modal); attachSelect(modal); + + modalShowSubmitButton(modal, true); }