U
     fP%                     @   sp   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 Z
dd	 Zd
d Zdd ZG dd deZdS )    )apps)GenericForeignKey)BaseCommand)transaction)signalcommandc                  C   sL   t  } d}| D ]}td||jf  |d7 }qttd}| |d  }|S )N   %s. %sz=Enter the number of the model you would like to de-duplicate:)r   
get_modelsprint__name__intinput)modelsiteratormodelZmodel_choiceZmodel_to_deduplicate r   _/tmp/pip-unpacked-wheel-1isl55vw/django_extensions/management/commands/merge_model_instances.pyget_model_to_deduplicate
   s    
r   c           	         sN  dd | j  D }d}|D ]}td||f  |d7 }qd}|slttd}|td|krbd}q>td q>||d  g d}|sJ fd	d|D }d}|D ]}td||f  |d7 }qtd
 d}|s~td td d  td}|dkrd}d}qt|ttdt|d kr> |t|d  g7  d}qtd qq~ S )Nc                 S   s   g | ]
}|j qS r   )name).0fieldr   r   r   
<listcomp>   s     z#get_field_names.<locals>.<listcomp>r   r   FzEEnter the number of the (first) field you would like to de-duplicate.Tz Invalid input. Please try again.c                    s   g | ]}| kr|qS r   r   )r   fZfields_to_deduplicater   r   r   &   s     zC. Done adding fields.z8You are currently deduplicating on the following fields:
z
                Enter the number of the field you would like to de-duplicate.
                If you have entered all fields, enter C to continue.
            C)	_meta
get_fieldsr
   r   r   rangejoinlistlen)	r   fieldsr   r   Z	validatedZfirst_fielddoneZavailable_fieldsZadditional_fieldr   r   r   get_field_names   sF    




 r$   c                  C   s   t d} | dkr | S q d S )Nz
            Do you want to keep the first or last duplicate instance?
            Enter "first" or "last" to continue.
            )firstlast)r   )first_or_lastr   r   r   keep_first_or_last_instanceD   s    r(   c                  C   s>   g } t  D ],}|j D ]\}}t|tr| | qq| S )z6Return a list of all GenericForeignKeys in all models.)r   r	   __dict__items
isinstancer   append)generic_fieldsr   
field_namer   r   r   r   get_generic_fieldsN   s    
r/   c                   @   s,   e Zd ZdZedd Ze dd ZdS )Commanda  
        Removes duplicate model instances based on a specified
        model and field name(s).

        Makes sure that any OneToOne, ForeignKey, or ManyToMany relationships
        attached to a deleted model(s) get reattached to the remaining model.

        Based on the following:
        https://djangosnippets.org/snippets/2283/
        https://stackoverflow.com/a/41291137/2532070
        https://gist.github.com/edelvalle/01886b6f79ba0c4dce66
    c              	   O   s   t  }t|}t }d}|j D ]}i }|D ]}	||	}
||	|
i q.z|jjf | W q" |jk
r   |jj	f |}|dkr|
 }|j|jd}n|dkr| }|j|jd}| ||\}}}||7 }Y q"X q"td| d S )Nr   r%   )pkr&   z(Successfully deleted {} model instances.)r   r$   r(   objectsall__getattribute__updategetZMultipleObjectsReturnedfilterr%   excluder1   r&   merge_model_instancesr
   format)selfargsoptionsr   field_namesr'   Ztotal_deleted_objects_countinstancekwargsr.   Zinstance_field_valueZ	instancesprimary_objectalias_objectsdeleted_objectsdeleted_objects_countr   r   r   handlef   s2    
 zCommand.handlec                 C   sn  t  }ttdd |j }ttdd |}ttdd |}g }d}|D ]}|D ]}	|	j}
t||
}| D ]}z$t||
| t||
	| W qt t
k
r   t||
j}|	 ||	 |i}|jjf |}|D ]}t||	 | |  qY qtX qtqX|D ]}|jrX| }
t||
}| D ]"}|jj}t||| |  q2np|jsh|jr|j}
t||
}t||
}|dkrt||
| |  n&|jr| jd||j |  q|D ]Z}i }| ||j< ||||j< |jjjf |}|D ]}t||j| |  q
q|jrN||g7 }| jd||j |  |d7 }qN|||fS )	z
        Merge several model instances into one, the `primary_object`.
        Use this function to merge model objects and migrate all of the related
        fields from the alias objects the primary object.
        c                 S   s
   | j dkS NT)Zis_relationxr   r   r   <lambda>       z/Command.merge_model_instances.<locals>.<lambda>c                 S   s
   | j dkS rF   Zmany_to_manyrG   r   r   r   rI      rJ   c                 S   s
   | j dkS )NFrK   rG   r   r   r   rI      rJ   r   NzDeleted {} with id {}
r   ) r/   r    r7   r   r   r   getattrr3   removeaddAttributeErrorZthroughZm2m_reverse_field_nameZm2m_field_namer2   setattrsaveZone_to_manyZget_accessor_namer   Z
one_to_oneZmany_to_onestdoutwriter:   iddeleteZ_get_pk_valZfk_fieldget_content_typeZct_fieldr   )r;   rA   rB   r-   Zrelated_fieldsZmany_to_many_fieldsrC   rD   Zalias_objectZmany_to_many_fieldZalias_varnameZrelated_objectsobjZthrough_modelr@   Zthrough_model_instancesr?   Zrelated_fieldr.   Zrelated_objectZprimary_related_objectr   Zfilter_kwargsZgeneric_related_objectr   r   r   r9      s      

  





 

 
zCommand.merge_model_instancesN)	r   
__module____qualname__helpr   rE   r   Zatomicr9   r   r   r   r   r0   X   s
   
r0   N)Zdjango.appsr   Z"django.contrib.contenttypes.fieldsr   Zdjango.core.managementr   Z	django.dbr   Z"django_extensions.management.utilsr   r   r$   r(   r/   r0   r   r   r   r   <module>   s   /

