
    h+                         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	m
Z
 ddlmZ ddlmZ dd	lmZmZ dd
lmZ efdZefdZefdZefdZd Zd Zd Zd ZdefdZd Zy)z'
PolymorphicQuerySet support functions
    N)deque)apps)ContentType)FieldDoesNotExist
FieldError)models)Q)ForeignObjectRelRelatedField)DEFAULT_DB_ALIASc                    g }|j                         j                         D ]b  \  }}t        | |||      }t        |t              r||= |d   ||d   <   4t        |t
        j                        sO||= |j                  |       d |S )a8  
    Translate the keyword argument list for PolymorphicQuerySet.filter()

    Any kwargs with special polymorphic functionality are replaced in the kwargs
    dict with their vanilla django equivalents.

    For some kwargs a direct replacement is not possible, as a Q object is needed
    instead to implement the required functionality. In these cases the kwarg is
    deleted from the kwargs dict and a Q object is added to the return list.

    Modifies: kwargs dict
    Returns: a list of non-keyword-arguments (Q objects) to be added to the filter() query.
    using   r   )copyitems(_translate_polymorphic_filter_definition
isinstancetupler   r	   append)queryset_modelkwargsr   additional_args
field_pathvalnew_exprs          K/home/dcms/DCMS/lib/python3.12/site-packages/polymorphic/query_translate.py2translate_polymorphic_filter_definitions_in_kwargsr      s      O!;;=..0 -
C;J5
 h&z""*1+F8A;&((+z"""8,-     c                 \    fdt        |t        j                        r	 | |       |S )Nc                     t        t        |j                              D ]W  }|j                  |   }t        |t        t
        f      r'|\  }}t        | ||      }|s?||j                  |<   O | |       Y y)z#process all children of this Q noder   N)rangelenchildrenr   r   listr   )	my_modelnodeichildkeyr   r   tree_node_correct_field_specsr   s	          r   r+   zEtranslate_polymorphic_Q_object.<locals>.tree_node_correct_field_specs<   sw    s4==)* 	?AMM!$E%%/ SCc3e '/DMM!$ .h>	?r   )r   r   r	   )r   potential_q_objectr   r+   s     `@r   translate_polymorphic_Q_objectr-   ;   s*    ?" $fhh/%n6HIr   c           	      j    |D cg c]#  }t        | t        j                  |      |      % c}S c c}w )aE  
    Translate the non-keyword argument list for PolymorphicQuerySet.filter()

    In the args list, we return all kwargs to Q-objects that contain special
    polymorphic functionality with their vanilla django equivalents.
    We traverse the Q object tree for this (which is simple).


    Returns: modified Q objects
    r   )r-   r   deepcopy)r   argsr   qs       r   0translate_polymorphic_filter_definitions_in_argsr2   S   s6     `dZ[&~t}}Q7GuU  s   (0c                 v    |dk(  rt        ||      S |dk(  rt        |d|      S d|vryt        | |      }||fS )a  
    Translate a keyword argument (field_path=field_val), as used for
    PolymorphicQuerySet.filter()-like functions (and Q objects).

    A kwarg with special polymorphic functionality is translated into
    its vanilla django equivalent, which is returned, either as tuple
    (field_path, field_val) or as Q object.

    Returns: kwarg tuple or Q object or None (if no change is required)
    instance_ofr   not_instance_ofT)r5   r   ___N)create_instanceof_q translate_polymorphic_field_path)r   r   	field_valr   newpaths        r   r   r   c   sU      ]""9E::	(	("9d%PP	j	  /~zJGYr   c                 
   t        |t              st        d|       |j                  d      \  }}}|s|S |sJ d| d       d}|d   dk(  rd}|j	                  d      }d	|v r~|j                  d	      \  }}}t        j                  ||      }|sJ d
|j                   d| d       t        ||       sd|j                  z   dz   | j                  z   dz   }t        |      	 | j                  j                  |      }	t        |	t        t        f      r|S 	 t        |       }
|
j!                  |d      }|sJ d
| d| j                   d       t#        | |      }|rd}nd}||z  }|r|d	z  }||z  }|S # t        $ r Y hw xY w)am  
    Translate a field path from a keyword argument, as used for
    PolymorphicQuerySet.filter()-like functions (and Q objects).
    Supports leading '-' (for order_by args).

    E.g.: if queryset_model is ModelA, then "ModelC___field3" is translated
    into modela__modelb__modelc__field3.
    Returns: translated path (unchanged, if no translation needed)
    zExpected field name as string: r6   zPolymorphicModel: z: bad field specificationFr   -T__zPolymorphicModel: model z	 (in app z) not found!z*PolymorphicModel: queryset filter error: "z" is not derived from ""Nz not found (not a subclass of z)! )r   str
ValueError	partitionlstripr   	get_model__name__
issubclassAssertionError_meta	get_fieldr   r
   r   _get_all_sub_modelsget_create_base_path)r   r   	classnameseppure_field_pathnegatedappnamemodelefield	submodelsbasepathr:   s                r   r8   r8      s    j#&::,GHH&0&:&:5&A#IsOP*:,6OPP9G|s$$S)	y"+"5"5d";iw	2_00@	'R^__u%0<..!+, !))* 	  !##		"((229=E%,0@!AB "! C (7	i. 	
&yk1OP^PgPgOhhjk	
u !7HxG4GN+ ! 		s   %2E6 6	FFc                 2   i }t        | g      }|r|j                         }t        |t        j                        r|t        j                  k7  r|j
                  |v r|||j
                     k7  rv|j                  j                   d|j
                   }||j
                     j                  j                   d||j
                     j
                   }t        d| d| d      |||j
                  <   |j                  |j                                |r|S )z:#Collect all sub-models, this should be optimized (cached).z1PolymorphicModel: model name alone is ambiguous: z and zH match!
In this case, please use the syntax: applabel__ModelName___field)r   popleftrF   r   ModelrE   rH   	app_labelr   extend__subclasses__)
base_modelresultqueuerR   name1name2s         r   rJ   rJ      s   F:,E
eV\\*u/D~~'EVENN5K,K ;;0015>>2BCenn-33==>au~~@V@_@_?`a  !GweTYSZ [W X 
 &+F5>>"U))+, " Mr   c                     |j                   D ]m  }|| k(  rt        |      c S t        | |      }|s$|j                  j                  s|j                  j
                  rt        |      c S | dt        |       c S  y)Nr=   r?   )	__bases___get_query_related_namerL   rH   abstractproxy)	baseclassmyclassbpaths       r   rL   rL      s{      	E	>*733 A.ww177==.w77r"9'"B!CDD	E r   c                     | j                   j                  D ]E  }t        |t        j                        s|j
                  j                  s5|j                         c S  | j                  j                         S )N)
rH   local_fieldsr   r   OneToOneFieldremote_fieldparent_linkrelated_query_namerE   lower)ri   fs     r   re   re      s]    ]]'' *a--.1>>3M3M''))* !!##r   Fc                     | syt        | t        t        f      s!ddlm} t        | |      r| g} nt        d      t        | |      }t        t        |            }|r| }|S )a  
    Helper function for instance_of / not_instance_of
    Creates and returns a Q object that filters for the models in modellist,
    including all subclasses of these models (as we want to do the same
    as pythons isinstance() ).
    .
    We recursively collect all __subclasses__(), create a Q filter for each,
    and or-combine these Q objects. This could be done much more
    efficiently however (regarding the resulting sql), should an optimization
    be needed.
    Nr   )PolymorphicModelzdPolymorphicModel: instance_of expects a list of (polymorphic) models or a single (polymorphic) model)polymorphic_ctype__in)
r   r%   r   r   ru   rF   	TypeError_get_mro_content_type_idsr	   sorted)	modellistr5   r   ru   contenttype_idsr1   s         r   r7   r7      sk     i$/,i!12"I9 
 0	5AO	 78ABHr   c                    t               }| D ]{  }t        j                  j                  |      j	                  |d      }|j                  |j                         |j                         }|sa|j                  t        ||             } |S )NF)for_concrete_model)
setr   objects
db_managerget_for_modeladdpkr]   updaterx   )r   r   r{   rR   ct
subclassess         r   rx   rx      s    eO Q  ++E2@@[`@aBEE"))+
""#<Z#OPQ r   )__doc__r   collectionsr   django.appsr   "django.contrib.contenttypes.modelsr   django.core.exceptionsr   r   	django.dbr   django.db.modelsr	   django.db.models.fields.relatedr
   r   django.db.utilsr   r   r-   r2   r   r8   rJ   rL   re   r7   rx    r   r   <module>r      s~       : @   J , #3D N^ 0 Rb " 2B :IX2 $ 49@P Br   