o
    ӷ6i@                     @   sj  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mZ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 dlmZmZ d dlmZmZ d dl m!Z!m"Z" d dl#m$Z$m%Z% d dl&m'Z'm(Z)m*Z* d dl+m,Z, d dl-m.Z. d dl/m0Z0m1Z1 d dl2m3Z3m4Z4 dZ5dej6v Z7G dd deZ8G dd de8Z9G dd de	Z:dS )    N)formshttp)settings)messages)RelatedFieldListFilter)delete_selected)CHANGEDELETIONLogEntry)IncorrectLookupParameters
ModelAdminget_content_type_for_model)get_model_from_relation)ValidationError)DjangoJSONEncoder)IntegrityErrortransaction)ForeignObjectRelManyToManyField)	force_str	smart_str)format_html	mark_safe)get_language_bidigettextgettext_lazy)JS)InvalidMove)MPTTAdminFormTreeNodeChoiceField)	MPTTModelTreeForeignKey)DraggableMPTTAdminr   MPTTModelAdmin	grappellic                       sN   e Zd ZdZerdZndZeZ fddZdd Z	dd	 Z
 fd
dZ  ZS )r#   z
    A basic admin class that displays tree items according to their position in
    the tree.  No extra editing functionality beyond what Django admin normally
    offers.
    z%admin/grappelli_mptt_change_list.htmlzadmin/mptt_change_list.htmlc                    sx   t |jjtr1t|ts1|j| jvr1|d}|	 }t
|jjj||dd}|| |}t j||fi |S )NusingF)
form_classquerysetrequired)
issubclassremote_fieldmodelr    
isinstancer!   nameraw_id_fieldsgetget_limit_choices_tor   _default_managerr%   complex_filterupdatesuperformfield_for_foreignkey)selfdb_fieldrequestkwargsdblimit_choices_todefaults	__class__ O/var/www/hoanhtaovolam_webdjango/env/lib/python3.10/site-packages/mptt/admin.pyr5   0   s"   


z'MPTTModelAdmin.formfield_for_foreignkeyc                 C   s   | j j}| jp|j|jfS )zM
        Changes the default ordering for changelists to tree-order.
        )r+   
_mptt_metaorderingtree_id_attr	left_attr)r6   r8   	mptt_optsr?   r?   r@   get_orderingD   s   zMPTTModelAdmin.get_orderingc                 C   s   |j dr]d}|jj 9 |D ].}| ||r?t|}tjdk r*| 	||| nt
jj|jj|gtdd |  |d7 }qW d   n1 sJw   Y  | |tdd	|i  dS t| ||S )
z
        Deletes multiple instances and makes sure the MPTT fields get
        recalculated properly. (Because merely doing a bulk delete doesn't
        trigger the post_delete hooks.)
        postr         T)user_idr'   action_flagsingle_objectrJ   Nz%Successfully deleted %(count)d items.count)POSTr/   r+   _tree_managerdelay_mptt_updateshas_delete_permissionr   djangoVERSIONlog_deletionr
   objectslog_actionsuserpkr	   deletemessage_user_r   )r6   
modeladminr8   r'   nobjobj_displayr?   r?   r@   delete_selected_treeK   s0   
z#MPTTModelAdmin.delete_selected_treec                    s4   t  |}|d urd|v r| jdtdf|d< |S )Nr   z'Delete selected %(verbose_name_plural)s)r4   get_actionsra   r\   )r6   r8   actionsr=   r?   r@   rb   l   s   zMPTTModelAdmin.get_actions)__name__
__module____qualname____doc__IS_GRAPPELLI_INSTALLEDchange_list_templater   formr5   rF   ra   rb   __classcell__r?   r?   r=   r@   r#   "   s    !r#   c                       s   e Zd ZdZdZdZdZdZdZdZ	dd	 Z
d
e
_dd Zede_ fddZdd Zdd Zejdd Zdd Zdd Z  ZS )r"   z
    The ``DraggableMPTTAdmin`` modifies the standard Django administration
    change list to a drag-drop enabled interface.
    Ni  )tree_actionsindented_title)rm      Fc                 C   s:   z|  }W n ty   d}Y nw td|j|d|S )N zg<div class="drag-handle"></div><div class="tree-node" data-pk="{}" data-level="{}" data-url="{}"></div>level)get_absolute_url	Exceptionr   rY   
_mpttfield)r6   itemurlr?   r?   r@   rl      s   zDraggableMPTTAdmin.tree_actionsro   c                 C   s   t d|d| j |S )z{
        Generate a short title for an object, indent it depending on
        the object's depth in the hierarchy.
        z&<div style="text-indent:{}px">{}</div>rp   )r   rs   mptt_level_indent)r6   rt   r?   r?   r@   rm      s
   z!DraggableMPTTAdmin.indented_titletitlec                    s   |j ddkr| |S t j|g|R i |}z&|jd tjddgiddtdd	t	j
| |td
dgd |jd< W |S  ttfyL   Y |S w )Ncmd	move_nodemediaallzmptt/draggable-admin.cssz admin/js/vendor/jquery/jquery.jszadmin/js/jquery.init.jszmptt/draggable-admin.jszdraggable-admin-context)cls)idzdata-context)cssjs)rO   r/   
_move_noder4   changelist_viewcontext_datar   Mediar   jsondumps_tree_contextr   AttributeErrorKeyError)r6   r8   argsr9   responser=   r?   r@   r      s8   

z"DraggableMPTTAdmin.changelist_viewc                    s0   | j jd}fdd|D } fdd|D S )N)parent_attrrD   
right_attrrC   
level_attrc                    s   g | ]}t  |qS r?   getattr).0attr)rE   r?   r@   
<listcomp>   s    z=DraggableMPTTAdmin.get_data_before_update.<locals>.<listcomp>c                    s   i | ]}|t  |qS r?   r   )r   kcut_itemr?   r@   
<dictcomp>   s    z=DraggableMPTTAdmin.get_data_before_update.<locals>.<dictcomp>)r+   rA   )r6   r8   r   	pasted_onmptt_attr_fieldsmptt_fieldsr?   )r   rE   r@   get_data_before_update   s   z)DraggableMPTTAdmin.get_data_before_updatec                    s$    fdd|  D }dd|iigS )Nc                    s"   g | ]\}}|t  |kr|qS r?   r   )r   r   vr   r?   r@   r      s    zCDraggableMPTTAdmin.get_move_node_change_message.<locals>.<listcomp>changedfields)items)r6   r8   r   r   data_before_updatechanged_fieldsr?   r   r@   get_move_node_change_message   s   
z/DraggableMPTTAdmin.get_move_node_change_messagec           	   
   C   s  |j d}|dvr| j|tdtjd tdS | |}z|j|j dd}|j|j dd}W n | j	j
ttfyS   | j|td	tjd td
 Y S w | ||sj| j|tdtjd tdS | |||}z| j	j||| W n; ty } z| j|d| tjd tdW  Y d }~S d }~w ty } z| j|td| tjd  d }~ww | ||||}tjdk rtjj|jjt|j|jt|t|d ntjj|jj|gt|dd | |td|  tdS )Nposition)z
last-childleftrightz&Did not understand moving instruction.)rp   zFAIL, unknown instruction.r   rY   r   z$Objects have disappeared, try again.zFAIL, invalid objects.zNo permissionzFAIL, no permission.z%szFAIL, invalid move.zDatabase error: %srH   )rK   content_type_id	object_idobject_reprrL   change_messageT)rK   r'   rL   r   rM   z%s has been successfully moved.z
OK, moved.)rO   r/   r[   r\   r   ERRORr   HttpResponseget_querysetr+   DoesNotExist	TypeError
ValueErrorhas_change_permissionr   rP   ry   r   r   r   rS   rT   r
   rV   
log_actionrX   rY   r   strr   rW   )	r6   r8   r   r'   r   r   r   er   r?   r?   r@   r      sp   



	
zDraggableMPTTAdmin._move_nodec              	   C   sZ   | j j}d|j d|j d| | || jtdtdtdtdtdd	| jd
S )Ntree_r\   
_collapsedzmove node before nodezmove node to child positionzmove node after nodezCollapse treezExpand tree)beforechildaftercollapseTree
expandTree)storageNametreeStructurelevelIndentr   expandTreeByDefault)	r+   _meta	app_label
model_name_build_tree_structurer   rv   r\   expand_tree_by_default)r6   r8   optsr?   r?   r@   r     s   z DraggableMPTTAdmin._tree_contextc                 C   sN   i }| j j}|dd|j }|D ]\}}||rt|ndg | q|S )aK  
        Build an in-memory representation of the item tree, trying to keep
        database accesses down to a minimum. The returned dictionary looks like
        this (as json dump):

            {"6": [7, 8, 10]
             "7": [12],
             ...
             }

        Leaves are not included in the dictionary.
        rY   z%s_idr   )r+   rA   values_listr   
setdefaultr   append)r6   r'   	all_nodesrE   r   p_id	parent_idr?   r?   r@   r   '  s   
z(DraggableMPTTAdmin._build_tree_structure)rd   re   rf   rg   ri   list_per_pagelist_displaylist_display_linksrv   r   rl   short_descriptionrm   r   r   r   r   r   atomicr   r   r   rk   r?   r?   r=   r@   r"   w   s&    
"
=r"   c                       sH   e Zd ZdZdZdZ fddZdd Zdd	 Zd
d Z	dd Z
  ZS )TreeRelatedFieldListFiltera  
    Admin filter class which filters models related to parent model with all
    its descendants.

     Usage:

    from mptt.admin import TreeRelatedFieldListFilter

    @admin.register(models.MyModel)
    class MyModelAdmin(admin.ModelAdmin):
        model = models.MyModel
        list_filter =
        (
            ('my_related_model', TreeRelatedFieldListFilter),
        )
    zadmin/mptt_filter.html
   c                    s|   t || _|jd urt|jdr|j j| _n| jjjj| _| d| j d| _	t
 |||||| |j| j	| _d S )Nget_related_field____inhierarchy)r   other_modelr*   hasattrr   r-   rel_namer   rY   changed_lookup_kwargr4   __init__GETr/   
lookup_val)r6   fieldr8   paramsr+   model_admin
field_pathr=   r?   r@   r   X  s   
z#TreeRelatedFieldListFilter.__init__c                 C   s   | j | jgS )N)r   lookup_kwarg_isnull)r6   r?   r?   r@   expected_parametersd  s   z.TreeRelatedFieldListFilter.expected_parametersc              
   C   s   z0| j r'| jjj| j d}|d}| j| j= | j| j d| j	 d|i |j
di | jW S  ty@ } zt|d }~ww )Nr   Tr   __inr?   )r   r   rV   r/   get_descendantsused_parametersr   r3   r   r   filterr   r   )r6   r8   r'   r   other_modelsr   r?   r?   r@   r'   i  s   

z#TreeRelatedFieldListFilter.querysetc                 C   s   t |d| j}t }|jdd}dd |D }|jjj|d}dd |D }	g }
|D ]\}}d	|r4d
nd||	|  }|
||t	|f q*|
S )Nrv   F)include_blankc                 S   s   g | ]\}}|qS r?   r?   )r   rY   valr?   r?   r@   r     s    z<TreeRelatedFieldListFilter.field_choices.<locals>.<listcomp>)pk__inc                 S   s   i | ]}|j t||jjqS r?   )rY   r   rA   r   )r   r+   r?   r?   r@   r     s    z<TreeRelatedFieldListFilter.field_choices.<locals>.<dictcomp>z style="padding-{}:{}px"r   r   )
r   rv   r   get_choicesrelated_modelr1   r   formatr   r   )r6   r   r8   r   rv   language_bidiinitial_choicespksmodelslevels_dictchoicesrY   r   padding_styler?   r?   r@   field_choicesy  s$   

z(TreeRelatedFieldListFilter.field_choicesc                 c   s    | j }| jd u o| j |i | j| jgtddV  | jD ]\}}}| jt|k|| j|i| jg||dV  qt	| j
trM| j
j
js]t	| j
j
ts]| j
jd urr| j
js]t	| j
trtt| j|| jdi| jg|dV  d S d S d S )NAll)selectedquery_stringdisplay)r   r   r   r   True)empty_value_displayr   lookup_val_isnullget_query_stringr   r   r\   lookup_choicesr   r,   r   r   nullr   r*   bool)r6   clEMPTY_CHANGELIST_VALUEpk_valr   r   r?   r?   r@   r     sL   


z"TreeRelatedFieldListFilter.choices)rd   re   rf   rg   templaterv   r   r   r'   r   r   rk   r?   r?   r=   r@   r   C  s    r   );r   rS   r   r   django.confr   django.contribr   django.contrib.adminr   django.contrib.admin.actionsr   django.contrib.admin.modelsr   r	   r
   django.contrib.admin.optionsr   r   r   django.contrib.admin.utilsr   django.core.exceptionsr   django.core.serializers.jsonr   	django.dbr   r   django.db.models.fields.relatedr   r   django.utils.encodingr   r   django.utils.htmlr   r   django.utils.translationr   r   r\   r   js_assetr   mptt.exceptionsr   
mptt.formsr   r   mptt.modelsr    r!   __all__INSTALLED_APPSrh   r#   r"   r   r?   r?   r?   r@   <module>   s6    
U M