
    hq                     d   d Z ddl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mZmZ ddlmZmZ dd	lmZ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m Z  ddl!m"Z"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/Z0 ddl1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9 ddl:m;Z;m<Z< ddl=m>Z> ddl?m@Z@mAZA dZB eddi      ZCeC ed !      z   ZD e       ZE G d" d#e      ZF G d$ d%eFej                        ZH G d& d'eFe      ZI G d( d)eI      ZJ G d* d+eI      ZK G d, d-ej                        ZMy).aE  
Translation support for admin forms.

*django-parler* provides the following classes:

* Model support: :class:`TranslatableAdmin`.
* Inline support: :class:`TranslatableInlineModelAdmin`, :class:`TranslatableStackedInline`, :class:`TranslatableTabularInline`.
* Utilities: :class:`SortedRelatedFieldListFilter`.

Admin classes can be created as expected:

.. code-block:: python

    from django.contrib import admin
    from parler.admin import TranslatableAdmin
    from myapp.models import Project

    class ProjectAdmin(TranslatableAdmin):
        list_display = ('title', 'status')
        fieldsets = (
            (None, {
                'fields': ('title', 'status'),
            }),
        )

    admin.site.register(Project, ProjectAdmin)

All translated fields can be used in the :attr:`~django.contrib.admin.ModelAdmin.list_display`
and :attr:`~django.contrib.admin.ModelAdmin.fieldsets` like normal fields.

While almost every admin feature just works, there are a few special cases to take care of:

* The :attr:`~django.contrib.admin.ModelAdmin.search_fields` needs the actual ORM fields.
* The :attr:`~django.contrib.admin.ModelAdmin.prepopulated_fields` needs to be replaced with a call
  to :func:`~django.contrib.admin.ModelAdmin.get_prepopulated_fields`.

See the :ref:`admin compatibility page <admin-compat>` for details.
    N)settings)admin)BaseModelAdminInlineModelAdmincsrf_protect_m)add_preserved_filters)get_deleted_objectsquoteunquote)ImproperlyConfiguredPermissionDenied)routertransaction)Media)Http404HttpRequestHttpResponseRedirect)render)re_pathreverse)	force_str
iri_to_uri)cached_property)conditional_escapeescape)	urlencode)	mark_safe)get_language)gettext_lazy)appsettings)TranslatableBaseInlineFormSetTranslatableModelForm)TranslatableQuerySet)TranslatableModelMixin)get_language_titleis_multilingual_project)select_template_name)get_language_parameterget_language_tabs)BaseTranslatableAdminTranslatableAdminTranslatableInlineModelAdminTranslatableStackedInlineTranslatableTabularInlineSortedRelatedFieldListFilterall)zparler/admin/parler_admin.css)css)zadmin/js/urlify.jszadmin/js/prepopulate.js)jsc                   b     e Zd ZdZeZdZe fd       Zd Z	d
dZ
d
dZd Z fdZd
d	Z xZS )r*   zM
    The shared code between the regular model admin and inline classes.
    languagec                 |    t        | j                  t                    }t        |   }|r	|t
        z   S |t        z   S N)lenget_prepopulated_fields_fakeRequestsupermedia_language_prepopulated_media_language_media)selfhas_prepopulated
base_media	__class__s      </home/dcms/DCMS/lib/python3.12/site-packages/parler/admin.pyr;   zBaseTranslatableAdmin.mediac   s>    
 t;;LIJW]
 <<<//    c                 6    t        | j                  t              S r6   )
issubclassmodelr$   r>   s    rB   _has_translatable_modelz-BaseTranslatableAdmin._has_translatable_modelo   s    $**&<==rC   c                 .    t        || j                        S )zF
        Get the language parameter from the current request.
        )r(   query_language_keyr>   requestobjs      rB   	_languagezBaseTranslatableAdmin._languages   s     &gt/F/FGGrC   c                 H    ||j                         S | j                  |      S )X
        Return the current language for the currently displayed object fields.
        )get_current_languagerN   rK   s      rB   get_form_languagez'BaseTranslatableAdmin.get_form_languagey   s'     ?++-->>'**rC   c                 f    t               st        j                  j                         S t	               S )z=
        Return the language to use in the queryset.
        )r&   r    PARLER_LANGUAGESget_default_languager   r>   rL   s     rB   get_queryset_languagez+BaseTranslatableAdmin.get_queryset_language   s)     '(//DDFF  >!rC   c                     t         |   |      }| j                         rVt        |t              s"t        |j                  j                   d      | j                  |      }|r|j                  |      }|S )z=
        Make sure the current language is selected.
        z1 class does not inherit from TranslatableQuerySet)
r:   get_querysetrH   
isinstancer#   r   rA   __name__rW   r4   )r>   rL   qsqs_languagerA   s       rB   rY   z"BaseTranslatableAdmin.get_queryset   sv     W!'*'')b"67*||,,--^_ 
 44W=K[[-	rC   c                 D    | j                  ||      }t        ||||      S )z6
        Determine the language tabs to show.
        	css_class)rR   r)   )r>   rL   rM   available_languagesr`   current_languages         rB   r)   z'BaseTranslatableAdmin.get_language_tabs   s/      11'3? %':i
 	
rC   r6   )r[   
__module____qualname____doc__r"   formrJ   propertyr;   rH   rN   rR   rW   rY   r)   __classcell__rA   s   @rB   r*   r*   X   sH    
 !D $	0 	0>H+
"&
rC   r*   c                   4    e Zd ZdZdZdZdZed        Zd Z	 e
d      e	_        d Z e
d      e_        ddZd	 Zd
 Z fdZ fdZd fd	Z fdZd fd	Zd fd	Z fdZd Zeej4                  d               Zd Zd ZddZddZe d        Z! xZ"S )r+   z
    Base class for translated admins.

    This class also works as regular admin for non TranslatableModel objects.
    When using this class with a non-TranslatableModel,
    all operations effectively become a NO-OP.
    Tz&admin/parler/deletion_not_allowed.htmlc                 &    | j                         ryy)z
        Dynamic property to support transition to regular models.

        This automatically picks ``admin/parler/change_form.html`` when the admin uses a translatable model.
        zadmin/parler/change_form.htmlN)rH   rG   s    rB   change_form_templatez&TranslatableAdmin.change_form_template   s     '') 3rC   c                 :    t        | j                  |d            S )zT
        The language column which can be included in the ``list_display``.
        zavailable-languagesspan_classes)r   _languages_column)r>   objects     rB   language_columnz!TranslatableAdmin.language_column   s%     ""68M"N
 	
rC   	Languagesc                     t         j                  D cg c]  \  }}|	 }}}t        | j                  ||d            S c c}}w )z
        The language column which can be included in the ``list_display``.
        It also shows untranslated languages
        zall-languagesrn   )r   	LANGUAGESr   rp   )r>   rq   code__all_languagess        rB   all_languages_columnz&TranslatableAdmin.all_languages_column   sI    
 /7.@.@A($AA""6="W
 	
 Bs   A c                    | j                  |      }||}|j                         }g }| j                  }|xs |D ]  }dg}	||v r|	j                  d       n|	j                  d       ||k(  r|	j                  d       |j                  |j
                  f}
t         dj                  |
 t        |j                        f| j                  j                        }|j                  dj                  |dj                  |	      t        |      t        | j                  |            	              d
j                  |dj                  |            S )Nz	lang-codeactiveuntranslatedcurrentadmin:{}_{}_changeargscurrent_appzG<a class="{classes}" href="{href}?language={language_code}">{title}</a> )language_codeclasseshreftitlez+<span class="language-buttons {}">{}</span>)get_available_languagesrQ   optsappend	app_label
model_namer   formatr
   pk
admin_sitenamejoinr   r   get_language_short_title)r>   rq   rx   ro   active_languagesrb   buttonsr   rv   r   info	admin_urls               rB   rp   z#TranslatableAdmin._languages_column   sE   77? ,M!668yy!5%5 	D"mG''x(~.''y)>>4??2D+$++T2FII&( OO00I
 NNY``"&HHW-	*,T-J-J4-PQ	 a 	. =CC#((7+
 	
rC   c                 "    |j                         S )zk
        Hook for allowing to change the title in the :func:`language_column` of the list_display.
        )upper)r>   r   s     rB   r   z*TranslatableAdmin.get_language_short_title  s     ""$$rC   c                     |r|j                         S | j                  j                  j                  j                  j                         S )z?
        Fetching the available languages as queryset.
        )r   rF   _parler_meta
root_modelobjectsnone)r>   rM   s     rB   r   z)TranslatableAdmin.get_available_languages  s;     ..00::**55==BBDDrC   c                     t         |   |      }| j                  rH| j                  |      }d|v sd|v r/|j	                  | j
                  j                  j                        }|S )Nrr   ry   )r:   rY   prefetch_language_columnget_list_displayprefetch_relatedrF   r   root_rel_name)r>   rL   r\   list_displayrA   s       rB   rY   zTranslatableAdmin.get_queryset  sb    W!'*((  009L L04Jl4Z(()@)@)N)NO	rC   c                     t        |   ||g|i |}|3| j                         r#|j                  | j	                  ||      d       |S )zJ
        Make sure the object is fetched in the correct language.
        T)
initialize)r:   
get_objectrH   set_current_languagerN   )r>   rL   	object_idr   kwargsrM   rA   s         rB   r   zTranslatableAdmin.get_object"  sS     g )EdEfE?t;;=$$T^^GS%Ad$S
rC   c                 x    t        |   ||fi |}| j                         r| j                  ||      |_        |S )z8
        Pass the current language to the form.
        )r:   get_formrH   rR   r   )r>   rL   rM   r   
form_classrA   s        rB   r   zTranslatableAdmin.get_form-  sB     W%gs=f=
'')'+'='=gs'KJ$rC   c                 $   t         |          }| j                         s|S | j                  j                  }|j
                  |j                  f}t        d| j                  j                  | j                         dj                  |       g|z   S )z0
        Add a delete-translation view.
        z&^(.+)/change/delete-translation/(.+)/$z{}_{}_delete_translation)r   )r:   get_urlsrH   rF   _metar   r   r   r   
admin_viewdelete_translationr   )r>   urlpatternsr   r   rA   s       rB   r   zTranslatableAdmin.get_urls7  s     g&(++-::##D>>4??2D=OO..t/F/FG:3::DA  rC   c                    | j                         r| j                  ||      }t        |      }| j                  |      }	| j	                  |||	      }
|
|d<   |
rdj                  |d   |      |d<   |
j                  sd}|j                  j                         }||d<   t        t        |      | j                  j                  d|      }d|vr| j                  |d<   t        | =  ||||||      S )z+
        Insert the language tabs.
        language_tabsz{} ({})r   Tr4   )preserved_filtersr   default_change_form_template)rH   rR   r%   r   r)   r   current_is_translatedGETdictr   r   rF   r   r   r:   render_change_form)r>   rL   contextaddchangeform_urlrM   	lang_codelangra   r   paramsrA   s               rB   r   z$TranslatableAdmin.render_change_formI  s    '')..w<I%i0D"&">">s"C 227CATUM'4GO$#,#3#3GG4Dd#K  66 [[%%'F!*F:,&/&7AQAQRT\H
 *86:6W6WG23 w)'7CSVWWrC   c                 L    t         |   |||      }| j                  |||      S r6   )r:   response_add_patch_redirect)r>   rL   rM   post_url_continueredirectrA   s        rB   r   zTranslatableAdmin.response_addk  s,    7'6GH##GS(;;rC   c                 J    t         |   ||      }| j                  |||      S r6   )r:   response_changer   )r>   rL   rM   r   rA   s       rB   r   z!TranslatableAdmin.response_changep  s)    7*7C8##GS(;;rC   c           	         |j                   dvr|S t        |j                        }| j                  j                  }|j
                  |j                  f}|j                  j                  | j                        }|r|dt         dj                  | | j                  j                        dt         dj                  | |j                  g| j                  j                        f}|d   j                  d	      }	|	d
   |v rH| j                  |j                  v r0t!        |	      dkD  rdnd	}
|dxx   |
 | j                   d| z  cc<   |S )N)i-  i.  z../add/zadmin:{}_{}_addr   z
../change/r~   r   Location?r      &=)status_coder   pathrF   r   r   r   r   getrJ   r   r   r   r   r   splitr7   )r>   rL   rM   r   urir   r   r4   continue_urlsredirect_parts	delimiters              rB   r   z!TranslatableAdmin._patch_redirectu  s?   z1O&zz~~t. ;;??4#:#:;0)00$7T__EYEYZ/(//6 !% 4 4M &j177<Na M1d6M6MQXQ\Q\6\#&~#6#:C	$9+d6M6M5NaPXz(ZZ$rC   c           
         | j                   j                  }| j                   j                  j                  }| j	                  |t        |            }|t        |j                  |       	 |j                  j                  ||      }| j                  ||      st        t        | j                  |            dk  r| j                  |||      S t!        j"                  |      }t%        |      }	g }
d}g }| j'                  ||j(                  || j*                        D ]  }t-        |t.        t0        f      r|d   j                  }n|j                   j                  }t2        j4                  dk\  rt7        ||| j8                        }n#t7        |||j:                  | j8                  |      }|\  }}}}|
|z  }
|xs |}||z  } |j<                  r#|rt        t?        d      jA                  |	tC        |            }| jE                  |||       | jG                  ||       | jI                  |t?        d	      tK        tC        |jL                        tC        |      
      z         | jO                  |d      rQ|jP                  |jR                  f}tU        tW         dj@                  | |f| j8                  jX                              S tU        tW        d| j8                  jX                              S t?        d      jA                  tC        |jL                              }|s|rt?        d      d|iz  }nt?        d      }||||
||||jP                  d}t[        | d      r'|j]                  d| j^                  j                  i       ta        || jb                  xs; d|jP                   d|jd                  jg                          dd|jP                  z  dg|      S # |j                  $ r t        w xY w)zE
        The 'delete translation' admin view for this model.
        Nmasterr   r   FrM   inlinesr   )   r   z{0} translation of {1}z0The %(name)s "%(obj)s" was deleted successfully.)r   rM   r~   r   zadmin:indexr   z{0} TranslationzCannot delete %(name)sr   zAre you sure?)r   object_namerq   deleted_objectsperms_lacking	protectedr   r   
base_model	base_optsadmin//z/delete_confirmation.htmlz!admin/%s/delete_confirmation.htmlzadmin/delete_confirmation.html)4rF   r   r   r   r   r   r   r   r   r   DoesNotExisthas_delete_permissionr   r7   r   deletion_not_allowedr   db_for_writer%   get_translation_objectsr   delete_inline_translationsrZ   listtupledjangoVERSIONr	   r   userPOST_r   r   log_deletiondelete_model_translationmessage_userr   verbose_namehas_change_permissionr   r   r   r   r   hasattrupdater   r   delete_confirmation_templater   lower)r>   rL   r   r   r   r   
shared_objtranslationusingr   r   perms_neededr   r\   qs_optsdeleted_resultdel2model_countsperms2
protected2obj_displayr   r   r   r   s                            rB   r   z$TranslatableAdmin.delete_translation  s    zzZZ,,77
 __Wgi.@A
M''6	$,,00
R_0`K ))';?""t++J78A=,,Wk=QQ
 ##J/!-0
 	 ..%%33	 / 
 	$B "tUm,Q%++((..~~'!4R$//!R!4t" 8F4T<t#O'16L#I+	$. <<&&45<<i,K g{K@))';?DEId&7&78i>TUV ))'48~~t6+3,33T:'\$(OO$8$8  ,Mt7K7KL  )*11)D<M<M2NO9./6;2GGEo&E &!.)"	
 4&NN!6!6 -- ($*:*:*@*@*B)CC\]3dnnD0
 	
 		
M && 	M	s   ,O O5c                     | j                   j                  }|j                  |||j                  t	        |      t        |j                        d}t        || j                  |      S )z,
        Deletion-not-allowed view.
        )rq   r   r   r   language_namer   )	rF   r   r   r   r%   r   r   r   deletion_not_allowed_template)r>   rL   rM   r   r   r   s         rB   r   z&TranslatableAdmin.deletion_not_allowed  s[     zzjj*/>$T%6%67
 gtAA7KKrC   c                     |j                   }| j                  ||j                  || j                        D ]@  }t	        |t
        t        f      r|D ]  }|j                           1|j                          B y)z
        Hook for deleting a translation.
        This calls :func:`get_translation_objects` to collect all related objects for the translation.
        By default, that includes the translations for inline objects.
        r   N)r   r   r   r   rZ   r   r   delete)r>   rL   r   r   r\   rM   s         rB   r   z*TranslatableAdmin.delete_model_translation%  sx     ##..[..FDDcDc / 
 	B "udm,  !CJJL!
 			rC   c              #     K   |B|j                   j                         D ]%  }	 |j                  j                  ||      }|g ' |r!| j                  |||      D ]	  \  }}|  yy# |j                  $ r Y ]w xY ww)z
        Return all objects that should be deleted when a translation is deleted.
        This method can yield all QuerySet objects or lists for the objects.
        Nr   rM   )r   get_all_modelsr   r   r   _get_inline_translations)	r>   rL   r   rM   r   translations_modelr   inliner\   s	            rB   r   z)TranslatableAdmin.get_translation_objects9  s     
 ? '*&6&6&E&E&G $""4"<"<"@"@"- #A #K
 #m#$ ";;G]X[;\ 
 	 *66 s(    B A+ +B +A=:B <A==B c              #     K   | j                  ||      }|D ]  }t        |j                  t              s|j	                  ||      j
                  }d|j                   }d|||i}|j                  j                  j                         D ]K  }	 |	j                  j                  di |}
|%|
j                  |j                  j                        }
||
f M  yw)z/
        Fetch the inline translations
        r  master__r   N )get_inline_instancesrE   rF   r$   get_formsetfkr   r   r  r   filterr   _statedb)r>   rL   r   rM   inline_instancesr  r  rel_namefiltersr  r\   s              rB   r  z*TranslatableAdmin._get_inline_translationsN  s       44W#4F& 	%F&,,(>? ''588%bggY/*M8SI*0,,*C*C*R*R*T %&:+33::EWEBXXcjjmm4 "*$%	%s   3CB&Cc                     | j                   j                  }|j                  }t        d| d|j                  j                          dd| ddf      S )zM
        Determine what the actual `change_form_template` should be.
        r   r   z/change_form.htmlzadmin/change_form.html)rF   r   r   r'   r   r   )r>   r   r   s      rB   r   z.TranslatableAdmin.default_change_form_templatec  sa    
 zzNN	#1T%5%5%;%;%=$>>OP#45(
 	
rC   )N r6   )FFr  N)NT)#r[   rc   rd   re   r   r  r   rg   rl   rr   r   short_descriptionry   rp   r   r   rY   r   r   r   r   r   r   r   r   r   atomicr   r   r   r   r  r   r   rh   ri   s   @rB   r+   r+      s      $$L! "& 
 )*+O%
 ./{^*!
F%E
	$ XD<
<
> ~
  ~
@L(*%* 
 
rC   r+   c                   Z     e Zd ZdZeZeZed        Z	d Z
d Zd fd	Zd fd	Zd Z xZS )	r,   z'
    Base class for inline models.
    c                 $    | j                          S )zU
        Whether to show inline tabs, can be set as attribute on the inline.
        )_has_translatable_parent_modelrG   s    rB   inline_tabsz(TranslatableInlineModelAdmin.inline_tabs}  s    
 66888rC   c                 6    t        | j                  t              S r6   )rE   parent_modelr$   rG   s    rB   r#  z;TranslatableInlineModelAdmin._has_translatable_parent_model  s    $++-CDDrC   c                 t    t               st        j                  j                         S | j	                  |      S r6   )r&   r    rT   rU   rN   rV   s     rB   rW   z2TranslatableInlineModelAdmin.get_queryset_language  s.    &(//DDFF >>'**rC   c                    t        |   ||fi |}| j                  ||      |_        | j                  rK| j                  ||      }| j                  |||d      |_        | j                         |j                  _	        |S )zZ
        Return the formset, and provide the language information to the formset.
        zparler-inline-language-tabsr_   )
r:   r  rR   r   r$  r   r)   r   r#  allow_deletion)r>   rL   rM   r   FormSetra   rA   s         rB   r  z(TranslatableInlineModelAdmin.get_formset  s     '%gs=f= !% 6 6w D"&">">sG"L$($:$:1=Z %; %G! 335 !!0 rC   c                 h    | j                         rt        | 	  ||      S | j                  |      S )rP   r  )r#  r:   rR   rN   )r>   rL   rM   rA   s      rB   rR   z.TranslatableInlineModelAdmin.get_form_language  s7     ..07,W#,>> >>'**rC   c                    |rd|j                   j                   |i} | j                  j                  j                  j
                  j                  |j                  j                        j                  di |j                  dd      j                         j                  d      S | j                  j                  j                  j
                  j                         S )zF
        Fetching the available inline languages as queryset.
        r  r   T)flatr  )r  r   rF   r   r   r   r   r  r  r  values_listdistinctorder_byr   )r>   rM   formsetr  s       rB   r   z4TranslatableInlineModelAdmin.get_available_languages  s      ! 12C8F

''22::@@O" "_48/* ::**55==BBDDrC   r6   )r[   rc   rd   re   r"   rf   r!   r1  rg   r$  r#  rW   r  rR   r   rh   ri   s   @rB   r,   r,   s  sA    
 !D+G9 9E+*+ErC   r,   c                        e Zd ZdZed        Zy)r-   z.
    The inline class for stacked layout.
    c                     | j                   ryy)Nz*admin/parler/edit_inline/stacked_tabs.htmlzadmin/edit_inline/stacked.htmlr$  rG   s    rB   templatez"TranslatableStackedInline.template      ? 4rC   Nr[   rc   rd   re   rg   r5  r  rC   rB   r-   r-          4 4rC   r-   c                        e Zd ZdZed        Zy)r.   z.
    The inline class for tabular layout.
    c                     | j                   ryy)Nz*admin/parler/edit_inline/tabular_tabs.htmlzadmin/edit_inline/tabular.htmlr4  rG   s    rB   r5  z"TranslatableTabularInline.template  r6  rC   Nr7  r  rC   rB   r.   r.     r8  rC   r.   c                   "     e Zd ZdZ fdZ xZS )r/   a  
    Override the standard :class:`~django.contrib.admin.RelatedFieldListFilter`,
    to sort the values after rendering their ``__unicode__()`` values.
    This can be used for translated models, which are difficult to sort beforehand.
    Usage:

    .. code-block:: python

        from django.contrib import admin
        from parler.admin import SortedRelatedFieldListFilter

        class MyAdmin(admin.ModelAdmin):

            list_filter = (
                ('related_field_name', SortedRelatedFieldListFilter),
            )
    c                 ^    t        |   |i | t        | j                  d       | _        y )Nc                 (    | d   j                         S )Nr   )r   )as    rB   <lambda>z7SortedRelatedFieldListFilter.__init__.<locals>.<lambda>  s    !

 rC   )key)r:   __init__sortedlookup_choices)r>   r   r   rA   s      rB   rA  z%SortedRelatedFieldListFilter.__init__  s+    $)&)$T%8%8>TUrC   )r[   rc   rd   re   rA  rh   ri   s   @rB   r/   r/     s    $V VrC   r/   )Nre   r   django.confr   django.contribr   django.contrib.admin.optionsr   r   r   ,django.contrib.admin.templatetags.admin_urlsr   django.contrib.admin.utilsr	   r
   r   django.core.exceptionsr   r   	django.dbr   r   django.formsr   django.httpr   r   r   django.shortcutsr   django.urlsr   r   django.utils.encodingr   r   django.utils.functionalr   django.utils.htmlr   r   django.utils.httpr   django.utils.safestringr   django.utils.translationr   r   r   parlerr    parler.formsr!   r"   parler.managersr#   parler.modelsr$   parler.utils.i18nr%   r&   parler.utils.templater'   parler.utils.viewsr(   r)   __all__r=   r<   r9   r*   
ModelAdminr+   r,   r-   r.   RelatedFieldListFilterr/   r  rC   rB   <module>r_     s  %L      Y Y N J J I )  B B # ( 7 3 8 ' - 1 6  M 0 0 I 6 H
 U$FGH.82    }P
N P
fE
-u/?/? E
PNE#8:J NEb4 < 44 < 4V5#?#? VrC   