3
v^/                 @   s   d Z ddlZddlZddlZddlmZ ddlmZ ddlm	Z	 eddZ
G dd	 d	eZd
d ZG dd dZG dd de	jZG dd dZG dd dZdddZdd Zdd ZG dd dZdS )z
Various data structures used in query construction.

Factored out from django.db.models.query to avoid making the main module very
large and/or so that they can be used by other modules without getting into
circular import difficulties.
    N)
namedtuple)
LOOKUP_SEP)treePathInfozGfrom_opts to_opts target_fields join_field m2m direct filtered_relationc               @   s   e Zd ZdZdS )InvalidQueryz?The query passed to raw() isn't a safe query to use with raw().N)__name__
__module____qualname____doc__ r   r   @/usr/lib/python3.6/site-packages/django/db/models/query_utils.pyr      s   r   c             c   s*   | V  x| j  D ]}t|E d H  qW d S )N)__subclasses__
subclasses)clssubclassr   r   r   r      s    r   c               @   s&   e Zd ZdZdZdd ZdddZdS )	QueryWrapperz
    A type that indicates the contents are an SQL fragment and the associate
    parameters. Can be used to pass opaque data to a where-clause, for example.
    Fc             C   s   |t |f| _d S )N)listdata)selfsqlparamsr   r   r   __init__(   s    zQueryWrapper.__init__Nc             C   s   | j S )N)r   )r   compiler
connectionr   r   r   as_sql+   s    zQueryWrapper.as_sql)NN)r   r   r	   r
   contains_aggregater   r   r   r   r   r   r   !   s   r   c                   sj   e Zd ZdZdZdZeZdZddd fdd	
Zd
d Z	dd Z
dd Zdd ZdddZdd Z  ZS )Qze
    Encapsulate filters as objects that can then be combined logically (using
    `&` and `|`).
    ANDORTNF)
_connector_negatedc               s"   t  j|t|j ||d d S )N)children	connectornegated)superr   sorteditems)r   r   r    argskwargs)	__class__r   r   r   :   s    z
Q.__init__c             C   sZ   t |tst||s tj| S | s.tj|S t|  }||_|j| | |j|| |S )N)
isinstancer   	TypeErrorcopydeepcopytyper"   add)r   otherconnobjr   r   r   _combine=   s    



z
Q._combinec             C   s   | j || jS )N)r3   r   )r   r0   r   r   r   __or__N   s    zQ.__or__c             C   s   | j || jS )N)r3   r   )r   r0   r   r   r   __and__Q   s    z	Q.__and__c             C   s$   t |  }|j| | j |j  |S )N)r.   r/   r   Znegate)r   r2   r   r   r   
__invert__T   s    
zQ.__invert__c             C   s&   |j | ||ddd\}}|j| |S )NF)allow_joinsZ
split_subqZcheck_filterable)Z_add_qZpromote_joins)r   queryr7   reuse	summarizefor_saveZclauseZjoinsr   r   r   resolve_expressionZ   s
    
zQ.resolve_expressionc             C   s   d| j j| j jf }|jdr*|jdd}f i  }}t| jdkrpt| jd t rp| jd }|d |d i}n t	| j}| j
| jkrd| j
i}| jrd|d< |||fS )	Nz%s.%szdjango.db.models.query_utilszdjango.db.models   r   r   Tr    )r)   r   r   
startswithreplacelenr!   r*   r   tupler"   defaultr#   )r   pathr'   r(   childr   r   r   deconstructd   s    

 


zQ.deconstruct)NTNFF)r   r   r	   r
   r   r   rB   conditionalr   r3   r4   r5   r6   r<   rE   __classcell__r   r   )r)   r   r   /   s   

r   c               @   s*   e Zd ZdZdd Zd	ddZdd ZdS )
DeferredAttributez
    A wrapper for a deferred-loading field. When the value is read from this
    object the first time, the query is executed.
    c             C   s
   || _ d S )N)field)r   rI   r   r   r   r   z   s    zDeferredAttribute.__init__Nc             C   sd   |dkr| S |j }| jj}|j|| | kr\| j|}|dkrT|j|gd t||}|||< || S )zx
        Retrieve and caches the value from the datastore on the first lookup.
        Return the cached value.
        N)fields)__dict__rI   attnameget_check_parent_chainZrefresh_from_dbgetattr)r   instancer   r   
field_namevalr   r   r   __get__}   s    

zDeferredAttribute.__get__c             C   s6   |j }|j| jj}| jjr2| j|kr2t||jS dS )z
        Check if the field value can be fetched from a parent field already
        loaded in the instance. This can be done if the to-be fetched
        field is a primary key field.
        N)_metaZget_ancestor_linkrI   modelprimary_keyrO   rL   )r   rP   optsZ
link_fieldr   r   r   rN      s
    z%DeferredAttribute._check_parent_chain)N)r   r   r	   r
   r   rS   rN   r   r   r   r   rH   u   s   
rH   c               @   st   e Zd Zedd Zeejdddd Zdd Zd	d
 Z	e
dd Zedd ZedddZedddZdS )RegisterLookupMixinc             C   s   | j  j|d S )N)get_lookupsrM   )r   lookup_namer   r   r   _get_lookup   s    zRegisterLookupMixin._get_lookupN)maxsizec             C   s   dd t j| D }| j|S )Nc             S   s   g | ]}|j jd i qS )class_lookups)rK   rM   ).0parentr   r   r   
<listcomp>   s    z3RegisterLookupMixin.get_lookups.<locals>.<listcomp>)inspectgetmromerge_dicts)r   r]   r   r   r   rY      s    zRegisterLookupMixin.get_lookupsc             C   sP   ddl m} | j|}|d kr4t| dr4| jj|S |d k	rLt|| rLd S |S )Nr   )Lookupoutput_field)django.db.models.lookupsrd   r[   hasattrre   
get_lookup
issubclass)r   rZ   rd   foundr   r   r   rh      s    
zRegisterLookupMixin.get_lookupc             C   sP   ddl m} | j|}|d kr4t| dr4| jj|S |d k	rLt|| rLd S |S )Nr   )	Transformre   )rf   rk   r[   rg   re   get_transformri   )r   rZ   rk   rj   r   r   r   rl      s    
z!RegisterLookupMixin.get_transformc             C   s$   i }xt | D ]}|j| qW |S )z
        Merge dicts in reverse to preference the order of the original list. e.g.,
        merge_dicts([a, b]) will preference the keys in 'a' over those in 'b'.
        )reversedupdate)dictsZmergeddr   r   r   rc      s    zRegisterLookupMixin.merge_dictsc             C   s    xt | D ]}|jj  q
W d S )N)r   rY   cache_clear)r   r   r   r   r   _clear_cached_lookups   s    z)RegisterLookupMixin._clear_cached_lookupsc             C   s4   |d kr|j }d| jkri | _|| j|< | j  |S )Nr]   )rZ   rK   r]   rr   )r   lookuprZ   r   r   r   register_lookup   s    

z#RegisterLookupMixin.register_lookupc             C   s   |dkr|j }| j|= dS )zn
        Remove given lookup from cls lookups. For use in tests only as it's
        not thread-safe.
        N)rZ   r]   )r   rs   rZ   r   r   r   _unregister_lookup   s    z&RegisterLookupMixin._unregister_lookup)N)N)r   r   r	   classmethodr[   	functools	lru_cacherY   rh   rl   staticmethodrc   rr   rt   ru   r   r   r   r   rX      s   			rX   Fc             C   s   | j s
dS | j jr| rdS |rH|r4| j |kr4dS | rH| j|krHdS | rX| jrXdS |r| j|kr|r| j|krtd| jjj	| jf dS )au  
    Return True if this field should be used to descend deeper for
    select_related() purposes. Used by both the query construction code
    (sql.query.fill_related_selections()) and the model instance creation code
    (query.get_klass_info()).

    Arguments:
     * field - the field to be checked
     * restricted - a boolean field, indicating if the field list has been
       manually restricted using a requested clause)
     * requested - The select_related() dictionary.
     * load_fields - the set of fields to be loaded on this model
     * reverse - boolean, True if we are checking a reverse select related
    FzXField %s.%s cannot be both deferred and traversed using select_related at the same time.T)
remote_fieldparent_linkZrelated_query_namenamenullrL   r   rU   rT   object_name)rI   Z
restrictedZ	requestedZload_fieldsreverser   r   r   select_related_descend   s"    
r   c             C   sZ   xPt dt| d D ]:}tj| d| }||kr|| r|| | |d fS qW df fS )z
    Check if the lookup_parts contains references to the given annotations set.
    Because the LOOKUP_SEP is contained in the default annotation names, check
    each prefix of the lookup_parts for a match.
    r=   r   NF)ranger@   r   join)Zlookup_partsannotationsnZlevel_n_lookupr   r   r   refs_expression  s
    r   c                s,    fdd}||p*t |ddo*||jjS )z
    Check that self.model is compatible with target_opts. Compatibility
    is OK if:
      1) model and opts match (where proxy inheritance is removed)
      2) model is parent of opts' model or the other way around
    c                s*    j j| jkp(| j j j kp( | j kS )N)rT   concrete_modelget_parent_list)rW   )rU   r   r   check  s    z-check_rel_lookup_compatibility.<locals>.checkrV   F)rO   rU   rT   )rU   Ztarget_optsrI   r   r   )rU   r   check_rel_lookup_compatibility  s    r   c               @   s@   e Zd ZdZe dddZdd Zdd Zd	d
 Zdd Z	dS )FilteredRelationz7Specify custom filtering in the ON clause of SQL joins.)	conditionc            C   s:   |st d|| _d | _t|ts*t d|| _g | _d S )Nzrelation_name cannot be empty.z*condition argument must be a Q() instance.)
ValueErrorrelation_namealiasr*   r   r   rC   )r   r   r   r   r   r   r   0  s    
zFilteredRelation.__init__c             C   s0   t || jo.| j|jko.| j|jko.| j|jkS )N)r*   r)   r   r   r   )r   r0   r   r   r   __eq__:  s    zFilteredRelation.__eq__c             C   s,   t | j| jd}| j|_| jd d  |_|S )N)r   )r   r   r   r   rC   )r   cloner   r   r   r   B  s    zFilteredRelation.clonec             O   s   t ddS )zz
        QuerySet.annotate() only accepts expression-like arguments
        (with a resolve_expression() method).
        z0FilteredRelation.resolve_expression() is unused.N)NotImplementedError)r   r'   r(   r   r   r   r<   H  s    z#FilteredRelation.resolve_expressionc             C   s&   |j }|j| jt| jd}|j|S )N)r9   )r8   Zbuild_filtered_relation_qr   setrC   compile)r   r   r   r8   wherer   r   r   r   O  s    zFilteredRelation.as_sqlN)
r   r   r	   r
   r   r   r   r   r<   r   r   r   r   r   r   -  s   
r   )F)r
   r,   rw   ra   collectionsr   django.db.models.constantsr   django.utilsr   r   	Exceptionr   r   r   Noder   rH   rX   r   r   r   r   r   r   r   r   <module>   s"   
F(C
$