
    hW                         d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZmZmZ dd	lmZmZmZmZ d
Z G d de      Zd Z G d de      Zy)z
QuerySet for PolymorphicModel
    N)defaultdict)ContentType)FieldDoesNotExist)FilteredRelation)ModelIterableQQuerySet   ) translate_polymorphic_field_path0translate_polymorphic_filter_definitions_in_args2translate_polymorphic_filter_definitions_in_kwargstranslate_polymorphic_Q_objectd   c                   (     e Zd ZdZ fdZd Z xZS )PolymorphicModelIterablez
    ModelIterable for PolymorphicModel

    Yields real instances if qs.polymorphic_disabled is False,
    otherwise acts like a regular ModelIterable.
    c                 r    t         |          }| j                  j                  r|S | j	                  |      S N)super__iter__querysetpolymorphic_disabled_polymorphic_iterator)self	base_iter	__class__s     A/home/dcms/DCMS/lib/python3.12/site-packages/polymorphic/query.pyr   z!PolymorphicModelIterable.__iter__!   s4    G$&	==--)))44    c              #      K   	 g }d}t        t              D ]  }	 t        |      }|j                  |       ! | j
                  j                  |      }|D ]  }|  |ry_# t        $ r d}Y  8w xY ww)a!  
        Here we do the same as::

            real_results = queryset._get_real_instances(list(base_iter))
            for o in real_results: yield o

        but it requests the objects in chunks from the database,
        with Polymorphic_QuerySet_objects_per_request per chunk
        TFN)range(Polymorphic_QuerySet_objects_per_requestnextappendStopIterationr   _get_real_instances)r   r   base_result_objectsreached_endioreal_resultss          r   r   z.PolymorphicModelIterable._polymorphic_iterator'   s      "$K CD YA'..q1  ==<<=PQL!  )  % "&Ks'   A5A#,A5#A2.A51A22A5)__name__
__module____qualname____doc__r   r   __classcell__r   s   @r   r   r      s    5r   r   c                     d|j                   vr|}| |_        |S  |        }|j                   j                         D ]  \  }}||j                   |<    |S )zF
    Upcast a class to a different type without asking questions.
    __init__)__dict__r   items)clsobjnewkvs        r   transmogrifyr9   H   s^     % J eLL&&( 	 DAqCLLO	 Jr   c                        e Zd ZdZ fdZ fdZd Zde_         ee      Zd fd	Z	d Z
d Zd	 Z fd
Z fdZ fdZ fdZd Zd Zd Z fdZ fdZ fdZd Z fdZ G d de      ZddZ xZS )PolymorphicQuerySetz
    QuerySet for PolymorphicModel

    Contains the core functionality for PolymorphicModel

    Usually not explicitly needed, except if a custom queryset class
    is to be used.
    c                 j    t        |   |i | t        | _        d| _        t               df| _        y )NFT)r   r1   r   _iterable_classr   setpolymorphic_deferred_loadingr   argskwargsr   s      r   r1   zPolymorphicQuerySet.__init__f   s5    $)&)7$)! .1UDM)r   c                     t        |   |i |}| j                  |_        t        j                  | j                  d         | j                  d   f|_        |S )Nr   r
   )r   _cloner   copyr?   )r   rA   rB   r6   r   s       r   rD   zPolymorphicQuerySet._cloner   sZ    gnd-f-#'#<#< IId77:;--a0,
( 
r   c                 L    ddl m}  |j                  |              }d|_        |S )Nr
   )PolymorphicManagerT)managersrG   from_queryset_built_with_as_manager)r4   rG   managers      r   
as_managerzPolymorphicQuerySet.as_manager|   s(    07$22379)-&r   Tc                 l    t        |      }|D ]  }|j                           t        |   |||      S )N)ignore_conflicts)listpre_save_polymorphicr   bulk_create)r   objs
batch_sizerN   r5   r   s        r   rQ   zPolymorphicQuerySet.bulk_create   s?    Dz 	'C$$&	'w"4FV"WWr   c                 ~    | j                         }d|_        t        |j                  t              rt
        |_        |S )zswitch off polymorphic behaviour for this query.
        When the queryset is evaluated, only objects of the type of the
        base class used for this query are returned.T)rD   r   
issubclassr=   r   r   )r   qss     r   non_polymorphicz#PolymorphicQuerySet.non_polymorphic   s5     [[]"&b((*BC!.B	r   c                 &    | j                  |      S )zOFilter the queryset to only include the classes in args (and their subclasses).)instance_offilterr   rA   s     r   rY   zPolymorphicQuerySet.instance_of   s     {{t{,,r   c                 &    | j                  |      S )zJFilter the queryset to exclude the classes in args (and their subclasses).)not_instance_ofrZ   r\   s     r   r^   z#PolymorphicQuerySet.not_instance_of   s     {{4{00r   c                     t        | j                  || j                        }t        | j                  || j                        }t	        |      |z   }t
        |   |||      S )N)queryset_modelrA   using)r`   rB   ra   )negaterA   rB   )r   modeldbr   rO   r   _filter_or_exclude)r   rb   rA   rB   	q_objectsadditional_argsr   s         r   re   z&PolymorphicQuerySet._filter_or_exclude   s_    D::D
	 M::fDGG
 I0w)d6)RRr   c                     |D cg c]*  }t        |t              rt        | j                  |      n|, }}t	        |   | S c c}w )zBtranslate the field paths in the args, then call vanilla order_by.)
isinstancestrr   rc   r   order_by)r   field_namesar   s      r   rk   zPolymorphicQuerySet.order_by   sZ     !	
  !S! -TZZ;
 
 w--
s   /Ac                     |D cg c]  }t        | j                  |       }}t        |   | }|j	                  |       |S c c}w )a!  
        Translate the field paths in the args, then call vanilla defer.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        )r   rc   r   defer!_polymorphic_add_deferred_loadingr   fieldsrm   
new_fieldscloner   s        r   ro   zPolymorphicQuerySet.defer   sM     PVV!6tzz1EV
Vz*//7 W   Ac                     |D cg c]  }t        | j                  |       }}t        |   | }|j	                  |       |S c c}w )a   
        Translate the field paths in the args, then call vanilla only.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        )r   rc   r   only"_polymorphic_add_immediate_loadingrq   s        r   rw   zPolymorphicQuerySet.only   sM     PVV!6tzz1EV
Vj)008 Wru   c                     | j                   \  }}|r|j                  |      df| _         y|j                  |      df| _         y)z
        Follows the logic of django.db.models.query.Query.add_deferred_loading(),
        but for the non-translated field names that were passed to self.defer().
        TFN)r?   union
differencer   rl   existingro   s       r   rp   z5PolymorphicQuerySet._polymorphic_add_deferred_loading   sG    
 ;;%08{0KT0QD- 190C0CK0PRW0WD-r   c                    | j                   \  }}t        |      }d|v rJ|j                  d       |j                  | j                  j
                  j                  j                         |r|j                  |      df| _         y|df| _         y)z
        Follows the logic of django.db.models.query.Query.add_immediate_loading(),
        but for the non-translated field names that were passed to self.only()
        pkFN)	r?   r>   removeaddrc   _metar   namer{   r|   s       r   rx   z6PolymorphicQuerySet._polymorphic_add_immediate_loading   s    
 ;;%+&;t$OODJJ,,//445 1<0F0Fx0PRW0WD- 1<U0BD-r   c                      d fd fd|D ]
  } |        |j                         D ]
  } |        y)zfor aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args.
        Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)
        z_PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments onlyc                 >   t        | t              rt        j                  |        y t        | t              r | j
                         y t        | d      r!| j                         D ]  }| |        y t        j                  | j                        | _	        y )Nget_source_expressions)
ri   r   r   rc   r   	conditionhasattrr   r   r   )rm   source_expressionpatch_lookupr   s     r   r   zAPolymorphicQuerySet._process_aggregate_args.<locals>.patch_lookup   s     !Q.tzz1=A/0Q[[)45)*)A)A)C 8%(4$%678 :$**affMr   c                     t        | t              rfd j                  |        yt        | d      r!| j	                         D ]  }| |        yd| j
                  vsJ        y)zy*args might be complex expressions too in django 1.8 so
            the testing for a '___' is rather complex on this onec                     t        t        |j                              D ];  }|j                  |   }t        |      t        k(  rd|d   vr,J         | |       = y)z#process all children of this Q node___r   N)r   lenchildrentypetuple)my_modelnoder'   child(_PolymorphicQuerySet___lookup_assert_msgtree_node_test___lookups       r   r   zcPolymorphicQuerySet._process_aggregate_args.<locals>.test___lookup.<locals>.tree_node_test___lookup	  s`    "3t}}#56 E $a 0;%/#(a#8N:NN#8 4HeDEr   r   Nr   )ri   r   rc   r   r   r   )rm   r   r   r   r   test___lookups     @r   r   zBPolymorphicQuerySet._process_aggregate_args.<locals>.test___lookup  sr     !Q
E (

A645)*)A)A)C 9%(4%&789 AFF*@,@@*r   N)values)r   rA   rB   rm   r   r   r   s   `   @@@r   _process_aggregate_argsz+PolymorphicQuerySet._process_aggregate_args   sM      A	N	A2  	A!	 	AO	r   c                 F    | j                  ||       t        |   |i |S )ztranslate the polymorphic field paths in the kwargs, then call vanilla annotate.
        _get_real_instances will do the rest of the job after executing the query.)r   r   annotater@   s      r   r   zPolymorphicQuerySet.annotate"  s*     	$$T62w000r   c                 n    | j                  ||       | j                         }t        t        |  |i |S )ztranslate the polymorphic field paths in the kwargs, then call vanilla aggregate.
        We need no polymorphic object retrieval for aggregate => switch it off.)r   rW   r   r;   	aggregate)r   rA   rB   rV   r   s       r   r   zPolymorphicQuerySet.aggregate(  s;     	$$T62!!#("7HHHr   c                 4    t        |   |i |}d|_        |S )NT)r   _valuesr   )r   rA   rB   rt   r   s       r   r   zPolymorphicQuerySet._values2  s#    00%)"r   c                 	   g }t        t              }t        t              }| j                  j                  }t        j
                  j                  | j                        }|j                  | j                  d      j                  }|j                  | j                  d      j                  }t        |      D ]  \  }	}
|
j                  |k(  r|j                  |
       '|
j                         }|
j                         }|J||k(  r|j                  t        ||
             k|j!                  |      j#                         }||   j                  t%        |
|             ||   j                  |	t'        |      f       |j                  d        |j)                         D ]	  \  }}||   } |j*                  j                  | j                        j,                  d
i | d|i}| j.                  j0                  |j.                  _        g }| j2                  d   }|D ]   }	 t5        ||      }|j                  |       " tA        |      | j.                  jB                  d	   f|j.                  _!        |D ci c]  }t%        ||      | }}|D ]  \  }	}||	   }
t%        |
|      }|jE                  |      }|,tG        jF                  |      }|j                         }||k7  rt        ||      }| j.                  jH                  rB| j.                  jH                  jK                         D ]  }t%        |
|      }tM        |||        | j.                  jN                  rB| j.                  jN                  jK                         D ]  }t%        |
|      }tM        |||        |||<     |D 	cg c]  }	|	s|		 }}	| j.                  jH                  r;t        | j.                  jH                  jK                               }|D ]	  }||_(         | j.                  jN                  r;t        | j.                  jN                  jK                               }|D ]	  }||_)         |S # t6        $ rK d|v rB|j9                  d      d   }	 |j:                  j=                  |       n# t>        $ r Y Y w xY w Y w xY wc c}w c c}	w )ai  
        Polymorphic object loader

        Does the same as:

            return [ o.get_real_instance() for o in base_result_objects ]

        but more efficiently.

        The list base_result_objects contains the objects from the executed
        base class query. The class of all of them is self.model (our base model).

        Some, many or all of these objects were not created and stored as
        class self.model, but as a class derived from self.model. We want to re-fetch
        these objects from the db as their original class so we can return them
        just as they were created/saved.

        We identify these objects by looking at o.polymorphic_ctype, which specifies
        the real class of these objects (the class at the time they were saved).

        First, we sort the result objects in base_result_objects for their
        subclass (from o.polymorphic_ctype), and then we execute one db query per
        subclass of objects. Here, we handle any annotations from annotate().

        Finally we re-sort the resulting objects into the correct order and
        return them as a list.
        F)for_concrete_modelTN__inr   r   r
    )*r   rO   rc   polymorphic_primary_key_namer   objects
db_managerrd   get_for_modelr   	enumeratepolymorphic_ctype_idr"   get_real_instance_class#get_real_concrete_instance_class_idr9   
get_for_idmodel_classgetattrr   r3   _base_objectsr[   queryselect_relatedr?   r   AssertionError
rpartitionr   	get_fieldr   r>   deferred_loadinggetrE   annotationskeyssetattrextra_selectpolymorphic_annotate_namespolymorphic_extra_select_names)r   r%   
resultlistidlist_per_modelindexlist_per_modelpk_namecontent_type_managerself_model_class_idself_concrete_model_class_idr'   base_objectreal_concrete_classreal_concrete_class_ididlistindicesreal_objectsdeferred_loading_fieldsexisting_fieldsfieldtranslated_field_namereal_objectreal_objects_dictjo_pk
real_classanno_field_nameattrselect_field_nameannotate_namesextra_select_namess                                 r   r$   z'PolymorphicQuerySet._get_real_instances=  s   8 
 't,)$/ **99  +22==dggF2@@JJ5 A 

" 	 (<'I'IJJ4 (J (

" 	% ((;< 	,NA{//3FF!!+.&1&I&I&K#)4)X)X)Z&)1+/KK %%l3F&TU +?*I*I.+!km ( %%89@@V]A^_'(;<CCQJDXY%%d+-	,: ,<+A+A+C D	,')*=>GW.<<GGPWW it$v.L 15

0I0IL- ')#"??BO( F,L+U-)( (../DE-F0 +,

++A.3L/ O[!?JW-{:! !   ,11!4{G4/33D9& #ii4(@@B
 !44".z;"GK::))+/::+A+A+F+F+H D&{OD_dCD ::**-1ZZ-D-D-I-I-K F)&{4EF->EF !,
13,WD	,L ",1Aqa1
1 ::!!!$**"8"8"="="?@N) H9G6H ::""!%djj&=&=&B&B&D!E) P=O:P M & ~
 160@0@0G0K-%/55??@UV0 %$% 	 W.!> 2sH   %Q&;R=4S<S&!R:R$#R:$	R2	-R:1R2	2R:9R:c                     | j                   j                  r,dj                  d | j                         D              }d| dS t	        |   |i |S )N,
  c              3   2   K   | ]  }t        |        y wr   repr.0r(   s     r   	<genexpr>z/PolymorphicQuerySet.__repr__.<locals>.<genexpr>  s     !>a$q'!>   [  ])rc   "polymorphic_query_multiline_outputjoinallr   __repr__)r   rA   rB   resultr   s       r   r   zPolymorphicQuerySet.__repr__  sM    ::88\\!>488:!>>Fxr?"7#T4V44r   c                       e Zd Zd Zy)!PolymorphicQuerySet._p_list_classc                 >    dj                  d | D              }d| dS )Nr   c              3   2   K   | ]  }t        |        y wr   r   r   s     r   r   z=PolymorphicQuerySet._p_list_class.__repr__.<locals>.<genexpr>  s     !8a$q'!8r   r   r   )r   )r   rA   rB   r   s       r   r   z*PolymorphicQuerySet._p_list_class.__repr__  s$    \\!84!88Fxr?"r   N)r*   r+   r,   r   r   r   r   _p_list_classr     s    	#r   r   c                     	 || }| j                  |      }| j                  j                  s|S t        j	                  |      }|S )z
        Cast a list of objects to their actual classes.

        This does roughly the same as::

            return [ o.get_real_instance() for o in base_result_objects ]

        but more efficiently.

        :rtype: PolymorphicQuerySet
        )r$   rc   r   r;   r   )r   r%   olistclists       r   get_real_instancesz&PolymorphicQuerySet.get_real_instances  sL     	k&"&(()<=zz<<L#11%8r   )NFr   )r*   r+   r,   r-   r1   rD   rL   queryset_onlyclassmethodrQ   rW   rY   r^   re   rk   ro   rw   rp   rx   r   r   r   r   r$   r   rO   r   r   r.   r/   s   @r   r;   r;   \   s    
:  $JZ(JX-
1

S.XC&0d1IiV5# #
r   r;   )r-   rE   collectionsr   "django.contrib.contenttypes.modelsr   django.core.exceptionsr   django.db.modelsr   django.db.models.queryr   r   r	   query_translater   r   r   r   r    r   r9   r;   r   r   r   <module>r      sS     # : 4 - = =  ,/ (,} ,^(k( kr   