Include API endpoints in OPTIONS metadata

This commit is contained in:
Oliver 2021-06-25 00:36:22 +10:00
parent 04374c71c2
commit 970a5d5eed
2 changed files with 55 additions and 14 deletions

View File

@ -1,24 +1,18 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models import logging
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 import serializers
from rest_framework.metadata import SimpleMetadata from rest_framework.metadata import SimpleMetadata
import users.models import users.models
logger = logging.getLogger('inventree')
class InvenTreeMetadata(SimpleMetadata): class InvenTreeMetadata(SimpleMetadata):
""" """
Custom metadata class for the DRF API. Custom metadata class for the DRF API.
@ -88,3 +82,31 @@ class InvenTreeMetadata(SimpleMetadata):
pass pass
return metadata return metadata
def get_field_info(self, field):
"""
Given an instance of a serializer field, return a dictionary
of metadata about it.
We take the regular DRF metadata and add our own unique flavor
"""
# Run super method first
field_info = super().get_field_info(field)
# Introspect writable related fields
if field_info['type'] == 'field' and not field_info['read_only']:
# If the field is a PrimaryKeyRelatedField, we can extract the model from the queryset
if isinstance(field, serializers.PrimaryKeyRelatedField):
model = field.queryset.model
else:
logger.debug("Could not extract model for:", field_info['label'], '->', field)
model = None
if model:
# Mark this field as "related", and point to the URL where we can get the data!
field_info['type'] = 'related field'
field_info['api_url'] = model.get_api_url()
return field_info

View File

@ -213,6 +213,8 @@ function constructFormBody(url, fields, options={}) {
} }
} }
// Render selected fields
for (var idx = 0; idx < field_names.length; idx++) { for (var idx = 0; idx < field_names.length; idx++) {
var name = field_names[idx]; var name = field_names[idx];
@ -242,6 +244,7 @@ function constructFormBody(url, fields, options={}) {
modalSetTitle(modal, title); modalSetTitle(modal, title);
// Insert generated form content
$(modal).find('.modal-form-content').html(html); $(modal).find('.modal-form-content').html(html);
$(modal).modal('show'); $(modal).modal('show');
@ -434,8 +437,8 @@ function constructInput(name, parameters, options={}) {
case 'choice': case 'choice':
func = constructChoiceInput; func = constructChoiceInput;
break; break;
case 'field': case 'related field':
// TODO: foreign key field! func = constructRelatedFieldInput;
break; break;
default: default:
// Unsupported field type! // Unsupported field type!
@ -597,6 +600,22 @@ function constructChoiceInput(name, parameters, options={}) {
} }
/*
* Construct a "related field" input.
* This will create a "select" input which will then, (after form is loaded),
* be converted into a select2 input.
* This will then be served custom data from the API (as required)...
*/
function constructRelatedFieldInput(name, parameters, options={}) {
var html = `<select id='id_${name}' class='select form-control' name='${name}'></select>`;
// Don't load any options - they will be filled via an AJAX request
return html;
}
/* /*
* Construct a 'help text' div based on the field parameters * Construct a 'help text' div based on the field parameters
* *