mirror of
				https://github.com/HackSoftware/Django-Styleguide.git
				synced 2025-10-30 23:27:25 +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