Fix schema generation with OneToOneFields (#81)
* Fix: OneToOneRel, used by OneToOneField doesn't have help_text nor primary_key attributes, thus breaking OpenAPISchemaGenerator; use hasattr() as safe-guard. * Fix: use getattr() with a default value instead of hasattr() + acessing the value * Add: 'people' app that breaks drf_yasg without previous commits * Update tests/references.yaml + run isort and flake8 * Fix: set on_delete for Person.identity as Django-2+ requires itopenapi3
parent
a7fbba4967
commit
309a6eb8cd
|
|
@ -409,9 +409,9 @@ class OpenAPISchemaGenerator(object):
|
|||
if getattr(view_cls, 'lookup_field', None) == variable and attrs['type'] == openapi.TYPE_STRING:
|
||||
attrs['pattern'] = getattr(view_cls, 'lookup_value_regex', attrs.get('pattern', None))
|
||||
|
||||
if model_field and model_field.help_text:
|
||||
if model_field and getattr(model_field, 'help_text', False):
|
||||
description = force_text(model_field.help_text)
|
||||
elif model_field and model_field.primary_key:
|
||||
elif model_field and getattr(model_field, 'primary_key', False):
|
||||
description = get_pk_description(model, model_field)
|
||||
else:
|
||||
description = None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PeopleConfig(AppConfig):
|
||||
name = 'people'
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.10 on 2018-03-18 16:22
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Identity',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('firstName', models.CharField(max_length=30, null=True)),
|
||||
('lastName', models.CharField(max_length=30, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Person',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('Identity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='person', to='people.Identity')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.10 on 2018-03-18 17:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('people', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='person',
|
||||
name='Identity',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='person', to='people.Identity'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Identity(models.Model):
|
||||
firstName = models.CharField(max_length=30, null=True)
|
||||
lastName = models.CharField(max_length=30, null=True)
|
||||
|
||||
|
||||
class Person(models.Model):
|
||||
Identity = models.OneToOneField(Identity, related_name='person',
|
||||
on_delete=models.PROTECT)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from .models import Identity, Person
|
||||
|
||||
|
||||
class IdentitySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Identity
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class PersonSerializer(serializers.ModelSerializer):
|
||||
identity = IdentitySerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Person
|
||||
fields = '__all__'
|
||||
|
||||
def create(self, validated_data):
|
||||
identity = Identity(**validated_data['identity'])
|
||||
identity.save()
|
||||
validated_data['identity'] = identity
|
||||
return super().create(validated_data)
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import IdentityViewSet, PersonViewSet
|
||||
|
||||
person_list = PersonViewSet.as_view({
|
||||
'get': 'list',
|
||||
'post': 'create'
|
||||
})
|
||||
person_detail = PersonViewSet.as_view({
|
||||
'get': 'retrieve',
|
||||
'patch': 'partial_update',
|
||||
'delete': 'destroy'
|
||||
})
|
||||
|
||||
identity_detail = IdentityViewSet.as_view({
|
||||
'get': 'retrieve',
|
||||
'patch': 'partial_update',
|
||||
})
|
||||
|
||||
urlpatterns = (
|
||||
url(r'^$', person_list, name='people-list'),
|
||||
url(r'^(?P<pk>[0-9]+)$', person_detail, name='person-detail'),
|
||||
|
||||
url(r'^(?P<person>[0-9]+)/identity$', identity_detail,
|
||||
name='person-identity'),
|
||||
)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from .models import Identity, Person
|
||||
from .serializers import IdentitySerializer, PersonSerializer
|
||||
|
||||
|
||||
class PersonViewSet(viewsets.ModelViewSet):
|
||||
model = Person
|
||||
queryset = Person.objects
|
||||
serializer_class = PersonSerializer
|
||||
|
||||
|
||||
class IdentityViewSet(viewsets.ModelViewSet):
|
||||
model = Identity
|
||||
queryset = Identity.objects
|
||||
serializer_class = IdentitySerializer
|
||||
|
|
@ -27,6 +27,7 @@ INSTALLED_APPS = [
|
|||
'users',
|
||||
'articles',
|
||||
'todo',
|
||||
'people'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
|||
|
|
@ -63,5 +63,6 @@ urlpatterns = [
|
|||
url(r'^articles/', include('articles.urls')),
|
||||
url(r'^users/', include('users.urls')),
|
||||
url(r'^todo/', include('todo.urls')),
|
||||
url(r'^people/', include('people.urls')),
|
||||
url(r'^plain/', plain_view),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -234,6 +234,113 @@ paths:
|
|||
type: string
|
||||
format: slug
|
||||
pattern: '[a-z0-9]+(?:-[a-z0-9]+)'
|
||||
/people/:
|
||||
get:
|
||||
operationId: people_list
|
||||
description: ''
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Person'
|
||||
tags:
|
||||
- people
|
||||
post:
|
||||
operationId: people_create
|
||||
description: ''
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Person'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/Person'
|
||||
tags:
|
||||
- people
|
||||
parameters: []
|
||||
/people/{id}:
|
||||
get:
|
||||
operationId: people_read
|
||||
description: ''
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/Person'
|
||||
tags:
|
||||
- people
|
||||
patch:
|
||||
operationId: people_partial_update
|
||||
description: ''
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Person'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/Person'
|
||||
tags:
|
||||
- people
|
||||
delete:
|
||||
operationId: people_delete
|
||||
description: ''
|
||||
parameters: []
|
||||
responses:
|
||||
'204':
|
||||
description: ''
|
||||
tags:
|
||||
- people
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: A unique integer value identifying this person.
|
||||
required: true
|
||||
type: integer
|
||||
/people/{person}/identity:
|
||||
get:
|
||||
operationId: people_identity_read
|
||||
description: ''
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/Identity'
|
||||
tags:
|
||||
- people
|
||||
patch:
|
||||
operationId: people_identity_partial_update
|
||||
description: ''
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Identity'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/Identity'
|
||||
tags:
|
||||
- people
|
||||
parameters:
|
||||
- name: person
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
/plain/:
|
||||
get:
|
||||
operationId: plain_list
|
||||
|
|
@ -609,6 +716,37 @@ definitions:
|
|||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
Identity:
|
||||
title: Identity
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
firstName:
|
||||
title: FirstName
|
||||
type: string
|
||||
maxLength: 30
|
||||
lastName:
|
||||
title: LastName
|
||||
type: string
|
||||
maxLength: 30
|
||||
readOnly: true
|
||||
Person:
|
||||
required:
|
||||
- Identity
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
identity:
|
||||
$ref: '#/definitions/Identity'
|
||||
Identity:
|
||||
title: Identity
|
||||
type: integer
|
||||
Project:
|
||||
required:
|
||||
- projectName
|
||||
|
|
|
|||
Loading…
Reference in New Issue