U
    dY                     @   s  d dl Z d dl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
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 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# d dl$m%Z% ddl&m'Z' ddlm(Z(m)Z)m*Z*m+Z+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3m4Z4 ddl5m6Z6m7Z7 ddl8m9Z9 G dd dZ:G dd de/e:Z;G dd de.e:Z<G dd  d e;e<Z=G d!d" d"e=ej>Z?G d#d$ d$e<Z@G d%d& d&e@ej>ZAG d'd( d(e;eAZBdS ))    N)forms)settings)adminmessages)ADDITIONCHANGEDELETIONLogEntry)get_permission_codename)ContentType)PermissionDenied)HttpResponseHttpResponseRedirect)escape)TemplateResponse)pathreverse)method_decorator)import_string)gettext_lazy)require_POST   )DEFAULT_FORMATS)ConfirmImportForm
ExportFormImportExportFormBase
ImportFormexport_action_form_factory)BaseExportMixinBaseImportMixin)	RowResult)post_exportpost_import)MediaStorageTempFolderStorage)originalc                       s2   e Zd Z fddZdd Zd fdd	Z  ZS )	ImportExportMixinBasec                    sN   t  j|| t| dd r$| j| _nd| _t| dd | _| jd krJ| j| _d S )Nchange_list_templatezadmin/change_list.html"import_export_change_list_template)super__init__getattrr'   base_change_list_template)selfargskwargs	__class__ 7/tmp/pip-unpacked-wheel-gh2cwdms/import_export/admin.pyr*   $   s    
  
zImportExportMixinBase.__init__c                 C   s   | j jj}|| j jjfS N)model_meta	app_labelZ
model_name)r-   r7   r2   r2   r3   get_model_info7   s    
z$ImportExportMixinBase.get_model_infoNc                    s    |pi }| j |d< t ||S )Nr,   )r,   r)   changelist_viewr-   requestZextra_contextr0   r2   r3   r9   ;   s    
z%ImportExportMixinBase.changelist_view)N)__name__
__module____qualname__r*   r8   r9   __classcell__r2   r2   r0   r3   r&   #   s   r&   c                       s&  e Zd ZdZdZdZeZeZ	e
ZdZdZdZdd Zdd	 Zd
d Z fddZeedd Zdd Zdd Zdd Zdd Zdd Zdd Zedd Zedd Zed d! Zd"d# Z d$d% Z!d&d' Z"d(d) Z#d:d*d+Z$d,d- Z%d;d.d/Z&d0d1 Z'd2d3 Z(d4d5 Z)d6d7 Z*d< fd8d9	Z+  Z,S )=ImportMixinz
    Import mixin.

    This is intended to be mixed with django.contrib.admin.ModelAdmin
    https://docs.djangoproject.com/en/dev/ref/contrib/admin/
    z+admin/import_export/change_list_import.htmlzadmin/import_export/import.htmlz	utf-8-sigNc                 C   s    | j d krttddS | j S d S )NZIMPORT_EXPORT_SKIP_ADMIN_LOGF)skip_admin_logr+   r   r-   r2   r2   r3   get_skip_admin_logY   s    
zImportMixin.get_skip_admin_logc                 C   s4   | j d krttdt}n| j }t|tr0t|}|S )NZIMPORT_EXPORT_TMP_STORAGE_CLASS)tmp_storage_classr+   r   r$   
isinstancestrr   )r-   rD   r2   r2   r3   get_tmp_storage_class_   s    
  
z!ImportMixin.get_tmp_storage_classc                 C   s>   t tdd}|dkrdS | j}t||}|jd|j|f S )zB
        Returns whether a request has import permission.
        Z$IMPORT_EXPORT_IMPORT_PERMISSION_CODENT%s.%sr+   r   optsr
   userZhas_permr7   )r-   r;   ZIMPORT_PERMISSION_CODErJ   codenamer2   r2   r3   has_import_permissionk   s    
z!ImportMixin.has_import_permissionc                    sR   t   }|  }td| j| jd| dtd| j| jd| dg}|| S )Nzprocess_import/z%s_%s_process_importnamezimport/z%s_%s_import)r)   get_urlsr8   r   
admin_site
admin_viewprocess_importimport_action)r-   urlsinfomy_urlsr0   r2   r3   rP   w   s    
zImportMixin.get_urlsc                 O   s   |  |stt| jddr(| |}n|  }||j}| r|  }|t|j	d  | j
d}| rpdn| j
}|  }	|	|j	d || d}
|
 }||}| j|||f||}|
  | ||S dS )z\
        Perform the actual import action (after the user has confirmed the import)
        is_originalFinput_format)encodingNimport_file_name)rO   rZ   	read_mode)rM   r   r+   get_confirm_import_formcreate_confirm_formPOSTis_validget_import_formatsintcleaned_datafrom_encoding	is_binaryrG   get_read_modereadcreate_datasetprocess_datasetremoveprocess_result)r-   r;   r.   r/   confirm_form	form_typeimport_formatsrY   rZ   tmp_storage_clstmp_storagedatadatasetresultr2   r2   r3   rS      s2    


zImportMixin.process_importc           	      O   sh   | j |f|d|i|}| |f |}| j|f|d|i|}|j|fdd|jd |jd|S )NformFToriginal_file_namedry_runraise_errors	file_namerK   )get_import_resource_kwargschoose_import_resource_classget_import_data_kwargsimport_datarc   rK   )	r-   rr   rl   r;   r.   r/   
res_kwargsresource
imp_kwargsr2   r2   r3   ri      s    zImportMixin.process_datasetc                 C   sH   |  || | || tjd | jd td|   | jjd}t	|S )NZsenderr5   zadmin:%s_%s_changelist)current_app)
generate_log_entriesadd_success_messager"   sendr5   r   r8   rQ   rO   r   )r-   rs   r;   urlr2   r2   r3   rk      s    zImportMixin.process_resultc              
   C   s   |   stjttjttjti}tj	
| jj}|D ]L}|j|jkr2|j|jkr2tj	j|jj||j|j||j td|j d q2d S )Nz%s through import_export)Zuser_idcontent_type_id	object_idobject_reprZaction_flagZchange_message)rC   r    IMPORT_TYPE_NEWr   IMPORT_TYPE_UPDATEr   ZIMPORT_TYPE_DELETEr   r   ZobjectsZget_for_modelr5   pkZimport_typeZIMPORT_TYPE_ERRORZIMPORT_TYPE_SKIPr	   Z
log_actionrK   r   r   _)r-   rs   r;   Zlogentry_mapr   rowr2   r2   r3   r      s&       z ImportMixin.generate_log_entriesc                 C   s<   | j j}td|jtj |jtj |j}t	
|| d S )Nz/Import finished, with {} new and {} updated {}.)r5   r6   r   formatZtotalsr    r   r   Zverbose_name_pluralr   success)r-   rs   r;   rJ   Zsuccess_messager2   r2   r3   r      s    

zImportMixin.add_success_messagec                 K   s   | j f |S r4   get_context_datar-   r/   r2   r2   r3   get_import_context_data   s    z#ImportMixin.get_import_context_datac                 K   s   i S r4   r2   r   r2   r2   r3   r      s    zImportMixin.get_context_datac                 C   s   t jdtd | jS )z
        .. deprecated:: 3.0
            Use :meth:`~import_export.admin.ImportMixin.get_import_form_class` or set the new
            :attr:`~import_export.admin.ImportMixin.import_form_class` attribute.
        zImportMixin.get_import_form() is deprecated and will be removed in a future release. Please use get_import_form_class() instead.category)warningswarnDeprecationWarningimport_form_classrB   r2   r2   r3   get_import_form   s
    zImportMixin.get_import_formc                 C   s   t jdtd | jS )z
        .. deprecated:: 3.0
            Use :func:`~import_export.admin.ImportMixin.get_confirm_form_class` or set the new
            :attr:`~import_export.admin.ImportMixin.confirm_form_class` attribute.
        zImportMixin.get_confirm_import_form() is deprecated and will be removed in a future release. Please use get_confirm_form_class() instead.r   )r   r   r   confirm_form_classrB   r2   r2   r3   r]      s
    z#ImportMixin.get_confirm_import_formc                 O   s   t jdtd |S )a	  
        .. deprecated:: 3.0
            Use :meth:`~import_export.admin.ImportMixin.get_import_form_kwargs` or
            :meth:`~import_export.admin.ImportMixin.get_confirm_form_kwargs`
            instead, depending on which form you wish to customise.
        zImportMixin.get_form_kwargs() is deprecated and will be removed in a future release. Please use get_import_form_kwargs() or get_confirm_form_kwargs() instead.r   )r   r   r   )r-   rt   r.   r/   r2   r2   r3   get_form_kwargs   s
    zImportMixin.get_form_kwargsc                 C   sR   |   }| |}| |}t|ts@tjdtd ||f|S |||  f|S )aL  
        .. versionadded:: 3.0

        Return a form instance to use for the 'initial' import step.
        This method can be extended to make dynamic form updates to the
        form after it has been instantiated. You might also look to
        override the following:

        * :meth:`~import_export.admin.ImportMixin.get_import_form_class`
        * :meth:`~import_export.admin.ImportMixin.get_import_form_kwargs`
        * :meth:`~import_export.admin.ImportMixin.get_import_form_initial`
        * :meth:`~import_export.mixins.BaseImportMixin.get_import_resource_classes`
        |The ImportForm class must inherit from ImportExportFormBase, this is needed for multiple resource classes to work properly. r   )	ra   get_import_form_classget_import_form_kwargs
issubclassr   r   r   r   get_import_resource_classes)r-   r;   formats
form_classr/   r2   r2   r3   create_import_form  s    


zImportMixin.create_import_formc                 C   s*   t | jdds$tjdtd |  S | jS )z
        .. versionadded:: 3.0

        Return the form class to use for the 'import' step. If you only have
        a single custom form class, you can set the ``import_form_class``
        attribute to change this for your subclass.
        rX   FzImportMixin.get_import_form() is deprecated and will be removed in a future release. Please use the new 'import_form_class' attribute to specify a custom form class, or override the get_import_form_class() method if your requirements are more complex.r   )r+   r   r   r   r   r   r-   r;   r2   r2   r3   r   (  s    	z!ImportMixin.get_import_form_classc                 C   s   |j pd|jpd| |dS )z
        .. versionadded:: 3.0

        Return a dictionary of values with which to initialize the 'import'
        form (including the initial values returned by
        :meth:`~import_export.admin.ImportMixin.get_import_form_initial`).
        Nrq   filesinitial)r_   FILESget_import_form_initialr   r2   r2   r3   r   >  s    	z"ImportMixin.get_import_form_kwargsc                 C   s   i S )z
        .. versionadded:: 3.0

        Return a dictionary of initial field values to be provided to the
        'import' form.
        r2   r   r2   r2   r3   r   L  s    z#ImportMixin.get_import_form_initialc                 C   s    |  |}| ||}|f |S )a  
        .. versionadded:: 3.0

        Return a form instance to use for the 'confirm' import step.
        This method can be extended to make dynamic form updates to the
        form after it has been instantiated. You might also look to
        override the following:

        * :meth:`~import_export.admin.ImportMixin.get_confirm_form_class`
        * :meth:`~import_export.admin.ImportMixin.get_confirm_form_kwargs`
        * :meth:`~import_export.admin.ImportMixin.get_confirm_form_initial`
        )get_confirm_form_classget_confirm_form_kwargs)r-   r;   import_formr   r/   r2   r2   r3   r^   U  s    
zImportMixin.create_confirm_formc                 C   s*   t | jdds$tjdtd |  S | jS )z
        .. versionadded:: 3.0

        Return the form class to use for the 'confirm' import step. If you only
        have a single custom form class, you can set the ``confirm_form_class``
        attribute to change this for your subclass.
        rX   Fa  ImportMixin.get_confirm_import_form() is deprecated and will be removed in a future release. Please use the new 'confirm_form_class' attribute to specify a custom form class, or override the get_confirm_form_class() method if your requirements are more complex.r   )r+   r]   r   r   r   r   r   r2   r2   r3   r   f  s    	z"ImportMixin.get_confirm_form_classc                 C   s6   |rd}d}n|j pd}|jp d}||| ||dS )z
        .. versionadded:: 3.0

        Return a dictionary of values with which to initialize the 'confirm'
        form (including the initial values returned by
        :meth:`~import_export.admin.ImportMixin.get_confirm_form_initial`).
        Nr   )r_   r   get_confirm_form_initial)r-   r;   r   rq   r   r2   r2   r3   r   |  s    


z#ImportMixin.get_confirm_form_kwargsc                 C   s:   |dkri S |j d j|j d j|j d |j dddS )z
        .. versionadded:: 3.0

        Return a dictionary of initial field values to be provided to the
        'confirm' form.
        Nimport_filerY   r    )r[   ru   rY   r   )rc   tmp_storage_namerO   get)r-   r;   r   r2   r2   r3   r     s    

z$ImportMixin.get_confirm_form_initialc                 O   s    | d}|r|d |S i S )z1
        Prepare kwargs for import_data.
        rt   )r   pop)r-   r;   r.   r/   rt   r2   r2   r3   r|     s
    

z"ImportMixin.get_import_data_kwargsc                 C   sp   d }|  s| j}|  }||| d}t }| D ]}||7 }q8|tkrb|  sb|| j}|| |S )N)rZ   r\   )	re   rd   rG   rf   byteschunksr#   decodesave)r-   r   rY   rZ   ro   rp   rq   chunkr2   r2   r3   write_to_tmp_storage  s    

z ImportMixin.write_to_tmp_storagec                    s  |  |st|  }|  }t| jddr8| |}nt| |}| j|f||}t|t	r||| 
 |jppd|jpxdf|}n*tjdtd |||jpd|jpdf|}t }	|jrP| rP|t|jd   }
|
 s| j|
_|jd }| ||
}|j|_z| }|
|}W nJ tk
rf } z*|dtdt|j  d	t!|  W 5 d}~X Y nX |j"s| j#|f|d
|i| | $|f  }|g}	| j%|f|d
|i|}|j&|fdd|j|j'd|}||d< |( s|) st| jddr| j*||d|d< n4| +|}| ,||}|| jf d
|i|d|d< n4| j#|f|d
|i| | 
 } fdd|D }	|-| j./| td|d< ||d
< | j0j1|d< | j2|j2 |d< dd |	D |d< | j.j|_3t4|| j5g|S )a  
        Perform a dry_run of the import to make sure the import will not
        result in errors.  If there are no errors, save the user
        uploaded file to a local temp file that will be used by
        'process_import' for the actual import.
        rX   FNr   r   rY   r   'za' encountered while trying to read file. Ensure you have chosen the correct format for the file. rt   Trv   rs   )r   rl   )r   c                    s   g | ]}|f  qS r2   r2   ).0Zresource_classr~   r2   r3   
<listcomp>  s     z-ImportMixin.import_action.<locals>.<listcomp>ZImporttitlerJ   mediac                 S   s&   g | ]}|  d d | D fqS )c                 S   s   g | ]
}|j qS r2   )Zcolumn_name)r   fr2   r2   r3   r   '  s     z8ImportMixin.import_action.<locals>.<listcomp>.<listcomp>)Zget_display_nameZget_user_visible_fields)r   r   r2   r2   r3   r   &  s   Zfields_list)6rM   r   r   ra   r+   r   r   r   r   r   r   r_   r   r   r   r   listr`   rb   rc   re   rd   rZ   r   rO   r   rg   rh   	ExceptionZ	add_errorr   typer<   rF   errorsrz   r{   r|   r}   rK   Z
has_errorsZhas_validation_errorsr^   r   r   updaterQ   each_contextr5   r6   r   r   r   import_template_name)r-   r;   r.   r/   contextrn   r   r   Zform_kwargs	resourcesrY   r   rp   rq   rr   er   r   rs   r   r   Zresource_classesr2   r   r3   rT     s    




 



zImportMixin.import_actionc                    s(   |d kri }|  ||d< t ||S )NrM   )rM   r)   r9   r:   r0   r2   r3   r9   /  s    zImportMixin.changelist_view)N)N)N)-r<   r=   r>   __doc__r(   r   r   r   r   r   r   r   rd   rA   rD   rC   rG   rM   rP   r   r   rS   ri   rk   r   r   r   r   r%   r   r]   r   r   r   r   r   r^   r   r   r   r|   r   rT   r9   r?   r2   r2   r0   r3   r@   A   sN   
"	



	


qr@   c                       s   e Zd ZdZdZdZdZeZ fddZ	dd Z
d	d
 Zdd Zdd Zdd Zedd Zdd Zdd Zd fdd	Z fddZ  ZS )ExportMixinz
    Export mixin.

    This is intended to be mixed with django.contrib.admin.ModelAdmin
    https://docs.djangoproject.com/en/dev/ref/contrib/admin/
    z+admin/import_export/change_list_export.htmlzadmin/import_export/export.htmlNc                    s4   t   }td| j| jd|   dg}|| S )Nzexport/z%s_%s_exportrN   )r)   rP   r   rQ   rR   export_actionr8   )r-   rU   rW   r0   r2   r3   rP   F  s    

zExportMixin.get_urlsc                 C   s>   t tdd}|dkrdS | j}t||}|jd|j|f S )zB
        Returns whether a request has export permission.
        Z$IMPORT_EXPORT_EXPORT_PERMISSION_CODENTrH   rI   )r-   r;   ZEXPORT_PERMISSION_CODErJ   rL   r2   r2   r3   has_export_permissionO  s    
z!ExportMixin.has_export_permissionc           	      C   s   |  |}| ||}| |}| |}| |rBdgt| }| |}|| j|||| j|| j	| j
| j| j| d}| j|d< tjdkr| j|d< |f |}||S )zo
        Returns export queryset.

        Default implementation respects applied search and filters.
        Zaction_checkbox)r;   r5   list_displaylist_display_linkslist_filterdate_hierarchysearch_fieldslist_select_relatedlist_per_pagelist_max_show_alllist_editableZmodel_adminsortable_by)   r   search_help_text)Zget_list_displayZget_list_display_linksZget_list_filterZget_search_fieldsget_actionsr   Zget_changelistr5   r   r   r   r   r   r   djangoVERSIONr   Zget_queryset)	r-   r;   r   r   r   r   Z
ChangeListZchangelist_kwargsZclr2   r2   r3   get_export_queryset[  s2    








zExportMixin.get_export_querysetc           	      O   sZ   | d}| |st| j||f||}||}|d}| sV|rV||}|S )zH
        Returns file_format representation for given queryset.
        r;   rZ   )r   r   r   Zget_data_for_exportexport_datar   re   encode)	r-   file_formatquerysetr.   r/   r;   rq   r   rZ   r2   r2   r3   get_export_data~  s    




zExportMixin.get_export_datac                 K   s   | j f |S r4   r   r   r2   r2   r3   get_export_context_data  s    z#ExportMixin.get_export_context_datac                 K   s   i S r4   r2   r   r2   r2   r3   r     s    zExportMixin.get_context_datac                 C   s   t jdtd | jS )z
        .. deprecated:: 3.0
            Use :meth:`~import_export.admin.ExportMixin.get_export_form_class` or set the new
            :attr:`~import_export.admin.ExportMixin.export_form_class` attribute.
        zExportMixin.get_export_form() is deprecated and will be removed in a future release. Please use the new 'export_form_class' attribute to specify a custom form class, or override the get_export_form_class() method if your requirements are more complex.r   )r   r   r   export_form_classrB   r2   r2   r3   get_export_form  s
    zExportMixin.get_export_formc                 C   s   | j S )zD
        Get the form class used to read the export format.
        )r   rB   r2   r2   r3   get_export_form_class  s    z!ExportMixin.get_export_form_classc                 O   s  |  |stt| jddr&|  }n|  }|  }|||  |jpHd }| r|t	|j
d   }| |}| j|||| j|d}	| }
t|	|
d}d| |||f |d< tjd | jd |S |  }|| j| td	|d
< ||d< | jj|d< | jj|_t|| jg|S )NrX   Fr   )r;   rZ   Zexport_formcontent_typeattachment; filename="%s"Content-Dispositionr   ZExportr   rt   rJ   )r   r   r+   r   r   get_export_formatsZget_export_resource_classesr_   r`   rb   rc   r   r   to_encodingget_content_typer   get_export_filenamer!   r   r5   r   r   rQ   r   r   r6   rO   r   r   export_template_name)r-   r;   r.   r/   rm   r   rt   r   r   r   r   responser   r2   r2   r3   r     sF    


    


zExportMixin.export_actionc                    s(   |d kri }|  ||d< t ||S )Nr   )r   r)   r9   r:   r0   r2   r3   r9     s    zExportMixin.changelist_viewc                    s   t  |S r4   )r)   r   )r-   r;   r   r   r0   r2   r3   r     s    zExportMixin.get_export_filename)N)r<   r=   r>   r   r(   r   r   r   r   rP   r   r   r   r   r   r%   r   r   r   r9   r   r?   r2   r2   r0   r3   r   6  s"   	#
'r   c                   @   s   e Zd ZdZdZdS )ImportExportMixinz"
    Import and export mixin.
    z2admin/import_export/change_list_import_export.htmlN)r<   r=   r>   r   r(   r2   r2   r2   r3   r     s   r   c                   @   s   e Zd ZdZdS )ImportExportModelAdminzB
    Subclass of ModelAdmin with import/export functionality.
    Nr<   r=   r>   r   r2   r2   r2   r3   r     s   r   c                       sH   e Zd ZdZdZ fddZdd Z fddZe fd	d
Z	  Z
S )ExportActionMixinzI
    Mixin with export functionality implemented as an admin action.
    Nc                    sn   g }|   }|r:t|D ] \}}|t||  f qt|dkrR|dd t|| _t	 j
|| dS )zb
        Adds a custom action form initialized with the available export
        formats.
        r   r   )r   z---N)r   	enumerateappendrF   Z	get_titleleninsertr   Zaction_formr)   r*   )r-   r.   r/   choicesr   ir   r0   r2   r3   r*     s    
zExportActionMixin.__init__c           	      C   s   |j d}|s"t|td nZ|  }|t|  }| j|||| jd}|	 }t
||d}d| |||f |d< |S dS )z>
        Exports the selected rows using file_format.
        r   z!You must select an export format.)r;   rZ   r   r   r   N)r_   r   r   warningr   r   rb   r   r   r   r   r   )	r-   r;   r   Zexport_formatr   r   r   r   r   r2   r2   r3   export_admin_action  s    
z%ExportActionMixin.export_admin_actionc                    s(   t  |}|jtjdtdfd |S )zJ
        Adds the export action to the list of available actions.
        r   z'Export selected %(verbose_name_plural)s)r   )r)   r   r   r   r   r   )r-   r;   actionsr0   r2   r3   r     s    zExportActionMixin.get_actionsc                    s    t  j}tj|jdg |jdS )Nzimport_export/action_formats.js)Zjscss)r)   r   r   ZMediaZ_jsZ_css)r-   Zsuper_mediar0   r2   r3   r   %  s    zExportActionMixin.media)r<   r=   r>   r   r(   r*   r   r   propertyr   r?   r2   r2   r0   r3   r     s   r   c                   @   s   e Zd ZdZdS )ExportActionModelAdminz^
    Subclass of ModelAdmin with export functionality implemented as an
    admin action.
    Nr   r2   r2   r2   r3   r  +  s   r  c                   @   s   e Zd ZdZdS )ImportExportActionModelAdminz
    Subclass of ExportActionModelAdmin with import/export functionality.
    Export functionality is implemented as an admin action.
    Nr   r2   r2   r2   r3   r  2  s   r  )Cr   r   r   Zdjango.confr   Zdjango.contribr   r   Zdjango.contrib.admin.modelsr   r   r   r	   Zdjango.contrib.authr
   Z"django.contrib.contenttypes.modelsr   Zdjango.core.exceptionsr   Zdjango.httpr   r   Zdjango.template.defaultfiltersr   Zdjango.template.responser   Zdjango.urlsr   r   Zdjango.utils.decoratorsr   Zdjango.utils.module_loadingr   Zdjango.utils.translationr   r   Zdjango.views.decorators.httpr   Zformats.base_formatsr   r   r   r   r   r   Zmixinsr   r   resultsr    Zsignalsr!   r"   Ztmp_storagesr#   r$   utilsr%   r&   r@   r   r   Z
ModelAdminr   r   r  r  r2   r2   r2   r3   <module>   sF      x &B