mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
First pass at HTML form rendering
This commit is contained in:
parent
c630a12e26
commit
c171fa21ac
|
@ -13,17 +13,18 @@ import django
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.http.multipartparser import parse_header
|
from django.http.multipartparser import parse_header
|
||||||
from django.template import RequestContext, loader, Template
|
from django.template import Context, RequestContext, loader, Template
|
||||||
from django.test.client import encode_multipart
|
from django.test.client import encode_multipart
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.xmlutils import SimplerXMLGenerator
|
from django.utils.xmlutils import SimplerXMLGenerator
|
||||||
|
from rest_framework import exceptions, serializers, status, VERSION
|
||||||
from rest_framework.compat import StringIO, smart_text, yaml
|
from rest_framework.compat import StringIO, smart_text, yaml
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.request import is_form_media_type, override_method
|
from rest_framework.request import is_form_media_type, override_method
|
||||||
from rest_framework.utils import encoders
|
from rest_framework.utils import encoders
|
||||||
from rest_framework.utils.breadcrumbs import get_breadcrumbs
|
from rest_framework.utils.breadcrumbs import get_breadcrumbs
|
||||||
from rest_framework import exceptions, status, VERSION
|
from rest_framework.utils.field_mapping import ClassLookupDict
|
||||||
|
|
||||||
|
|
||||||
def zero_as_none(value):
|
def zero_as_none(value):
|
||||||
|
@ -341,6 +342,42 @@ class HTMLFormRenderer(BaseRenderer):
|
||||||
template = 'rest_framework/form.html'
|
template = 'rest_framework/form.html'
|
||||||
charset = 'utf-8'
|
charset = 'utf-8'
|
||||||
|
|
||||||
|
field_templates = ClassLookupDict({
|
||||||
|
serializers.Field: {
|
||||||
|
'default': 'input.html'
|
||||||
|
},
|
||||||
|
serializers.BooleanField: {
|
||||||
|
'default': 'checkbox.html'
|
||||||
|
},
|
||||||
|
serializers.CharField: {
|
||||||
|
'default': 'input.html',
|
||||||
|
'textarea': 'textarea.html'
|
||||||
|
},
|
||||||
|
serializers.ChoiceField: {
|
||||||
|
'default': 'select.html',
|
||||||
|
'radio': 'select_radio.html'
|
||||||
|
},
|
||||||
|
serializers.MultipleChoiceField: {
|
||||||
|
'default': 'select_multiple.html',
|
||||||
|
'checkbox': 'select_checkbox.html'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
def render_field(self, field, value, errors, layout=None):
|
||||||
|
layout = layout or 'vertical'
|
||||||
|
style_type = field.style.get('type', 'default')
|
||||||
|
if style_type == 'textarea' and layout == 'inline':
|
||||||
|
style_type = 'default'
|
||||||
|
base = self.field_templates[field][style_type]
|
||||||
|
template_name = 'rest_framework/fields/' + layout + '/' + base
|
||||||
|
template = loader.get_template(template_name)
|
||||||
|
context = Context({
|
||||||
|
'field': field,
|
||||||
|
'value': value,
|
||||||
|
'errors': errors
|
||||||
|
})
|
||||||
|
return template.render(context)
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
Render serializer data and return an HTML form, as a string.
|
Render serializer data and return an HTML form, as a string.
|
||||||
|
@ -349,7 +386,11 @@ class HTMLFormRenderer(BaseRenderer):
|
||||||
request = renderer_context['request']
|
request = renderer_context['request']
|
||||||
|
|
||||||
template = loader.get_template(self.template)
|
template = loader.get_template(self.template)
|
||||||
context = RequestContext(request, {'form': data})
|
context = RequestContext(request, {
|
||||||
|
'form': data,
|
||||||
|
'layout': getattr(getattr(data, 'Meta', None), 'layout', 'vertical'),
|
||||||
|
'renderer': self
|
||||||
|
})
|
||||||
return template.render(context)
|
return template.render(context)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,8 @@ class Serializer(BaseSerializer):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
errors = self.errors if hasattr(self, '_errors') else {}
|
errors = self.errors if hasattr(self, '_errors') else {}
|
||||||
for field in self.fields.values():
|
for field in self.fields.values():
|
||||||
|
if field.read_only:
|
||||||
|
continue
|
||||||
value = self.data.get(field.field_name) if self.data else None
|
value = self.data.get(field.field_name) if self.data else None
|
||||||
error = errors.get(field.field_name)
|
error = errors.get(field.field_name)
|
||||||
yield FieldResult(field, value, error)
|
yield FieldResult(field, value, error)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
name="{{ field.field_name }}" {% if field.style.placeholder %}placeholder="{{ field.style.placeholder }}"{% endif %} {% if field.style.rows %}rows="{{ field.style.rows }}"{% endif %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
|
||||||
|
{% if field.label %}{{ field.label }}{% endif %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<fieldset>
|
||||||
|
{% if field.label %}
|
||||||
|
<div class="form-group" style="border-bottom: 1px solid #e5e5e5">
|
||||||
|
<legend class="control-label col-sm-2 {% if field.style.hide_label %}sr-only{% endif %}" style="border-bottom: 0">{{ field.label }}</legend>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% for field_item in value.field_items.values() %}
|
||||||
|
{{ renderer.render_field(field_item, layout=layout) }}
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
|
||||||
|
{% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
{% if field.label %}<label class="col-sm-2 control-label {% if field.style.hide_label %}sr-only{% endif %}">{{ field.label }}</label>{% endif %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
{% if field.style.inline %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select multiple class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
{% if field.style.inline %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/horizontal/label.html" %}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
|
||||||
|
{% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
|
||||||
|
{% if field.label %}{{ field.label }}{% endif %}
|
||||||
|
</label>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% for field_item in value.field_items.values() %}
|
||||||
|
{{ renderer.render_field(field_item, layout=layout) }}
|
||||||
|
{% endfor %}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
<input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
{% if field.label %}<label class="sr-only">{{ field.label }}</label>{% endif %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
<select class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ rest_framework/field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
<select multiple class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/inline/label.html" %}
|
||||||
|
<textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
|
||||||
|
{% if field.label %}{{ field.label }}{% endif %}
|
||||||
|
</label>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<fieldset>
|
||||||
|
{% if field.label %}<legend {% if field.style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</legend>{% endif %}
|
||||||
|
{% for field_item in value.field_items.values() %}
|
||||||
|
{{ renderer.render_field(field_item, layout=layout) }}
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
<input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
|
||||||
|
{% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
{% if field.label %}<label {% if field.style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label>{% endif %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
<select class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
{% if field.style.inline %}
|
||||||
|
<div>
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
<select multiple class="form-control" name="{{ field.field_name }}">
|
||||||
|
{% for key, text in field.choices.items() %}
|
||||||
|
<option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
{% if field.style.inline %}
|
||||||
|
<div>
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key|string==value|string %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% for key, text in field.choices.items %}
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key|string==value|string %}checked{% endif %}>
|
||||||
|
{{ text }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="form-group">
|
||||||
|
{% include "rest_framework/fields/vertical/label.html" %}
|
||||||
|
<textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
|
||||||
|
{% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
|
||||||
|
</div>
|
|
@ -1,15 +1,31 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<h1>User update</h1>
|
||||||
|
<div class="well">
|
||||||
|
|
||||||
{% load rest_framework %}
|
{% load rest_framework %}
|
||||||
{% csrf_token %}
|
<form {% if layout == "inline" %}class="form-inline"{% elif layout == "horizontal" %}class="form-horizontal"{% endif %} role="form" action="" method="POST">
|
||||||
{{ form.non_field_errors }}
|
{% csrf_token %}
|
||||||
{% for field in form.fields.values %}
|
{% for field, value, errors in form %}
|
||||||
{% if not field.read_only %}
|
{% render_field field value errors layout=layout renderer=renderer %}
|
||||||
<div class="control-group {% if field.errors %}error{% endif %}">
|
{% endfor %}
|
||||||
{{ field.label_tag|add_class:"control-label" }}
|
<!-- form.non_field_errors -->
|
||||||
<div class="controls">
|
{% if layout == "horizontal" %}
|
||||||
{{ field.widget_html }}
|
<div class="form-group">
|
||||||
{% if field.help_text %}<span class="help-block">{{ field.help_text }}</span>{% endif %}
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
{% for error in field.errors %}<span class="help-block">{{ error }}</span>{% endfor %}
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% else %}
|
||||||
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div></body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -31,6 +31,14 @@ class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
|
||||||
|
|
||||||
# And the template tags themselves...
|
# And the template tags themselves...
|
||||||
|
|
||||||
|
# @register.simple_tag
|
||||||
|
# def render_field(field, value, errors, renderer):
|
||||||
|
# return renderer.render_field(field, value, errors)
|
||||||
|
@register.simple_tag
|
||||||
|
def render_field(field, value, errors, layout=None, renderer=None):
|
||||||
|
return renderer.render_field(field, value, errors, layout)
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def optional_login(request):
|
def optional_login(request):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -79,6 +79,9 @@ def get_field_kwargs(field_name, model_field):
|
||||||
kwargs['choices'] = model_field.flatchoices
|
kwargs['choices'] = model_field.flatchoices
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
if isinstance(model_field, models.TextField):
|
||||||
|
kwargs['style'] = {'type': 'textarea'}
|
||||||
|
|
||||||
if model_field.null and not isinstance(model_field, models.NullBooleanField):
|
if model_field.null and not isinstance(model_field, models.NullBooleanField):
|
||||||
kwargs['allow_null'] = True
|
kwargs['allow_null'] = True
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class TestRegularFieldMappings(TestCase):
|
||||||
positive_small_integer_field = IntegerField()
|
positive_small_integer_field = IntegerField()
|
||||||
slug_field = SlugField(max_length=100)
|
slug_field = SlugField(max_length=100)
|
||||||
small_integer_field = IntegerField()
|
small_integer_field = IntegerField()
|
||||||
text_field = CharField()
|
text_field = CharField(style={'type': 'textarea'})
|
||||||
time_field = TimeField()
|
time_field = TimeField()
|
||||||
url_field = URLField(max_length=100)
|
url_field = URLField(max_length=100)
|
||||||
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>)
|
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user