mirror of
https://github.com/HackSoftware/Django-Styleguide.git
synced 2025-06-30 18:03:09 +03:00
Expand section for advanced serialization
This commit is contained in:
parent
f200a06334
commit
4a5a6e3604
70
README.md
70
README.md
|
@ -864,7 +864,75 @@ The implementation of `inline_serializer` can be found [here](https://github.com
|
||||||
|
|
||||||
### Advanced serialization
|
### Advanced serialization
|
||||||
|
|
||||||
*Coming soon*
|
Sometimes, the end result of an API can be quite complex. Sometimes, we want to optimize the queries that we do and the optimization itself is quite complex.
|
||||||
|
|
||||||
|
Trying to stick with just an `OutputSerializer` in that case might limit our options.
|
||||||
|
|
||||||
|
In those cases, we can implement our output serialization as a function, and have the optimizations we need there.
|
||||||
|
|
||||||
|
Lets take this API as an example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class SomeGenericFeedApi(BaseApi):
|
||||||
|
def get(self, request):
|
||||||
|
feed = some_feed_get(
|
||||||
|
user=request.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
data = some_feed_serialize(feed)
|
||||||
|
|
||||||
|
return Response(data)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this scenario, `some_feed_get` has the responsibility of returning a list of feed items (can be ORM objects, can be just IDs).
|
||||||
|
|
||||||
|
And we want to push the complexity of serializing this feed, in an optimal manner, to the serializer function - `some_feed_serialize`.
|
||||||
|
|
||||||
|
This means we don't have to do any unnecessary prefetches & optimizations in `some_feed_get`.
|
||||||
|
|
||||||
|
Here's an example of `some_feed_serialize`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class FeedItemSerializer(serializers.Serializer):
|
||||||
|
... some fields here ...
|
||||||
|
calculated_field = serializers.IntegerField(source="_calculated_field")
|
||||||
|
|
||||||
|
|
||||||
|
def some_feed_serialize(feed: List[FeedItem]):
|
||||||
|
feed_ids = [feed_item.id for feed_item in feed]
|
||||||
|
|
||||||
|
# Refetch items with more optimizations
|
||||||
|
# Based on the relations that are going in
|
||||||
|
objects = FeedItem.objects.select_related(
|
||||||
|
... as complex as you want ...
|
||||||
|
).prefetch_related(
|
||||||
|
... as complex as you want ...
|
||||||
|
).filter(
|
||||||
|
id__in=feed_ids
|
||||||
|
).order_by(
|
||||||
|
"-some_timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
some_cache = get_some_cache(feed_ids)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for feed_item in objects:
|
||||||
|
# An example, adding additional fields for the serializer
|
||||||
|
# That are based on values outside of our current object
|
||||||
|
# This may be some optimization to save queries
|
||||||
|
feed_item._calculated_field = some_cache.get(feed_item.id)
|
||||||
|
|
||||||
|
result.append(FeedItemSerializer(feed_item).data)
|
||||||
|
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see, this is a pretty generic example, but the idea is simple:
|
||||||
|
|
||||||
|
1. Refetch your data, with the needed joins & prefetches.
|
||||||
|
1. Fetch or build in-memory caches, that will save you queries for specific computed values.
|
||||||
|
1. Return a result, that's ready to be an API response.
|
||||||
|
|
||||||
## Urls
|
## Urls
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user