
    hs                        S SK r S SKrS SKJr  S SKJr  S SKJr  S SKJ	r	  S SK
JrJr  S SKJr  S SKJrJr  S SKr S S	KJr  \(       a  S SKrOS SKr\R2                  R4                  R6                  r\R8                  r\" \SS5      r\" \S-   5      r\" \S/ 5      r \" \SS5      r!\!(       a	  \" \!5      r"OSr"\ RF                  " S\ RH                  5      r%S r&S r' " S S\RP                  5      r( " S S5      r)g! \ a    S
r Nf = f)    N)settings)import_module)import_string)DatabaseSchemaIntrospection)get_public_schema_nameget_limit_set_calls)ContentType)ImproperlyConfiguredValidationError)is_psycopg3FORIGINAL_BACKENDzdjango.db.backends.postgresqlz.basePG_EXTRA_SEARCH_PATHSEXTRA_SET_TENANT_METHOD_PATHz^(?!pg_).{1,63}$c                 ,    [         R                  U 5      $ N)PGSQL_VALID_SCHEMA_NAMEmatchnames    X/var/www/html/env/lib/python3.13/site-packages/django_tenants/postgresql_backend/base.pyis_valid_schema_namer   3   s    "((..    c                 :    [        U 5      (       d  [        S5      eg )Nz(Invalid string used for the schema name.)r   r   r   s    r   _check_schema_namer   7   s    %%HII &r   c                   ~   ^  \ rS rSrSrSrU 4S jrU 4S jrSS jrSS jr	S r
S	 rS
 rS rSU 4S jjrS rSrU =r$ )DatabaseWrapper<   zX
Adds the capability to manipulate the search_path using set_tenant and set_schema_name
Tc                    > S U l         S U l        S U l        [        TU ]  " U0 UD6  [        U 5      U l        U R                  5         g r   )search_path_set_schemastenantschema_namesuper__init__r   introspectionset_schema_to_public)selfargskwargs	__class__s      r   r#   DatabaseWrapper.__init__D   sG    '+$$)&) 9>!!#r   c                 0   > S U l         [        TU ]	  5         g r   )r   r"   close)r&   r)   s    r   r,   DatabaseWrapper.closeP   s    '+$r   c                     Xl         UR                  U l        X l        U R                  U R                  5        [        (       a  [	        X5        SU l        [        R                  R                  5         g)`
Main API method to current database schema,
but it does not actually modify the db connection.
N)	r    r!   include_public_schemaset_settings_schemaEXTRA_SET_TENANT_METHODr   r	   objectsclear_cache)r&   r    include_publics      r   
set_tenantDatabaseWrapper.set_tenantT   s[    
 !--%3"  !1!12""#D1'+$ 	'')r   c                 8    U R                  [        UUS9U5        g)r/   r!   tenant_typeN)r6   
FakeTenant)r&   r!   r5   r:   s       r   
set_schemaDatabaseWrapper.set_schemal   s     
 	
{/:<=K	Mr   c                 D    U R                  [        [        5       S95        g)z2
Instructs to stay in the common 'public' schema.
)r!   N)r6   r;   r   r&   s    r   r%   $DatabaseWrapper.set_schema_to_publict   s     	
/E/GHIr   c                      XR                   S'   g )NSCHEMA)settings_dict)r&   r!   s     r   r1   #DatabaseWrapper.set_settings_schemaz   s    '28$r   c                 L    [         R                  " S[        S9  U R                  $ )NzJconnection.get_schema() is deprecated, use connection.schema_name instead.category)warningswarnDeprecationWarningr!   r?   s    r   
get_schemaDatabaseWrapper.get_schema}   s     b1	3r   c                 L    [         R                  " S[        S9  U R                  $ )NzEconnection.get_tenant() is deprecated, use connection.tenant instead.rF   )rH   rI   rJ   r    r?   s    r   
get_tenantDatabaseWrapper.get_tenant   s    ]1	3{{r   c                   > U(       a  [         TU ]  US9nO[         TU ]  5       n[        5       (       a  U R                  (       d  U R                  (       d  [        S5      eU R                  5       nU(       d  [        (       a  U R                  R                  5       nOUn U Vs/ s H  nSR                  U5      PM     nnUR                  SR                  SR                  U5      5      5        X0l        U(       d  [        (       a  UR'                  5         U$ s  snf ! [        R                  R                  R                   ["        R$                  4 a
    SU l         Njf = f)z
Here it happens. We hope every Django db operation using PostgreSQL
must go through this to get the cursor handle. We change the path.
r   zMDatabase schema not set. Did you forget to call set_schema() or set_tenant()?z'{}'zSET search_path = {0},N)r"   _cursorr   r   r!   r
   _get_cursor_search_pathsr   
connectioncursorformatexecutejoindjangodbutilsDatabaseErrorpsycopgInternalErrorr,   )r&   r   rU   search_pathscursor_for_search_pathsformatted_search_pathsr)   s          r   rR   DatabaseWrapper._cursor   s&   
 W_$_/FW_&F $%%d.J.J ##* ,S T T  88:L{{)-)?)?)A& *0&<FR)Sl(//!*<l&)S&../F/M/MchhWmNn/op 0<,{{&,,. *TIIOO1173H3HI 4/3,4s$   !D  %D 1D  D   ?E"!E"c                     [        U R                  5        [        5       nU R                  U:X  a  U/nO-U R                  (       a  U R                  U/nOU R                  /nUR	                  [
        5        U$ r   )r   r!   r   r0   extendEXTRA_SEARCH_PATHS)r&   public_schema_namer_   s      r   rS   (DatabaseWrapper._get_cursor_search_paths   sm    4++,3511./L'' ,,.@AL ,,-L./r   )r0   r$   r!   r   r    )T)TNr   )__name__
__module____qualname____firstlineno____doc__r0   r#   r,   r6   r<   r%   r1   rK   rN   rR   rS   __static_attributes____classcell__)r)   s   @r   r   r   <   sJ     !
$*0MJ3 

+Z r   r   c                   (    \ rS rSrSrSS jrS rSrg)r;      z
We can't import any db model in a backend (apparently?), so this class is used
for wrapping schema names in a tenant-like structure.
Nc                     Xl         X l        g r   r9   )r&   r!   r:   s      r   r#   FakeTenant.__init__   s    &&r   c                     U R                   $ r   )r:   r?   s    r   get_tenant_typeFakeTenant.get_tenant_type   s    r   r9   r   )ri   rj   rk   rl   rm   r#   ru   rn    r   r   r;   r;      s    ' r   r;   )*rerH   django.confr   	importlibr   django.utils.module_loadingr   /django_tenants.postgresql_backend.introspectionr   django_tenants.utilsr   r   "django.contrib.contenttypes.modelsr	   django.core.exceptionsr
   r   django.db.utilsrY   )django.db.backends.postgresql.psycopg_anyr   ImportErrorr]   psycopg2rZ   r[   r\   IntegrityErrorgetattrr   original_backendrf   r   r2   compile
IGNORECASEr   r   r   r   r;   rw   r   r   <module>r      s   	    # 5 W L : H F  		--''8%79XY  !1G!;< X'>C &x1OQUV +,HI" **%8"--H /J
E&66 EP
  
 i  Ks   C< <DD