-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
APIv3: add more generic fields #11205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b2635aa
556dd42
e1f4167
1ddbbb5
e0b2ca0
869f953
132a00c
eb3bf85
9e31c81
2c81f2f
80b3f5f
302d8a0
f6f8940
5b64ec1
c672071
513355e
f7ca124
9d0f9d2
6c26948
afcfda9
b04c2a0
c3bc391
700cc5d
87020d1
5f7a9d7
94a0c00
571308d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| from rest_framework import serializers | ||
| from taggit.serializers import TaggitSerializer, TagListSerializerField | ||
|
|
||
| from readthedocs.builds.constants import LATEST, STABLE | ||
| from readthedocs.builds.models import Build, Version | ||
| from readthedocs.core.resolver import Resolver | ||
| from readthedocs.core.utils import slugify | ||
|
|
@@ -322,13 +323,15 @@ class VersionURLsSerializer(BaseLinksSerializer, serializers.Serializer): | |
| dashboard = VersionDashboardURLsSerializer(source="*") | ||
|
|
||
| def get_documentation(self, obj): | ||
| return Resolver().resolve_version( | ||
| resolver = getattr(self.parent, "resolver", Resolver()) | ||
| return resolver.resolve_version( | ||
| project=obj.project, | ||
| version=obj, | ||
| ) | ||
|
|
||
|
|
||
| class VersionSerializer(FlexFieldsModelSerializer): | ||
| aliases = serializers.SerializerMethodField() | ||
| ref = serializers.CharField() | ||
| downloads = serializers.SerializerMethodField() | ||
| urls = VersionURLsSerializer(source="*") | ||
|
|
@@ -337,6 +340,7 @@ class VersionSerializer(FlexFieldsModelSerializer): | |
| class Meta: | ||
| model = Version | ||
| fields = [ | ||
| "aliases", | ||
| "id", | ||
| "slug", | ||
| "verbose_name", | ||
|
|
@@ -354,6 +358,17 @@ class Meta: | |
|
|
||
| expandable_fields = {"last_build": (BuildSerializer,)} | ||
|
|
||
| def __init__(self, *args, resolver=None, version_serializer=None, **kwargs): | ||
| super().__init__(*args, **kwargs) | ||
|
|
||
| # Use a shared resolver to reduce the amount of DB queries while | ||
| # resolving version URLs. | ||
| self.resolver = kwargs.pop("resolver", Resolver()) | ||
|
|
||
| # Allow passing a specific serializer when initializing it. | ||
| # This is required to pass ``VersionSerializerNoLinks`` from the addons API. | ||
| self.version_serializer = version_serializer or VersionSerializer | ||
|
|
||
| def get_downloads(self, obj): | ||
| downloads = obj.get_downloads() | ||
| data = {} | ||
|
|
@@ -368,6 +383,16 @@ def get_downloads(self, obj): | |
|
|
||
| return data | ||
|
|
||
| def get_aliases(self, obj): | ||
| if obj.machine and obj.slug in (STABLE, LATEST): | ||
| if obj.slug == STABLE: | ||
| alias_version = obj.project.get_original_stable_version() | ||
| if obj.slug == LATEST: | ||
| alias_version = obj.project.get_original_latest_version() | ||
| if alias_version and alias_version.active: | ||
| return [self.version_serializer(alias_version).data] | ||
| return [] | ||
|
|
||
|
|
||
| class VersionUpdateSerializer(serializers.ModelSerializer): | ||
|
|
||
|
|
@@ -426,10 +451,12 @@ class ProjectURLsSerializer(BaseLinksSerializer, serializers.Serializer): | |
|
|
||
| """Serializer with all the user-facing URLs under Read the Docs.""" | ||
|
|
||
| documentation = serializers.CharField(source="get_docs_url") | ||
| documentation = serializers.SerializerMethodField() | ||
|
|
||
| home = serializers.SerializerMethodField() | ||
| builds = serializers.SerializerMethodField() | ||
| versions = serializers.SerializerMethodField() | ||
| downloads = serializers.SerializerMethodField() | ||
|
|
||
| def get_home(self, obj): | ||
| path = reverse("projects_detail", kwargs={"project_slug": obj.slug}) | ||
|
|
@@ -443,6 +470,15 @@ def get_versions(self, obj): | |
| path = reverse("project_version_list", kwargs={"project_slug": obj.slug}) | ||
| return self._absolute_url(path) | ||
|
|
||
| def get_downloads(self, obj): | ||
| path = reverse("project_downloads", kwargs={"project_slug": obj.slug}) | ||
| return self._absolute_url(path) | ||
|
|
||
| def get_documentation(self, obj): | ||
| version_slug = getattr(self.parent, "version_slug", None) | ||
| resolver = getattr(self.parent, "resolver", Resolver()) | ||
| return obj.get_docs_url(version_slug=version_slug, resolver=resolver) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we already have the version object, we can just call
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made this change, but for some reason the amount of queries increased using This is the diff applied: diff --git a/common b/common
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 4af0fffd2cbeeb40f0a71b875beb99d6dc88a355
+Subproject commit 4af0fffd2cbeeb40f0a71b875beb99d6dc88a355-dirty
diff --git a/readthedocs/api/v3/serializers.py b/readthedocs/api/v3/serializers.py
index f0eb9237c..03c4d9a03 100644
--- a/readthedocs/api/v3/serializers.py
+++ b/readthedocs/api/v3/serializers.py
@@ -475,9 +475,9 @@ class ProjectURLsSerializer(BaseLinksSerializer, serializers.Serializer):
return self._absolute_url(path)
def get_documentation(self, obj):
- version_slug = getattr(self.parent, "version_slug", None)
+ version = getattr(self.parent, "version", None)
resolver = getattr(self.parent, "resolver", Resolver())
- return obj.get_docs_url(version_slug=version_slug, resolver=resolver)
+ return resolver.resolve_version(project=obj, version=version)
class RepositorySerializer(serializers.Serializer):
@@ -801,8 +801,8 @@ class ProjectSerializer(FlexFieldsModelSerializer):
}
def __init__(self, *args, **kwargs):
- # Receive a `Version.slug` here to build URLs properly
- self.version_slug = kwargs.pop("version_slug", None)
+ # Receive a `Version` here to build URLs properly
+ self.version = kwargs.pop("version", None)
# Use a shared resolver to reduce the amount of DB queries while
# resolving version URLs.
diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py
index f70638632..52a477ead 100644
--- a/readthedocs/proxito/views/hosting.py
+++ b/readthedocs/proxito/views/hosting.py
@@ -354,12 +354,12 @@ class AddonsResponse:
"current": ProjectSerializerNoLinks(
project,
resolver=resolver,
- version_slug=version.slug if version else None,
+ version=version,
).data,
"translations": ProjectSerializerNoLinks(
project_translations,
resolver=resolver,
- version_slug=version.slug if version else None,
+ version=version,
many=True,
).data,
},I will leave the code as-is for now. Let me know if you understand why or feel free to open an issue to track this performance improvement.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My two guesses:
|
||
|
|
||
|
|
||
| class RepositorySerializer(serializers.Serializer): | ||
| url = serializers.CharField(source="repo") | ||
|
|
@@ -765,6 +801,13 @@ class Meta: | |
| } | ||
|
|
||
| def __init__(self, *args, **kwargs): | ||
| # Receive a `Version.slug` here to build URLs properly | ||
| self.version_slug = kwargs.pop("version_slug", None) | ||
|
|
||
| # Use a shared resolver to reduce the amount of DB queries while | ||
| # resolving version URLs. | ||
| self.resolver = kwargs.pop("resolver", Resolver()) | ||
|
|
||
| super().__init__(*args, **kwargs) | ||
| # When using organizations, projects don't have the concept of users. | ||
| # But we have organization.owners. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "active": true, | ||
| "aliases": [], | ||
| "hidden": false, | ||
| "built": true, | ||
| "downloads": { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we pass this to the constructor? That way is more explicit, rather than relying on the attribute being present in the parent serialzer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe at this line
readthedocs.org/readthedocs/api/v3/serializers.py
Line 337 in 94a0c00
However, that would be a new instance of the Resolver since it's at the class definition and we want to share the instance the parent serializer is using due to caching purposes.
Are you thinking something different here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you could pass this in the context of the serializer, something like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. It sounds similar to what I did but more standardized. I found some documentation about this at https://www.django-rest-framework.org/api-guide/serializers/#including-extra-context
I opened #11280 to track this refactor as it's not a blocker for now and it may not be required in the future anyways.