@@ -518,7 +518,7 @@ def update(self, instance, validated_data):
518518
519519
520520def retrieve_thumbail_src (item ):
521- """ Get either the encoding or the url to use as the <img> src attribute """
521+ """Get either the encoding or the url to use as the <img> src attribute"""
522522 try :
523523 if item .get ("thumbnail_encoding" ):
524524 encoding = json .loads (item .get ("thumbnail_encoding" ))
@@ -705,54 +705,64 @@ def dict_if_none(obj, field_name=None):
705705
706706class ContentNodePagination (ValuesViewsetCursorPagination ):
707707 """
708- A simplified cursor pagination class for ContentNodeViewSet.
709- Instead of using an opaque cursor, it uses the lft value for filtering.
710- As such, if this pagination scheme is used without applying a filter
711- that will guarantee membership to a specific MPTT tree, such as parent
712- or tree_id, the pagination scheme will not be predictable.
708+ A simplified cursor pagination class
709+ Instead of using a fixed 'lft' cursor, it dynamically sets the pagination field and operator
710+ based on the incoming `ordering` query parameter.
713711 """
714712
715- cursor_query_param = "lft__gt"
716- ordering = "lft"
717713 page_size_query_param = "max_results"
718714 max_page_size = 100
719715
716+ def get_pagination_params (self ):
717+ # Default ordering is "lft" if not provided.
718+ ordering_param = self .request .query_params .get ("ordering" , "lft" )
719+ # Remove the leading '-' if present to get the field name.
720+ pagination_field = ordering_param .lstrip ("-" )
721+ # Determine operator: if ordering starts with '-', use __lt; otherwise __gt.
722+ operator = "__lt" if ordering_param .startswith ("-" ) else "__gt"
723+ return pagination_field , operator
724+
720725 def decode_cursor (self , request ):
721726 """
722- Given a request with a cursor, return a `Cursor` instance.
727+ Given a request with a cursor parameter, return a `Cursor` instance.
728+ The cursor parameter name is dynamically built from the pagination field and operator.
723729 """
724- # Determine if we have a cursor, and if so then decode it.
725- value = request .query_params .get (self .cursor_query_param )
730+ pagination_field , operator = self .get_pagination_params ()
731+ cursor_param = f"{ pagination_field } { operator } "
732+ value = request .query_params .get (cursor_param )
726733 if value is None :
727734 return None
728735
729- try :
730- value = int (value )
731- except ValueError :
732- raise ValidationError (
733- "lft must be an integer but an invalid value was given."
734- )
736+ if pagination_field == "lft" :
737+ try :
738+ value = int (value )
739+ except ValueError :
740+ raise ValidationError (
741+ "lft must be an integer but an invalid value was given."
742+ )
735743
736744 return Cursor (offset = 0 , reverse = False , position = value )
737745
738746 def encode_cursor (self , cursor ):
739747 """
740- Given a Cursor instance, return an url with query parameter.
748+ Given a Cursor instance, return a URL with the dynamic pagination cursor query parameter.
741749 """
742- return replace_query_param (
743- self . base_url , self . cursor_query_param , str ( cursor . position )
744- )
750+ pagination_field , operator = self . get_pagination_params ()
751+ cursor_param = f" { pagination_field } { operator } "
752+ return replace_query_param ( self . base_url , cursor_param , str ( cursor . position ) )
745753
746754 def get_more (self ):
755+ """
756+ Construct a "more" URL (or query parameters) that includes the pagination cursor
757+ built from the dynamic field and operator.
758+ """
759+ pagination_field , operator = self .get_pagination_params ()
760+ cursor_param = f"{ pagination_field } { operator } "
747761 position , offset = self ._get_more_position_offset ()
748762 if position is None and offset is None :
749763 return None
750764 params = self .request .query_params .copy ()
751- params .update (
752- {
753- self .cursor_query_param : position ,
754- }
755- )
765+ params .update ({cursor_param : position })
756766 return params
757767
758768
@@ -1068,7 +1078,7 @@ def copy(
10681078 position = None ,
10691079 mods = None ,
10701080 excluded_descendants = None ,
1071- ** kwargs
1081+ ** kwargs ,
10721082 ):
10731083 target , position = self .validate_targeting_args (target , position )
10741084
@@ -1133,7 +1143,7 @@ def perform_create(self, serializer, change=None):
11331143 )
11341144
11351145 def update_descendants (self , pk , mods ):
1136- """ Update a node and all of its descendants with the given mods """
1146+ """Update a node and all of its descendants with the given mods"""
11371147 root = ContentNode .objects .get (id = pk )
11381148
11391149 if root .kind_id != content_kinds .TOPIC :
0 commit comments