H
H
Hikmat Abdunabiev2016-03-24 10:10:27
Django
Hikmat Abdunabiev, 2016-03-24 10:10:27

How to convert Django model to Json Schema?

Hello!
Strongly do not kick, practical advice is needed.
One project is being developed in the Django + Django Rest Framework backend and in the AngularJS frontend. There was such situation that it is necessary to generate the form of the Django model in Angular. I would like to use Json Schema for this. People give advice on how to convert a Django model to Json Schema? Or which way to dig to convert a Django model to a form?
Thank you very much in advance!!!

Answer the question

In order to leave comments, you need to log in

5 answer(s)
S
sim3x, 2016-03-24
@sim3x

stackoverflow.com/questions/18561585/django-form-t...
the package is a bit old, but
https://github.com/WiserTogether/django-remote-forms
will do for an example, but it's better not to reinvent the wheel and www.django-rest- framework.org/topics/html-and-form...

C
chupasaurus, 2016-03-24
@chupasaurus

Serialization in Django and json peculiarities
Schema is not very suitable for defining dynamic structures.

A
Artem Klimenko, 2016-03-24
@aklim007

I don't know any solutions for automatically obtaining a schema from a model, and I'm not sure that they exist. If you decide to describe with your hands, then I recommend https://jsl.readthedocs.org/en/latest/

K
Khikmat Abdunabiev, 2016-03-25
@Khikmat

sim3x here is the bike needed here :) Since DRF and its TemplateHTMLRenderer render a ready-made form that I cannot use with AngularJS Material. So far I've made a form mixin in Django:

class MDSwitchRenderer(RadioFieldRenderer): 
  def render(self):
    return render_to_string('switch_widget.html', {'field': self})


class MDSwitch(RadioSelect): 
  renderer = MDSwitchRenderer


class MDSelect(Widget):
  allow_multiple_selected = False

  def __init__(self, attrs=None, choices=()):
    super(MDSelect, self).__init__(attrs)
    self.choices = list(choices)

  def render(self, name, value, attrs=None, choices=()):
    if value is None:
      value = ''
    final_attrs = self.build_attrs(attrs, name=name)
    output = [format_html('<md-select{}>', flatatt(final_attrs))]
    options = self.render_options(choices, [value])
    if options:
      output.append(options)
    output.append('</md-select>')
    return mark_safe('\n'.join(output))

  def render_option(self, selected_choices, option_value, option_label):
    if option_value is None:
      option_value = ''
    option_value = force_text(option_value)
    if option_value in selected_choices:
      selected_html = mark_safe(' selected')
      if not self.allow_multiple_selected:
        selected_choices.remove(option_value)
    else:
      selected_html = ''
    return format_html('<md-option data-ng-value="{}"{}>{}</md-option>', option_value, selected_html, force_text(option_label))

  def render_options(self, choices, selected_choices):
    selected_choices = set(force_text(v) for v in selected_choices)
    output = []
    for option_value, option_label in chain(self.choices, choices):
      if isinstance(option_label, (list, tuple)):
        output.append(format_html('<md-optgroup label="{}">', force_text(option_value)))
        for option in option_label:
          output.append(self.render_option(selected_choices, *option))
        output.append('</md-optgroup>')
      else:
        output.append(self.render_option(selected_choices, option_value, option_label))
    return '\n'.join(output)


class MDSelectMultiple(MDSelect):
  allow_multiple_selected = True

  def render(self, name, value, attrs=None, choices=()):
    if value is None:
      value = []
    final_attrs = self.build_attrs(attrs, name=name)
    output = [format_html('<md-select multiple="multiple"{}>', flatatt(final_attrs))]
    options = self.render_options(choices, value)
    if options:
      output.append(options)
    output.append('</md-select>')
    return mark_safe('\n'.join(output))

  def value_from_datadict(self, data, files, name):
    if isinstance(data, MultiValueDict):
      return data.getlist(name)
    return data.get(name)


class MDFormMixin(object):
  """
  Angular Material Design form mixin
  """

  def __init__(self, *args, **kwargs):
    super(MDFormMixin, self).__init__(args, kwargs)
    for field_name in self.fields:
      field = self.fields.get(field_name)
      if field:
        if type(field) in (ModelChoiceField, ):
          field.empty_label = None
          field.widget = MDSelect(choices=field.choices)
        elif type(field) in (ModelMultipleChoiceField, ):
          field.empty_label = None
          field.widget = MDSelectMultiple(choices=field.choices)

        if type(field.widget) in (TextInput, Textarea):
          field.widget.attrs.update({'md-maxlength': field.max_length, })
        #elif type(field.widget) in (TimeInput, ): # FIXME: Remove
        #	field.widget.input_type = 'time'
        #	field.widget.attrs.update({'step': 1, })
        elif type(field.widget) in (Select, ):
          field.widget = MDSelect(choices=field.choices)

        if field.required:
          field.widget.attrs.update({'required': 'required'})

        field.widget.attrs.update({'ng-model': 'vm.object.'+field_name})

template "switch_widget.html":
<md-radio-group ng-model="vm.object.{{ field.name }}">
{% for choice in field %}
  <md-radio-button ng-value="{{ choice.choice_value|lower }}">
    {{ choice.choice_label }}
  </md-radio-button>
{% endfor %}
</md-radio-group>

and template of the form itself "django_form.html":
{% if form.fieldsets %}
<md-content>
{% for fieldset in form.fieldsets %}
  <div{% if fieldset.class %} class="{{ fieldset.classes }}"{% endif %}{% if fieldset.description %} layout="{{ fieldset.description }}{% endif %}">
  {% for field in fieldset %}
    <md-input-container class="md-block" flex>
      <label>{{ field.label }}</label>
      {{ field }}
      {% if field.help_text %}
      <div class="hint">{{ field.help_text }}</div>
      {% endif %}
      <div ng-messages="vm.objectForm.{{ field.name }}.$error">
        <div ng-message="required" ng-show="vm.objectForm.{{ field.name }}.$error['required']">Обязательное поле для заполнения!</div>
        <div ng-message="md-maxlength" ng-show="vm.objectForm.{{ field.name }}.$error['md-maxlength']">Длина строки не должна превышать {{ field.field.max_length }} символов.</div>
      </div>
    </md-input-container>
  {% endfor %}
  </div>
{% endfor %}
</md-content>
{% endif %}

This link is working. But I had a problem when I started using Angular ControllerAs :( When I used $scope there were no such problems :)

D
Denis Nikanorov, 2016-03-25
@SlimHouse

There is a documentation generator for DRF: rest_framework_swagger. It has similar functionality. You can try to see, especially since you are using DRF.
In the DocumentationGenerator class, the get_models method https://github.com/marcgibbons/django-rest-swagger...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question