Merge branch 'api-serializers-enhancements' into 'master'
Api serializers enhancements See merge request funkwhale/funkwhale!941
This commit is contained in:
commit
d224f74f5d
|
@ -38,10 +38,26 @@ EMAIL_PORT = 1025
|
||||||
DEBUG_TOOLBAR_CONFIG = {
|
DEBUG_TOOLBAR_CONFIG = {
|
||||||
"DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
|
"DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
|
||||||
"SHOW_TEMPLATE_CONTEXT": True,
|
"SHOW_TEMPLATE_CONTEXT": True,
|
||||||
"SHOW_TOOLBAR_CALLBACK": lambda request: True,
|
"SHOW_TOOLBAR_CALLBACK": lambda request: "debug" in request.GET,
|
||||||
"JQUERY_URL": "/staticfiles/admin/js/vendor/jquery/jquery.js",
|
"JQUERY_URL": "/staticfiles/admin/js/vendor/jquery/jquery.js",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_TOOLBAR_PANELS = [
|
||||||
|
# 'debug_toolbar.panels.versions.VersionsPanel',
|
||||||
|
"debug_toolbar.panels.timer.TimerPanel",
|
||||||
|
"debug_toolbar.panels.settings.SettingsPanel",
|
||||||
|
"debug_toolbar.panels.headers.HeadersPanel",
|
||||||
|
# 'debug_toolbar.panels.request.RequestPanel',
|
||||||
|
"debug_toolbar.panels.sql.SQLPanel",
|
||||||
|
# 'debug_toolbar.panels.staticfiles.StaticFilesPanel',
|
||||||
|
# 'debug_toolbar.panels.templates.TemplatesPanel',
|
||||||
|
"debug_toolbar.panels.cache.CachePanel",
|
||||||
|
# 'debug_toolbar.panels.signals.SignalsPanel',
|
||||||
|
# 'debug_toolbar.panels.logging.LoggingPanel',
|
||||||
|
# 'debug_toolbar.panels.redirects.RedirectsPanel',
|
||||||
|
# 'debug_toolbar.panels.profiling.ProfilingPanel',
|
||||||
|
]
|
||||||
|
|
||||||
# django-extensions
|
# django-extensions
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# INSTALLED_APPS += ('django_extensions', )
|
# INSTALLED_APPS += ('django_extensions', )
|
||||||
|
@ -69,4 +85,7 @@ if env.bool("WEAK_PASSWORDS", default=False):
|
||||||
# Faster during tests
|
# Faster during tests
|
||||||
PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
|
PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
|
||||||
|
|
||||||
MIDDLEWARE = ("funkwhale_api.common.middleware.DevHttpsMiddleware",) + MIDDLEWARE
|
MIDDLEWARE = (
|
||||||
|
"funkwhale_api.common.middleware.DevHttpsMiddleware",
|
||||||
|
"funkwhale_api.common.middleware.ProfilerMiddleware",
|
||||||
|
) + MIDDLEWARE
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import html
|
import html
|
||||||
|
import io
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
import xml.sax.saxutils
|
import xml.sax.saxutils
|
||||||
|
@ -242,3 +243,53 @@ class ThrottleStatusMiddleware:
|
||||||
response["X-RateLimit-ResetSeconds"] = str(remaining)
|
response["X-RateLimit-ResetSeconds"] = str(remaining)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class ProfilerMiddleware:
|
||||||
|
"""
|
||||||
|
from https://github.com/omarish/django-cprofile-middleware/blob/master/django_cprofile_middleware/middleware.py
|
||||||
|
Simple profile middleware to profile django views. To run it, add ?prof to
|
||||||
|
the URL like this:
|
||||||
|
http://localhost:8000/view/?prof
|
||||||
|
Optionally pass the following to modify the output:
|
||||||
|
?sort => Sort the output by a given metric. Default is time.
|
||||||
|
See
|
||||||
|
http://docs.python.org/2/library/profile.html#pstats.Stats.sort_stats
|
||||||
|
for all sort options.
|
||||||
|
?count => The number of rows to display. Default is 100.
|
||||||
|
?download => Download profile file suitable for visualization. For example
|
||||||
|
in snakeviz or RunSnakeRun
|
||||||
|
This is adapted from an example found here:
|
||||||
|
http://www.slideshare.net/zeeg/django-con-high-performance-django-presentation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, get_response):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
|
if "prof" not in request.GET:
|
||||||
|
return self.get_response(request)
|
||||||
|
import profile
|
||||||
|
import pstats
|
||||||
|
|
||||||
|
profiler = profile.Profile()
|
||||||
|
response = profiler.runcall(self.get_response, request)
|
||||||
|
profiler.create_stats()
|
||||||
|
if "prof-download" in request.GET:
|
||||||
|
import marshal
|
||||||
|
|
||||||
|
output = marshal.dumps(profiler.stats)
|
||||||
|
response = http.HttpResponse(
|
||||||
|
output, content_type="application/octet-stream"
|
||||||
|
)
|
||||||
|
response["Content-Disposition"] = "attachment; filename=view.prof"
|
||||||
|
response["Content-Length"] = len(output)
|
||||||
|
stream = io.StringIO()
|
||||||
|
stats = pstats.Stats(profiler, stream=stream)
|
||||||
|
|
||||||
|
stats.sort_stats(request.GET.get("prof-sort", "cumtime"))
|
||||||
|
stats.print_stats(int(request.GET.get("count", 100)))
|
||||||
|
|
||||||
|
response = http.HttpResponse("<pre>%s</pre>" % stream.getvalue())
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
|
@ -436,7 +436,7 @@ class TrackQuerySet(common_models.LocalFromFidQuerySet, models.QuerySet):
|
||||||
return self.exclude(pk__in=matches)
|
return self.exclude(pk__in=matches)
|
||||||
|
|
||||||
def with_playable_uploads(self, actor):
|
def with_playable_uploads(self, actor):
|
||||||
uploads = Upload.objects.playable_by(actor).select_related("track")
|
uploads = Upload.objects.playable_by(actor)
|
||||||
return self.prefetch_related(
|
return self.prefetch_related(
|
||||||
models.Prefetch("uploads", queryset=uploads, to_attr="playable_uploads")
|
models.Prefetch("uploads", queryset=uploads, to_attr="playable_uploads")
|
||||||
)
|
)
|
||||||
|
@ -594,7 +594,8 @@ class Track(APIModelMixin):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def listen_url(self):
|
def listen_url(self):
|
||||||
return reverse("api:v1:listen-detail", kwargs={"uuid": self.uuid})
|
# Not using reverse because this is slow
|
||||||
|
return "/api/v1/listen/{}/".format(self.uuid)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_license(self):
|
def local_license(self):
|
||||||
|
|
|
@ -45,26 +45,21 @@ class LicenseSerializer(serializers.Serializer):
|
||||||
return obj["identifiers"][0]
|
return obj["identifiers"][0]
|
||||||
|
|
||||||
|
|
||||||
class ArtistAlbumSerializer(serializers.ModelSerializer):
|
class ArtistAlbumSerializer(serializers.Serializer):
|
||||||
tracks_count = serializers.SerializerMethodField()
|
tracks_count = serializers.SerializerMethodField()
|
||||||
cover = cover_field
|
cover = cover_field
|
||||||
is_playable = serializers.SerializerMethodField()
|
is_playable = serializers.SerializerMethodField()
|
||||||
|
is_local = serializers.BooleanField()
|
||||||
|
id = serializers.IntegerField()
|
||||||
|
fid = serializers.URLField()
|
||||||
|
mbid = serializers.UUIDField()
|
||||||
|
title = serializers.CharField()
|
||||||
|
artist = serializers.SerializerMethodField()
|
||||||
|
release_date = serializers.DateField()
|
||||||
|
creation_date = serializers.DateTimeField()
|
||||||
|
|
||||||
class Meta:
|
def get_artist(self, o):
|
||||||
model = models.Album
|
return o.artist_id
|
||||||
fields = (
|
|
||||||
"id",
|
|
||||||
"fid",
|
|
||||||
"mbid",
|
|
||||||
"title",
|
|
||||||
"artist",
|
|
||||||
"release_date",
|
|
||||||
"cover",
|
|
||||||
"creation_date",
|
|
||||||
"tracks_count",
|
|
||||||
"is_playable",
|
|
||||||
"is_local",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_tracks_count(self, o):
|
def get_tracks_count(self, o):
|
||||||
return o._tracks_count
|
return o._tracks_count
|
||||||
|
@ -76,26 +71,20 @@ class ArtistAlbumSerializer(serializers.ModelSerializer):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ArtistWithAlbumsSerializer(serializers.ModelSerializer):
|
DATETIME_FIELD = serializers.DateTimeField()
|
||||||
albums = ArtistAlbumSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
|
class ArtistWithAlbumsSerializer(serializers.Serializer):
|
||||||
|
albums = ArtistAlbumSerializer(many=True)
|
||||||
tags = serializers.SerializerMethodField()
|
tags = serializers.SerializerMethodField()
|
||||||
attributed_to = serializers.SerializerMethodField()
|
attributed_to = serializers.SerializerMethodField()
|
||||||
tracks_count = serializers.SerializerMethodField()
|
tracks_count = serializers.SerializerMethodField()
|
||||||
|
id = serializers.IntegerField()
|
||||||
class Meta:
|
fid = serializers.URLField()
|
||||||
model = models.Artist
|
mbid = serializers.UUIDField()
|
||||||
fields = (
|
name = serializers.CharField()
|
||||||
"id",
|
creation_date = serializers.DateTimeField()
|
||||||
"fid",
|
is_local = serializers.BooleanField()
|
||||||
"mbid",
|
|
||||||
"name",
|
|
||||||
"creation_date",
|
|
||||||
"albums",
|
|
||||||
"is_local",
|
|
||||||
"tags",
|
|
||||||
"attributed_to",
|
|
||||||
"tracks_count",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_tags(self, obj):
|
def get_tags(self, obj):
|
||||||
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
|
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
|
||||||
|
@ -114,9 +103,7 @@ def serialize_artist_simple(artist):
|
||||||
"fid": artist.fid,
|
"fid": artist.fid,
|
||||||
"mbid": str(artist.mbid),
|
"mbid": str(artist.mbid),
|
||||||
"name": artist.name,
|
"name": artist.name,
|
||||||
"creation_date": serializers.DateTimeField().to_representation(
|
"creation_date": DATETIME_FIELD.to_representation(artist.creation_date),
|
||||||
artist.creation_date
|
|
||||||
),
|
|
||||||
"is_local": artist.is_local,
|
"is_local": artist.is_local,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +116,7 @@ def serialize_album_track(track):
|
||||||
"title": track.title,
|
"title": track.title,
|
||||||
"artist": serialize_artist_simple(track.artist),
|
"artist": serialize_artist_simple(track.artist),
|
||||||
"album": track.album_id,
|
"album": track.album_id,
|
||||||
"creation_date": serializers.DateTimeField().to_representation(
|
"creation_date": DATETIME_FIELD.to_representation(track.creation_date),
|
||||||
track.creation_date
|
|
||||||
),
|
|
||||||
"position": track.position,
|
"position": track.position,
|
||||||
"disc_number": track.disc_number,
|
"disc_number": track.disc_number,
|
||||||
"uploads": [
|
"uploads": [
|
||||||
|
@ -145,31 +130,22 @@ def serialize_album_track(track):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AlbumSerializer(serializers.ModelSerializer):
|
class AlbumSerializer(serializers.Serializer):
|
||||||
tracks = serializers.SerializerMethodField()
|
tracks = serializers.SerializerMethodField()
|
||||||
artist = serializers.SerializerMethodField()
|
artist = serializers.SerializerMethodField()
|
||||||
cover = cover_field
|
cover = cover_field
|
||||||
is_playable = serializers.SerializerMethodField()
|
is_playable = serializers.SerializerMethodField()
|
||||||
tags = serializers.SerializerMethodField()
|
tags = serializers.SerializerMethodField()
|
||||||
attributed_to = serializers.SerializerMethodField()
|
attributed_to = serializers.SerializerMethodField()
|
||||||
|
id = serializers.IntegerField()
|
||||||
class Meta:
|
fid = serializers.URLField()
|
||||||
model = models.Album
|
mbid = serializers.UUIDField()
|
||||||
fields = (
|
title = serializers.CharField()
|
||||||
"id",
|
artist = serializers.SerializerMethodField()
|
||||||
"fid",
|
release_date = serializers.DateField()
|
||||||
"mbid",
|
creation_date = serializers.DateTimeField()
|
||||||
"title",
|
is_local = serializers.BooleanField()
|
||||||
"artist",
|
is_playable = serializers.SerializerMethodField()
|
||||||
"tracks",
|
|
||||||
"release_date",
|
|
||||||
"cover",
|
|
||||||
"creation_date",
|
|
||||||
"is_playable",
|
|
||||||
"is_local",
|
|
||||||
"tags",
|
|
||||||
"attributed_to",
|
|
||||||
)
|
|
||||||
|
|
||||||
get_attributed_to = serialize_attributed_to
|
get_attributed_to = serialize_attributed_to
|
||||||
|
|
||||||
|
@ -227,7 +203,7 @@ def serialize_upload(upload):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TrackSerializer(serializers.ModelSerializer):
|
class TrackSerializer(serializers.Serializer):
|
||||||
artist = serializers.SerializerMethodField()
|
artist = serializers.SerializerMethodField()
|
||||||
album = TrackAlbumSerializer(read_only=True)
|
album = TrackAlbumSerializer(read_only=True)
|
||||||
uploads = serializers.SerializerMethodField()
|
uploads = serializers.SerializerMethodField()
|
||||||
|
@ -235,26 +211,17 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
tags = serializers.SerializerMethodField()
|
tags = serializers.SerializerMethodField()
|
||||||
attributed_to = serializers.SerializerMethodField()
|
attributed_to = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
id = serializers.IntegerField()
|
||||||
model = models.Track
|
fid = serializers.URLField()
|
||||||
fields = (
|
mbid = serializers.UUIDField()
|
||||||
"id",
|
title = serializers.CharField()
|
||||||
"fid",
|
artist = serializers.SerializerMethodField()
|
||||||
"mbid",
|
creation_date = serializers.DateTimeField()
|
||||||
"title",
|
is_local = serializers.BooleanField()
|
||||||
"album",
|
position = serializers.IntegerField()
|
||||||
"artist",
|
disc_number = serializers.IntegerField()
|
||||||
"creation_date",
|
copyright = serializers.CharField()
|
||||||
"position",
|
license = serializers.SerializerMethodField()
|
||||||
"disc_number",
|
|
||||||
"uploads",
|
|
||||||
"listen_url",
|
|
||||||
"copyright",
|
|
||||||
"license",
|
|
||||||
"is_local",
|
|
||||||
"tags",
|
|
||||||
"attributed_to",
|
|
||||||
)
|
|
||||||
|
|
||||||
get_attributed_to = serialize_attributed_to
|
get_attributed_to = serialize_attributed_to
|
||||||
|
|
||||||
|
@ -271,6 +238,9 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
|
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
|
||||||
return [ti.tag.name for ti in tagged_items]
|
return [ti.tag.name for ti in tagged_items]
|
||||||
|
|
||||||
|
def get_license(self, o):
|
||||||
|
return o.license_id
|
||||||
|
|
||||||
|
|
||||||
@common_serializers.track_fields_for_update("name", "description", "privacy_level")
|
@common_serializers.track_fields_for_update("name", "description", "privacy_level")
|
||||||
class LibraryForOwnerSerializer(serializers.ModelSerializer):
|
class LibraryForOwnerSerializer(serializers.ModelSerializer):
|
||||||
|
|
Loading…
Reference in New Issue