mirror of
https://github.com/HackSoftware/Django-Styleguide.git
synced 2024-11-22 09:36:36 +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
|
||||
|
||||
*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
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user