use numeric primary keys, but still use unique names as lookups in the API
This commit is contained in:
parent
fcd0f8072b
commit
9658de72a2
14 changed files with 46 additions and 95 deletions
|
@ -4,13 +4,13 @@ from django.db.models.manager import BaseManager
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
class PkField(serializers.DictField):
|
class RelatedNameField(serializers.DictField):
|
||||||
"""
|
"""
|
||||||
give primary key
|
give primary key
|
||||||
"""
|
"""
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
if hasattr(obj, 'pk'):
|
if hasattr(obj, 'name'):
|
||||||
return obj.pk
|
return obj.name
|
||||||
elif isinstance(obj, Iterable):
|
elif isinstance(obj, Iterable):
|
||||||
return tuple(self.to_representation(elem) for elem in obj)
|
return tuple(self.to_representation(elem) for elem in obj)
|
||||||
elif isinstance(obj, BaseManager):
|
elif isinstance(obj, BaseManager):
|
||||||
|
@ -30,7 +30,7 @@ class RecursiveSerializerMixin(serializers.Serializer):
|
||||||
for name in getattr(self.Meta, 'sparse_exclude', ()):
|
for name in getattr(self.Meta, 'sparse_exclude', ()):
|
||||||
value = self.fields.get(name)
|
value = self.fields.get(name)
|
||||||
if value is not None and isinstance(value, serializers.Serializer):
|
if value is not None and isinstance(value, serializers.Serializer):
|
||||||
self.fields[name] = PkField()
|
self.fields[name] = RelatedNameField()
|
||||||
|
|
||||||
if request_sparse:
|
if request_sparse:
|
||||||
for name in tuple(self.fields):
|
for name in tuple(self.fields):
|
||||||
|
@ -42,5 +42,5 @@ class RecursiveSerializerMixin(serializers.Serializer):
|
||||||
|
|
||||||
def recursive_value(self, serializer, obj, *args, **kwargs):
|
def recursive_value(self, serializer, obj, *args, **kwargs):
|
||||||
if self.context.get('sparse'):
|
if self.context.get('sparse'):
|
||||||
return PkField().to_representation(obj)
|
return RelatedNameField().to_representation(obj)
|
||||||
return serializer(obj, context=self.sparse_context(), *args, **kwargs).data
|
return serializer(obj, context=self.sparse_context(), *args, **kwargs).data
|
||||||
|
|
|
@ -18,6 +18,8 @@ class HosterViewSet(ViewSet):
|
||||||
"""
|
"""
|
||||||
Retrieve and interact with package hosters
|
Retrieve and interact with package hosters
|
||||||
"""
|
"""
|
||||||
|
lookup_field = 'name'
|
||||||
|
|
||||||
def retrieve(self, request, pk=None):
|
def retrieve(self, request, pk=None):
|
||||||
if pk not in hosters:
|
if pk not in hosters:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
@ -92,6 +94,8 @@ class SubmitTaskViewSet(ViewSet):
|
||||||
"""
|
"""
|
||||||
Get hoster submit tasks
|
Get hoster submit tasks
|
||||||
"""
|
"""
|
||||||
|
lookup_field = 'id'
|
||||||
|
|
||||||
def retrieve(self, request, pk=None):
|
def retrieve(self, request, pk=None):
|
||||||
task = submit_edit_task.AsyncResult(task_id=pk)
|
task = submit_edit_task.AsyncResult(task_id=pk)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -15,10 +15,6 @@ class Hoster(ABC):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.base_url = base_url
|
self.base_url = base_url
|
||||||
|
|
||||||
@property
|
|
||||||
def pk(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_packages(self):
|
def get_packages(self):
|
||||||
"""
|
"""
|
||||||
Get a Queryset of all packages that can be handled by this hoster
|
Get a Queryset of all packages that can be handled by this hoster
|
||||||
|
|
|
@ -4,7 +4,7 @@ from rest_framework.reverse import reverse
|
||||||
|
|
||||||
class HosterSerializer(serializers.Serializer):
|
class HosterSerializer(serializers.Serializer):
|
||||||
name = serializers.CharField()
|
name = serializers.CharField()
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='api:hoster-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='api:hoster-detail', lookup_field='name')
|
||||||
state_url = serializers.SerializerMethodField()
|
state_url = serializers.SerializerMethodField()
|
||||||
auth_uri_url = serializers.SerializerMethodField()
|
auth_uri_url = serializers.SerializerMethodField()
|
||||||
submit_url = serializers.SerializerMethodField()
|
submit_url = serializers.SerializerMethodField()
|
||||||
|
@ -22,7 +22,7 @@ class HosterSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class TaskSerializer(serializers.Serializer):
|
class TaskSerializer(serializers.Serializer):
|
||||||
id = serializers.CharField()
|
id = serializers.CharField()
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='api:hoster-detail', lookup_field='id', lookup_url_kwarg='pk')
|
url = serializers.HyperlinkedIdentityField(view_name='api:hoster-detail', lookup_field='id')
|
||||||
started = serializers.SerializerMethodField()
|
started = serializers.SerializerMethodField()
|
||||||
done = serializers.SerializerMethodField()
|
done = serializers.SerializerMethodField()
|
||||||
success = serializers.SerializerMethodField()
|
success = serializers.SerializerMethodField()
|
||||||
|
|
|
@ -20,6 +20,7 @@ class LevelViewSet(ReadOnlyModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Level.objects.all()
|
queryset = Level.objects.all()
|
||||||
serializer_class = LevelSerializer
|
serializer_class = LevelSerializer
|
||||||
|
lookup_field = 'name'
|
||||||
lookup_value_regex = '[^/]+'
|
lookup_value_regex = '[^/]+'
|
||||||
filter_fields = ('altitude', 'package')
|
filter_fields = ('altitude', 'package')
|
||||||
ordering_fields = ('altitude', 'package')
|
ordering_fields = ('altitude', 'package')
|
||||||
|
@ -33,6 +34,7 @@ class PackageViewSet(ReadOnlyModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Package.objects.all()
|
queryset = Package.objects.all()
|
||||||
serializer_class = PackageSerializer
|
serializer_class = PackageSerializer
|
||||||
|
lookup_field = 'name'
|
||||||
lookup_value_regex = '[^/]+'
|
lookup_value_regex = '[^/]+'
|
||||||
filter_fields = ('name', 'depends')
|
filter_fields = ('name', 'depends')
|
||||||
ordering_fields = ('name',)
|
ordering_fields = ('name',)
|
||||||
|
@ -46,6 +48,7 @@ class SourceViewSet(ReadOnlyModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Source.objects.all()
|
queryset = Source.objects.all()
|
||||||
serializer_class = SourceSerializer
|
serializer_class = SourceSerializer
|
||||||
|
lookup_field = 'name'
|
||||||
lookup_value_regex = '[^/]+'
|
lookup_value_regex = '[^/]+'
|
||||||
filter_fields = ('package',)
|
filter_fields = ('package',)
|
||||||
ordering_fields = ('name', 'package')
|
ordering_fields = ('name', 'package')
|
||||||
|
@ -69,6 +72,8 @@ class FeatureTypeViewSet(ViewSet):
|
||||||
"""
|
"""
|
||||||
List and retrieve feature types
|
List and retrieve feature types
|
||||||
"""
|
"""
|
||||||
|
lookup_field = 'name'
|
||||||
|
|
||||||
def list(self, request):
|
def list(self, request):
|
||||||
serializer = FeatureTypeSerializer(FEATURE_TYPES.values(), many=True, context={'request': request})
|
serializer = FeatureTypeSerializer(FEATURE_TYPES.values(), many=True, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
@ -86,4 +91,5 @@ class FeatureViewSet(ReadOnlyModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Feature.objects.all()
|
queryset = Feature.objects.all()
|
||||||
serializer_class = FeatureSerializer
|
serializer_class = FeatureSerializer
|
||||||
|
lookup_field = 'name'
|
||||||
lookup_value_regex = '[^/]+'
|
lookup_value_regex = '[^/]+'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Generated by Django 1.10.1 on 2016-09-23 15:15
|
# Generated by Django 1.10.1 on 2016-10-11 14:00
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import c3nav.mapdata.fields
|
import c3nav.mapdata.fields
|
||||||
|
@ -17,32 +17,27 @@ class Migration(migrations.Migration):
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Feature',
|
name='Feature',
|
||||||
fields=[
|
|
||||||
('name', models.SlugField(help_text='e.g. noc', primary_key=True, serialize=False, verbose_name='feature identifier')),
|
|
||||||
('feature_type', models.CharField(choices=[('building', 'Building'), ('room', 'Room'), ('outside', 'Outside Area'), ('obstacle', 'Obstacle')], max_length=50)),
|
|
||||||
('geometry', c3nav.mapdata.fields.GeometryField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='FeatureTitle',
|
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('language', models.CharField(max_length=50)),
|
('name', models.SlugField(unique=True, verbose_name='feature identifier')),
|
||||||
('title', models.CharField(max_length=50)),
|
('feature_type', models.CharField(choices=[('building', 'Building'), ('room', 'Room'), ('outside', 'Outside Area'), ('obstacle', 'Obstacle')], max_length=50)),
|
||||||
('feature', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='featuretitles', to='mapdata.Feature', verbose_name='map package')),
|
('titles', c3nav.mapdata.fields.JSONField()),
|
||||||
|
('geometry', c3nav.mapdata.fields.GeometryField()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Level',
|
name='Level',
|
||||||
fields=[
|
fields=[
|
||||||
('name', models.SlugField(help_text='Usually just an integer (e.g. -1, 0, 1, 2)', primary_key=True, serialize=False, verbose_name='level name')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.SlugField(help_text='Usually just an integer (e.g. -1, 0, 1, 2)', unique=True, verbose_name='level name')),
|
||||||
('altitude', models.DecimalField(decimal_places=2, max_digits=6, null=True, verbose_name='level altitude')),
|
('altitude', models.DecimalField(decimal_places=2, max_digits=6, null=True, verbose_name='level altitude')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Package',
|
name='Package',
|
||||||
fields=[
|
fields=[
|
||||||
('name', models.SlugField(help_text='e.g. de.c3nav.33c3.base', primary_key=True, serialize=False, verbose_name='package identifier')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.SlugField(help_text='e.g. de.c3nav.33c3.base', unique=True, verbose_name='package identifier')),
|
||||||
('home_repo', models.URLField(null=True, verbose_name='URL to the home git repository')),
|
('home_repo', models.URLField(null=True, verbose_name='URL to the home git repository')),
|
||||||
('commit_id', models.CharField(max_length=40, null=True, verbose_name='current commit id')),
|
('commit_id', models.CharField(max_length=40, null=True, verbose_name='current commit id')),
|
||||||
('bottom', models.DecimalField(decimal_places=2, max_digits=6, null=True, verbose_name='bottom coordinate')),
|
('bottom', models.DecimalField(decimal_places=2, max_digits=6, null=True, verbose_name='bottom coordinate')),
|
||||||
|
@ -56,7 +51,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Source',
|
name='Source',
|
||||||
fields=[
|
fields=[
|
||||||
('name', models.SlugField(primary_key=True, serialize=False, verbose_name='source name')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.SlugField(unique=True, verbose_name='source name')),
|
||||||
('bottom', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='bottom coordinate')),
|
('bottom', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='bottom coordinate')),
|
||||||
('left', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='left coordinate')),
|
('left', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='left coordinate')),
|
||||||
('top', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='top coordinate')),
|
('top', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='top coordinate')),
|
||||||
|
@ -79,8 +75,4 @@ class Migration(migrations.Migration):
|
||||||
name='package',
|
name='package',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='features', to='mapdata.Package', verbose_name='map package'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='features', to='mapdata.Package', verbose_name='map package'),
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name='featuretitle',
|
|
||||||
unique_together=set([('feature', 'language')]),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.1 on 2016-09-26 08:58
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import c3nav.mapdata.fields
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapdata', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name='featuretitle',
|
|
||||||
unique_together=set([]),
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='featuretitle',
|
|
||||||
name='feature',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='feature',
|
|
||||||
name='titles',
|
|
||||||
field=c3nav.mapdata.fields.JSONField(default={}),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='FeatureTitle',
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,20 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.1 on 2016-09-29 07:36
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapdata', '0002_auto_20160926_0858'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='feature',
|
|
||||||
name='name',
|
|
||||||
field=models.SlugField(primary_key=True, serialize=False, verbose_name='feature identifier'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -16,10 +16,6 @@ class FeatureType(namedtuple('FeatureType', ('name', 'title', 'title_plural', 'g
|
||||||
super().__init__()
|
super().__init__()
|
||||||
FEATURE_TYPES[self.name] = self
|
FEATURE_TYPES[self.name] = self
|
||||||
|
|
||||||
@property
|
|
||||||
def pk(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title_en(self):
|
def title_en(self):
|
||||||
language = get_language()
|
language = get_language()
|
||||||
|
@ -47,7 +43,7 @@ class Feature(models.Model):
|
||||||
"""
|
"""
|
||||||
TYPES = tuple((name, t.title) for name, t in FEATURE_TYPES.items())
|
TYPES = tuple((name, t.title) for name, t in FEATURE_TYPES.items())
|
||||||
|
|
||||||
name = models.SlugField(_('feature identifier'), primary_key=True, max_length=50)
|
name = models.SlugField(_('feature identifier'), unique=True, max_length=50)
|
||||||
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='features',
|
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='features',
|
||||||
verbose_name=_('map package'))
|
verbose_name=_('map package'))
|
||||||
feature_type = models.CharField(max_length=50, choices=TYPES)
|
feature_type = models.CharField(max_length=50, choices=TYPES)
|
||||||
|
|
|
@ -6,7 +6,7 @@ class Level(models.Model):
|
||||||
"""
|
"""
|
||||||
A map level (-1, 0, 1, 2…)
|
A map level (-1, 0, 1, 2…)
|
||||||
"""
|
"""
|
||||||
name = models.SlugField(_('level name'), primary_key=True, max_length=50,
|
name = models.SlugField(_('level name'), unique=True, max_length=50,
|
||||||
help_text=_('Usually just an integer (e.g. -1, 0, 1, 2)'))
|
help_text=_('Usually just an integer (e.g. -1, 0, 1, 2)'))
|
||||||
altitude = models.DecimalField(_('level altitude'), null=True, max_digits=6, decimal_places=2)
|
altitude = models.DecimalField(_('level altitude'), null=True, max_digits=6, decimal_places=2)
|
||||||
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='levels',
|
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='levels',
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Package(models.Model):
|
||||||
"""
|
"""
|
||||||
A c3nav map package
|
A c3nav map package
|
||||||
"""
|
"""
|
||||||
name = models.SlugField(_('package identifier'), primary_key=True, max_length=50,
|
name = models.SlugField(_('package identifier'), unique=True, max_length=50,
|
||||||
help_text=_('e.g. de.c3nav.33c3.base'))
|
help_text=_('e.g. de.c3nav.33c3.base'))
|
||||||
depends = models.ManyToManyField('Package')
|
depends = models.ManyToManyField('Package')
|
||||||
home_repo = models.URLField(_('URL to the home git repository'), null=True)
|
home_repo = models.URLField(_('URL to the home git repository'), null=True)
|
||||||
|
|
|
@ -6,7 +6,7 @@ class Source(models.Model):
|
||||||
"""
|
"""
|
||||||
A map source, images of levels that can be useful as backgrounds for the map editor
|
A map source, images of levels that can be useful as backgrounds for the map editor
|
||||||
"""
|
"""
|
||||||
name = models.SlugField(_('source name'), primary_key=True, max_length=50)
|
name = models.SlugField(_('source name'), unique=True, max_length=50)
|
||||||
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='sources',
|
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='sources',
|
||||||
verbose_name=_('map package'))
|
verbose_name=_('map package'))
|
||||||
|
|
||||||
|
|
|
@ -146,9 +146,13 @@ class ReaderItem:
|
||||||
}
|
}
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
depends = []
|
||||||
if self.model != Package:
|
if self.model != Package:
|
||||||
package_name = self.reader.package_names_by_dir[self.package_dir]
|
package_name = self.reader.package_names_by_dir[self.package_dir]
|
||||||
self.data['package'] = self.reader.saved_items[Package][package_name].obj
|
self.data['package'] = self.reader.saved_items[Package][package_name].obj
|
||||||
|
else:
|
||||||
|
depends = [self.reader.saved_items[Package][name].obj.pk for name in self.data['depends']]
|
||||||
|
self.data.pop('depends')
|
||||||
|
|
||||||
# Change name references to the referenced object
|
# Change name references to the referenced object
|
||||||
for name, model in self.relations.items():
|
for name, model in self.relations.items():
|
||||||
|
@ -161,3 +165,8 @@ class ReaderItem:
|
||||||
|
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
self.reader.saved_items[self.model][obj.name] = self
|
self.reader.saved_items[self.model][obj.name] = self
|
||||||
|
|
||||||
|
if depends:
|
||||||
|
self.obj.depends.clear()
|
||||||
|
for dependency in depends:
|
||||||
|
self.obj.depends.add(dependency)
|
||||||
|
|
|
@ -40,7 +40,7 @@ class PackageSerializer(RecursiveSerializerMixin, serializers.ModelSerializer):
|
||||||
fields = ('name', 'url', 'home_repo', 'commit_id', 'depends', 'bounds', 'public', 'hoster')
|
fields = ('name', 'url', 'home_repo', 'commit_id', 'depends', 'bounds', 'public', 'hoster')
|
||||||
sparse_exclude = ('depends', 'hoster')
|
sparse_exclude = ('depends', 'hoster')
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'url': {'view_name': 'api:package-detail'}
|
'url': {'view_name': 'api:package-detail', 'lookup_field': 'name'}
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_depends(self, obj):
|
def get_depends(self, obj):
|
||||||
|
@ -59,7 +59,7 @@ class LevelSerializer(RecursiveSerializerMixin, serializers.ModelSerializer):
|
||||||
fields = ('name', 'url', 'altitude', 'package')
|
fields = ('name', 'url', 'altitude', 'package')
|
||||||
sparse_exclude = ('package',)
|
sparse_exclude = ('package',)
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'url': {'view_name': 'api:level-detail'}
|
'url': {'view_name': 'api:level-detail', 'lookup_field': 'name'}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class SourceSerializer(RecursiveSerializerMixin, serializers.ModelSerializer):
|
||||||
fields = ('name', 'url', 'image_url', 'package', 'bounds')
|
fields = ('name', 'url', 'image_url', 'package', 'bounds')
|
||||||
sparse_exclude = ('package', )
|
sparse_exclude = ('package', )
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'url': {'view_name': 'api:source-detail'}
|
'url': {'view_name': 'api:source-detail', 'lookup_field': 'name'}
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_image_url(self, obj):
|
def get_image_url(self, obj):
|
||||||
|
@ -100,7 +100,8 @@ class FeatureSerializer(RecursiveSerializerMixin, serializers.ModelSerializer):
|
||||||
fields = ('name', 'url', 'title', 'feature_type', 'level', 'titles', 'package', 'geometry')
|
fields = ('name', 'url', 'title', 'feature_type', 'level', 'titles', 'package', 'geometry')
|
||||||
sparse_exclude = ('feature_type', 'level', 'package')
|
sparse_exclude = ('feature_type', 'level', 'package')
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'url': {'view_name': 'api:feature-detail'}
|
'lookup_field': 'name',
|
||||||
|
'url': {'view_name': 'api:feature-detail', 'lookup_field': 'name'}
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_feature_type(self, obj):
|
def get_feature_type(self, obj):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue