o
    ӷ6ie                     @   s`  d dl Z d dlZd dlZd dlZd dlmZm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 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 d dlmZ d dl m!Z! dZ"G dd dZ#G dd de$Z%e%dZ&G dd dZ'G dd deZ(dd Z)G dd de
j*e(dZ+dd Z,z
d dl-Z-e,e+_,W dS  e.y   Y dS w )     N)reducewraps)settings)models)truncate_name)	ModelBaseQ)DeferredAttribute)gettext)cached_field_value)TreeForeignKeyTreeManyToManyFieldTreeOneToOneField)TreeManager)
node_moved)_get_tree_model)	MPTTModelMPTTModelBaseMPTTOptionsr   r   r   r   c                   @   s&   e Zd ZdddZdd Zdd ZdS )	_classpropertyNc                 C   s   || _ || _d S N)fgetfset)selfgettersetter r   P/var/www/hoanhtaovolam_webdjango/env/lib/python3.10/site-packages/mptt/models.py__init__"   s   
z_classproperty.__init__c                 C   s
   |  |S r   )r   )r   clsownerr   r   r   __get__&   s   
z_classproperty.__get__c                 C   s   | j std|  || d S )NzThis classproperty is read only)r   AttributeError)r   r    r!   valuer   r   r   __set__)   s   z_classproperty.__set__r   )__name__
__module____qualname__r   r"   r%   r   r   r   r   r   !   s    
r   c                       s   e Zd Zd fdd	Z  ZS )classpropertytyper   Nc                    s6   |d u ri }t  |d|d|d|dS )Nr"   r%   
__delete____doc__)superr   get)r   namebasesmembers	__class__r   r   r   0   s   zclasspropertytype.__init__)r   N)r&   r'   r(   r   __classcell__r   r   r1   r   r)   /   s    r)   classpropertyc                   @   sb   e Zd ZdZg ZdZdZdZdZdZ	ddd	Z
d
d Zdd Zdd Zdd Zdd Zdd ZdS )r   z
    Options class for MPTT models. Use this as an inner class called ``MPTTMeta``::

        class MyModel(MPTTModel):
            class MPTTMeta:
                order_insertion_by = ['name']
                parent_attr = 'myparent'
    lftrghttree_idlevelparentNc                 K   s   |r	t |j ng }|t |  ddd |D v r!td|D ]\}}|d d dkr0q#t| || q#t| jtrD| jg| _d S t| jt	rRt | j| _d S | jd u r\g | _d S d S )Ntree_manager_attrc                 S   s   g | ]}|d  qS )r   r   ).0optr   r   r   
<listcomp>T   s    z(MPTTOptions.__init__.<locals>.<listcomp>zu`tree_manager_attr` has been removed; you should instantiate a TreeManager as a normal manager on your model instead.   __)
list__dict__itemsextend
ValueErrorsetattr
isinstanceorder_insertion_bystrtuple)r   optskwargskeyr$   r   r   r   r   O   s"   

zMPTTOptions.__init__c                 C   s   dd | j  D S )Nc                 s   s(    | ]\}}|d  dkr||fV  qdS )r   _Nr   )r;   kvr   r   r   	<genexpr>h   s   & z'MPTTOptions.__iter__.<locals>.<genexpr>)rA   rB   r   r   r   r   __iter__g   s   zMPTTOptions.__iter__c                 C   s   |j |}||S )z
        Gets the value of the given fieldname for the instance.
        This is not the same as getattr().
        This function will return IDs for foreignkeys etc, rather than doing
        a database query.
        )_meta	get_fieldvalue_from_object)r   instance
field_namefieldr   r   r   get_raw_field_valuek   s   
zMPTTOptions.get_raw_field_valuec                 C   s   |j |}t||j| dS )z
        Sets the value of the given fieldname for the instance.
        This is not the same as setattr().
        This function requires an ID for a foreignkey (etc) rather than an instance.
        N)rS   rT   rE   attname)r   rV   rW   r$   rX   r   r   r   set_raw_field_valueu   s   zMPTTOptions.set_raw_field_valuec                 C   s   i |_ | jh}| jr!| jD ]}|d dkr|dd }|| q| }|D ]$}|rB|j|}|j|v rB|j|jvrBt	|j |< q'| 
|||j |< q'dS )a)  
        Caches (in an instance._mptt_cached_fields dict) the original values of:
         - parent pk
         - fields specified in order_insertion_by

        These are used in save() to determine if the relevant fields have changed,
        so that the MPTT fields need to be updated.
        r   -   N)_mptt_cached_fieldsparent_attrrG   addget_deferred_fieldsrS   rT   rZ   rA   r
   rY   )r   rV   field_namesfdeferred_fieldsrW   rX   r   r   r   update_mptt_cached_fields~   s&   	


z%MPTTOptions.update_mptt_cached_fieldsc                 C   s   g }g }|j }|j }tj}tj}|D ]R}	|	d dkr#|	dd }	d}
nd}
t||	}|du r:|j|	}||d}|du rD|
dk}d}
tdi |	|
 |i}|t	|d	d
 |D |g  ||	|f qt	||S )a  
        Creates a filter which matches suitable right siblings for ``node``,
        where insertion should maintain ordering according to the list of
        fields in ``order_insertion_by``.

        For example, given an ``order_insertion_by`` of
        ``['field1', 'field2', 'field3']``, the resulting filter should
        correspond to the following SQL::

           field1 > %s
           OR (field1 = %s AND field2 > %s)
           OR (field1 = %s AND field2 = %s AND field3 > %s)

        r   r\   r]   N__lt__gtT__isnullc                 S   s"   g | ]\}}t d i ||iqS )r   r   )r;   rc   rO   r   r   r   r=      s   " z8MPTTOptions.insertion_target_filters.<locals>.<listcomp>r   )
appendoperatorand_or_getattrrS   rT   pre_saver	   r   )r   rV   rG   fieldsfiltersfields__appendfilters__appendrk   rl   rW   filter_suffixr$   rX   qr   r   r   insertion_target_filters   s,   

z$MPTTOptions.insertion_target_filtersc                 C   s   d}| j ru|du s| dkru|j}|j dd }| ||}|r4|tdi |j|i@ }||j n|tdi |jdi@ }||j |j	j
|jj|j| }|jr_|j|jd}z|dd d }W |S  tyt   Y |S w |S )aV  
        Attempts to retrieve a suitable right sibling for ``node``
        underneath ``parent`` (which may be ``None`` in the case of root
        nodes) so that ordering by the fields specified by the node's class'
        ``order_insertion_by`` option is maintained.

        Returns ``None`` if no suitable sibling can be found.
        Nr   pkr]   r   )rG   get_descendant_count
_mptt_metaru   r	   r_   ri   	left_attrtree_id_attrr2   _tree_manager
db_manager_statedbfilterorder_byrw   exclude
IndexError)r   noder9   right_siblingrJ   r   rp   querysetr   r   r   get_ordered_insertion_target   s4   	z(MPTTOptions.get_ordered_insertion_targetr   )r&   r'   r(   r+   rG   rz   
right_attrr{   
level_attrr_   r   rR   rY   r[   re   ru   r   r   r   r   r   r   >   s    	

	#-r   c                       s,   e Zd ZdZ fddZedd Z  ZS )r   z#
    Metaclass for MPTT models
    c                    sJ  |dkr|i krt  | |||S d}zt W n ty"   d}Y nw |dd}|s2G dd d}tt|}|D ]}t|drX|jD ]\}}	|dkrMqD||vrWt	|||	 qDq:t
||d< t  j}
|
| |||}| |}d|_|rx|g}n	d	d
 | D }|D ]}|jjs|jjs|jj|u r||_ nq||ju rt |_|S )z
        Create subclasses of MPTTModel. This:
         - adds the MPTT fields to the class
         - adds a TreeManager to the model
        NewBaseFTMPTTMetaNc                   @   s   e Zd ZdS )z'MPTTModelBase.__new__.<locals>.MPTTMetaN)r&   r'   r(   r   r   r   r   r     s    ry   r:   c                 S   s   g | ]	}t |tr|qS r   )
issubclassr   )r;   baser   r   r   r=   '  s    z)MPTTModelBase.__new__.<locals>.<listcomp>)r,   __new__r   	NameErrorpop	frozensetdirhasattrry   rE   r   register_mptt_tracking_basemrorS   abstractproxyr|   
tree_model	threadinglocal_threadlocal)meta
class_namer/   
class_dictis_MPTTModelr   initial_optionsr   r.   r$   	super_newr    r1   r   r   r      sP   



zMPTTModelBase.__new__c                 K   s^  t |tjsttdt|dstdi ||_t|j	dd}zt
 W n
 ty.   Y |S w t |t
s[t|j}tt|d ddD ]}t t
|| rO||= qC|dt
 t||_t||u }|rt }| D ]}t|dr}|d	d
 |j	jD  qj|j}	|	jf}
|	j|	j|	j|	jf}|D ]}||vrtj||
v dd}||| q|jj|jjf}|j	jD ]}t|j|kr n&q|j	jtj |t!|j	j" d|j	j# d|jj d|jj dtj j$d |s-d}|j%rt&|j%t'r|j%}n|j	j(D ]}t&|t'r|j)|u r|} nq|r|j)|ur|*|}n|du r$t' }||d ||_+|S )z
        For the weird cases when you need to add tree-ness to an *existing*
        class. For other cases you should subclass MPTTModel instead of calling this.
        z0register() expects a Django model class argumentry   r   Fr]   r   rS   c                 S      g | ]}|j qS r   )r.   )r;   rc   r   r   r   r=   e      z*MPTTModelBase.register.<locals>.<listcomp>)db_indexeditablerM   _idx)ro   r.   Nr|   r   ),r   r   ModelrD   rM   r   r   ry   rm   rS   r   r   r@   	__bases__rangeleninsertrI   r   setr   updatelocal_fieldsr{   rz   r   r   PositiveIntegerFieldcontribute_to_classindexesro   ri   Indexr   	app_label
model_namemax_name_length_default_managerrF   r   managersmodel_copy_to_modelr|   )r   r    rK   r   r/   iis_cls_tree_modelexisting_field_namesr   	mptt_metaindexed_attrsrb   rW   rX   index_fieldsindextree_managercls_managerr   r   r   r   6  s   
X




zMPTTModelBase.register)r&   r'   r(   r+   r   classmethodr   r3   r   r   r1   r   r      s
    8r   c                    s   t   fdd}|S )Nc                    s6   | j jrtd j| jjd  | g|R i |S )Nz7Cannot call %(function)s on unsaved %(class)s instances)functionclass)r~   addingrD   r&   r2   r   argsrK   funcr   r   _fn  s   zraise_if_unsaved.<locals>._fn)r   )r   r   r   r   r   raise_if_unsaved  s   r   c                       s  e Zd ZdZG dd dZe Z fddZdd Ze	dd	 Z
ed
d Ze	dd Zedd Zedd Zedd Zedd ZedHddZedd Zedd ZedIddZdd  ZedId!d"Zed#d$ Zed%d& Zed'd( ZedId)d*Zd+d, Z	-			.dJd/d0Zd1d2 Zd3d4 Z d5d6 Z!edId7d8Z"edId9d:Z#dKd;d<Z$dLd>d?Z%d@dA Z& fdBdCZ'd.e'_( fdDdEZ)d.e)_(dFdG Z*  Z+S )Mr   z%
    Base class for tree models.
    c                   @   s   e Zd ZdZdS )zMPTTModel.MetaTN)r&   r'   r(   r   r   r   r   r   Meta  s    r   c                    s4   t | dr	|   t j|i | | j|  d S )N_check_no_testing_generators)r   r   r,   r   ry   re   r   r1   r   r   r     s   
zMPTTModel.__init__c                 C   s   t | j|d }t | |S )N_attr)rm   ry   )r   	fieldnametranslated_fieldnamer   r   r   
_mpttfield  s   
zMPTTModel._mpttfieldc                 C   s   | j sdS t| j jddS )NTmptt_updates_enabled)r   rm   r   r    r   r   r   _mptt_updates_enabled  s
   
zMPTTModel._mptt_updates_enabledc                 C   s   | | j u s	J d|| j_d S )Nz=Can't enable or disable mptt updates on a non-tracking class.)r   r   r   )r    r$   r   r   r   _set_mptt_updates_enabled  s   z#MPTTModel._set_mptt_updates_enabledc                 C   s*   | j sdS t| jdsd | j_| jjd uS )NFmptt_delayed_tree_changes)r   r   r   r   r   r   r   r   _mptt_is_tracking  s
   zMPTTModel._mptt_is_trackingc                 C   s.   | | j u s	J d| jrJ dt | j_d S )N:Can't start or stop mptt tracking on a non-tracking class.z!mptt tracking is already started.)r   r   r   r   r   r   r   r   r   _mptt_start_tracking  s
   zMPTTModel._mptt_start_trackingc                 C   s4   | | j u s	J d| jsJ d| jj}d | j_|S )Nr   zmptt tracking isn't started.)r   r   r   r   )r    resultsr   r   r   _mptt_stop_tracking  s   zMPTTModel._mptt_stop_trackingc                 C   s   | j sd S | jj| d S r   )r   r   r   r`   )r    r7   r   r   r   _mptt_track_tree_modified  s   z#MPTTModel._mptt_track_tree_modifiedc                    s`   | j sd S | jj} r|sd S  dk r t    }||  fdd|D }|| j_d S )Nr   c                    s    h | ]}|kr|  n|qS r   r   )r;   tnum_insertedr7   r   r   	<setcomp>  s     z8MPTTModel._mptt_track_tree_insertions.<locals>.<setcomp>)r   r   r   r   difference_update)r    r7   r   changesdeletednew_changesr   r   r   _mptt_track_tree_insertions  s   
z%MPTTModel._mptt_track_tree_insertionsFc           
      C   s   | j }|  r|s| j S | jj| jd}n0|j}|r d| }t| |j}t| |j}|s6|d8 }|d7 }| jj	||| 
dd}||}t| drrg }| }	|sXt|	|j}	|	durk||	 t|	|j}	|	dus\|  ||_|S )a  
        Creates a ``QuerySet`` containing the ancestors of this model
        instance.

        This defaults to being in descending order (root ancestor first,
        immediate parent last); passing ``True`` for the ``ascending``
        argument will reverse the ordering (immediate parent first, root
        ancestor last).

        If ``include_self`` is ``True``, the ``QuerySet`` will also
        include this model instance.
        rv   r\   r]   r7   )	left__lte
right__gter7   _mptt_use_cached_ancestorsN)ry   is_root_noder|   noner   rw   rz   rm   r   _mptt_filterr   r   r   r_   ri   reverse_result_cache)
r   	ascendinginclude_selfrJ   qsr   leftright	ancestorspr   r   r   get_ancestors	  s>   



zMPTTModel.get_ancestorsc                 C   s   | j }t| |j}t| |j}tdi d|j |d|j ||j| di}tdi d|j |d|j ||j| di}| j||B S )z
        Returns a ``QuerySet`` containing the ancestors, the model itself
        and the descendants, in tree order.
        z%s__ltez%s__gter7   Nr   )	ry   rm   rz   r   r	   r{   r   r|   r   )r   rJ   r   r   r   descendantsr   r   r   
get_familyD  s    



zMPTTModel.get_familyc                 C   sP   t | dr| jjdd | jD d}| j|_|S |  r!| j S | jj| dS )a   
        Returns a ``QuerySet`` containing the immediate children of this
        model instance, in tree order.

        The benefit of using this method over the reverse relation
        provided by the ORM to the instance's children is that a
        database query can be avoided in the case where the instance is
        a leaf node (it has no children).

        If called from a template where the tree has been walked by the
        ``cache_tree_children`` filter, no database query is required.
        _cached_childrenc                 S   r   r   rv   )r;   nr   r   r   r=   p  r   z*MPTTModel.get_children.<locals>.<listcomp>)pk__inr9   )r   r|   r   r   r   is_leaf_noder   r   )r   r   r   r   r   get_childrena  s   

zMPTTModel.get_childrenc                 C   sp   |   r|s| j S | jj| jdS | j}t| |j}t| |j}|s,|d7 }|d8 }| jj	| 
d||dS )z
        Creates a ``QuerySet`` containing descendants of this model
        instance, in tree order.

        If ``include_self`` is ``True``, the ``QuerySet`` will also
        include this model instance.
        rv   r]   r7   )r7   	left__gter   )r   r|   r   r   rw   ry   rm   rz   r   r   r   )r   r   rJ   r   r   r   r   r   get_descendantsy  s   	
zMPTTModel.get_descendantsc                 C   s.   |  ddu r	dS |  d|  d d d S )zL
        Returns the number of descendants this model instance has.
        r   Nr   r   r]   r>   )r   rQ   r   r   r   rx     s   zMPTTModel.get_descendant_countc                 C   s*   | j |d}| jj|t| jjd dS )z
        Creates a ``QuerySet`` containing leafnodes of this model
        instance, in tree order.

        If ``include_self`` is ``True``, the ``QuerySet`` will also
        include this model instance (if it is a leaf node)
        )r   r]   )r   )r  r|   r   r   Fry   r   )r   r   r   r   r   r   get_leafnodes  s   	zMPTTModel.get_leafnodesc                 O   sv   | j j|i |}|  r| j j|d| dd}n| j j|t| | jjd | dd}|dd }|r9|d p:dS )	z
        Returns this model instance's next sibling in the tree, or
        ``None`` if it doesn't have a next sibling.
        Nr7   )r9   tree_id__gt_idr   )
parent__pkleft__gtr]   r   )r|   r   r   r   r   rm   ry   r_   )r   filter_argsfilter_kwargsr   siblingsr   r   r   get_next_sibling  s   zMPTTModel.get_next_siblingc                 O   s   | j }| jj|i |}|  r%| jj|d| dd}|d|j }n| jj|t| |j	d | dd}|d|j
 }|dd }|rK|d	 pLdS )
z
        Returns this model instance's previous sibling in the tree, or
        ``None`` if it doesn't have a previous sibling.
        Nr7   )r9   tree_id__ltr\   r  r   )r  	right__ltr]   r   )ry   r|   r   r   r   r   r   r{   rm   r_   r   )r   r	  r
  rJ   r   r  r   r   r   get_previous_sibling  s"   zMPTTModel.get_previous_siblingc                 C   s6   |   rt| | jjkr| S | jj| ddd S )zF
        Returns the root node of this model instance's tree.
        r7   N)r7   r9   )r   typer|   r   r   r   r-   rQ   r   r   r   get_root  s   zMPTTModel.get_rootc                 C   sN   |   r| jjdd}nt| | jjd }| jj|d}|s%|j| jd}|S )a  
        Creates a ``QuerySet`` containing siblings of this model
        instance. Root nodes are considered to be siblings of other root
        nodes.

        If ``include_self`` is ``True``, the ``QuerySet`` will also
        include this model instance.
        Nr   r  )r  rv   )r   r|   r   rm   ry   r_   r   rw   )r   r   r   	parent_idr   r   r   get_siblings  s   
zMPTTModel.get_siblingsc                 C   s   t | | jjS )zE
        Returns the level of this node (distance from root)
        )rm   ry   r   rQ   r   r   r   	get_level  s   zMPTTModel.get_levelfirst-childTc                 C   s   | j j| |||||d dS )zn
        Convenience method for calling ``TreeManager.insert_node`` with this
        model instance.
        allow_existing_pkrefresh_targetN)r|   insert_node)r   targetpositionsaver  r  r   r   r   	insert_at  s   
zMPTTModel.insert_atc                 C   
   |    S )zg
        Returns ``True`` if this model instance is a child node, ``False``
        otherwise.
        )r   rQ   r   r   r   is_child_node     
zMPTTModel.is_child_nodec                 C   r  )z{
        Returns ``True`` if this model instance is a leaf node (it has no
        children), ``False`` otherwise.
        )rx   rQ   r   r   r   r      r   zMPTTModel.is_leaf_nodec                 C   s   t | | jjd du S )zf
        Returns ``True`` if this model instance is a root node,
        ``False`` otherwise.
        r  N)rm   ry   r_   rQ   r   r   r   r   '  s   zMPTTModel.is_root_nodec                 C   sn   | j }|r|j| jkrdS t| |jt||jkrdS t| |j}t| |j}|t||jko6|t||jk S )z
        Returns ``True`` if this model is a descendant of the given node,
        ``False`` otherwise.
        If include_self is True, also returns True if the two nodes are the same node.
        TF)ry   rw   rm   r{   rz   r   )r   otherr   rJ   r   r   r   r   r   is_descendant_of.  s   zMPTTModel.is_descendant_ofc                 C   s   |r
|j | j kr
dS || S )z
        Returns ``True`` if this model is an ancestor of the given node,
        ``False`` otherwise.
        If include_self is True, also returns True if the two nodes are the same node.
        T)rw   r"  )r   r!  r   r   r   r   is_ancestor_ofD  s   
zMPTTModel.is_ancestor_ofc                 C   s   | j | || dS )a!  
        Convenience method for calling ``TreeManager.move_node`` with this
        model instance.

        NOTE: This is a low-level method; it does NOT respect ``MPTTMeta.order_insertion_by``.
        In most cases you should just move the node yourself by setting node.parent.
        N)r|   	move_node)r   r  r  r   r   r   move_toO  s   zMPTTModel.move_toNc                 C   sh   | j d u s| dd u rdS | j}|j jd u rdS t| ds1| jj}||}|j| j d	 | _
| j
S )Nr7   FT_mptt_savedrv   )rw   r   rS   remote_fieldr   r2   _base_managerusingr   existsr&  )r   r)  rJ   managerr   r   r   	_is_savedY  s   

zMPTTModel._is_savedc                 C   sd   ddl m} g }| jj| jj| jj| jjf}| jjD ]}|j	|vr/t
||s/|js/||j	 q|S )zFReturns the list of user defined (i.e. non-mptt internal) field names.r   )	AutoField)django.db.models.fieldsr-  ry   rz   r   r{   r   rS   concrete_fieldsr.   rF   primary_keyri   )r   r-  rb   internal_fieldsrX   r   r   r   _get_user_field_namesf  s    
zMPTTModel._get_user_field_namesc                    sh  | j j}| j j}| j}|sx|sx| ddu rot| |j}|rS|dd }t| |j| t| |j	|d  t| |j
|dd  t| |j|d | j|d nt| |jd t| |j	d t| |j
d t| |jd t j|i |S || |j}|dd	}	|d
d	}
d}|  }|	s|
s4| j|ddr4| j|j }|tu rd}n||k}|rt| jdkr| j D ]\}}|tu r||vrd	} n||| |krd	} nq|s|sd}| j | d nM|s9|s9|du r9| d}t| |j}|d}|dd }| j | t| |j| t| |j| t| |j	|d  t| |j
|dd  d}|st| |j}|| |j| z|| |}|dur|o~t| |jt||jkp~t| |jt||jk p~t| |j	t||j	k}|r| jj| |dd	d	d n;|du r| j }z|j| jd d|j d }| jj| |dd	d	d W n t!y   Y nw | jj| |dd	d |dur|rd| " d  }| j|| W || |j| n	|| |j| w t#j$| j | t| |jd n|| |j| |s3t|dkr'|d s&t%|}| & |d< t'|}n]|ds3| & |d< nPt| |jrCt| |j	rCnAt| |j}d}|sS|du r]|j(r]|| |}|r|| j)|ddd	d |r{d| " d  }| j|| n| j)|ddd zt j|i | W |dur| j*|d n|dur| j*|d w w d| _+|,|  dS )aO  
        If this is a new node, sets tree fields up before it is inserted
        into the database, making room in the tree structure as necessary,
        defaulting to making the new node the last child of its parent.

        It the node's left and right edge indicators already been set, we
        take this as indication that the node has already been set up for
        insertion, so its tree fields are left untouched.

        If this is an existing node and its parent has been changed,
        performs reparenting in the tree structure, defaulting to making the
        node the last child of its new parent.

        In either case, if the node's class has its ``order_insertion_by``
        tree option set, the node will be inserted or moved to the
        appropriate position to maintain ordering by the specified field.
        r   Nr]   r8   r7   r>   r   force_updateFforce_insertr)  )r)  T)r  r  rv   r\   r   z
last-child)r  )senderrV   r     update_fieldsr  )r  r  r   )-r2   r   r   ry   r   r   r_   rE   rz   r   r   r{   r|   '_post_insert_update_cached_parent_rightr,   r  rY   r-   ra   r,  r^   r
   r   rB   r   rm   r[   r   
_move_node
root_nodesr   rw   r   r   rx   r   sendr@   r2  rI   rG   r  _create_tree_spacer&  re   )r   r   rK   
do_updatestrack_updatesrJ   r9   r   r  r3  r4  collapse_old_treerd   old_parent_id
same_orderrW   	old_valuer7   r   update_cached_parentr:  rightmost_siblingright_shiftr1   r   r   r  z  sB  








	
	

$



zMPTTModel.savec           	         s   z| j j| j j| j jg}| j|d W n | jjy   Y nw | d| d d }| d}| d}| j	||| t
| | j j}|rT|   d }| j|| t j|i |S )aJ  Calling ``delete`` on a node will delete it as well as its full
        subtree, as opposed to reattaching all the subnodes to its parent node.

        There are no argument specific to a MPTT model, all the arguments will
        be passed directly to the django's ``Model.delete``.

        ``delete`` will not return anything.)ro   r   r   r]   r7   r>   )ry   r   rz   r{   refresh_from_dbr2   DoesNotExistr   r|   
_close_gapr   r_   rx   r8  r,   delete)	r   r   rK   fields_to_refresh
tree_widthtarget_rightr7   r9   rE  r1   r   r   rI  [  s(   

zMPTTModel.deletec                 C   sl   | j sd S t| j}| j}|| jjj| j d|j	|j
|j|jd }| D ]
\}}t| || q)d S )Nrv   r   )rw   r  r|   ry   r)  r~   r   r   valuesrz   r   r   r{   rB   rE   )r   r+  rJ   rM  rN   rO   r   r   r   _mptt_refresh  s&   

zMPTTModel._mptt_refresh)FF)F)r  FFT)r  r   ),r&   r'   r(   r+   r   r   objectsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  rx   r  r  r  r  r  r  r  r  r   r   r"  r#  r%  r,  r2  r  alters_datarI  rN  r3   r   r   r1   r   r     sz    
	



	

:





	




 `#r   )	metaclassc                 C   sr   t jdd dgkr3t }t|d}|d d }|dd }d|v r5ttd	d
s7td| ddS dS dS )z9Check that we are not generationg model from model_bakeryr]   r>   testr      /model_bakeryMPTT_ALLOW_TESTING_GENERATORSFzThe z populates django-mptt fields with random values which leads to unpredictable behavior. If you really want to generate this model that way, please set MPTT_ALLOW_TESTING_GENERATORS=True in your settings.N)	sysargvinspectcurrentframegetouterframessplitrm   r   	Exception)r   curframe
call_frame	call_filecall_directoryr   r   r   r     s   

r   )/rZ  rj   rX  r   	functoolsr   r   django.confr   	django.dbr   django.db.backends.utilsr   django.db.models.baser   django.db.models.queryr	   django.db.models.query_utilsr
   django.utils.translationr   rM   mptt.compatr   mptt.fieldsr   r   r   mptt.managersr   mptt.signalsr   
mptt.utilsr   __all__r   propertyr)   r4   r   r   r   r   r   r   rV  ImportErrorr   r   r   r   <module>   sN     < /     d