o
    ǯh'                     @   s   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 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mZmZ G dd dejZG dd dejZdS )    )settings)get_current_site)call_command)modelsconnectionstransaction)reverse)CloneSchema   )_check_schema_name)post_schema_syncschema_needs_to_be_sync)get_creation_fakes_migrationsget_tenant_base_schema)schema_existsget_tenant_domain_modelget_public_schema_nameget_tenant_database_aliasc                       s   e Zd ZdZdZ	 dZ	 dZ	 ejddde	gdZ
dZ	 dZ	 g ZG dd	 d	Zd
d Zdd Zdd Zdd Zedd Zd' fdd	Zdd Zd(ddZdd Zd( fdd	Z		d)dd Zd!d" Zd#d$ Zd%d& Z  ZS )*TenantMixinz4
    All tenant models must inherit this class.
    FTDATA?   )
max_lengthuniquedb_index
validatorsNc                   @      e Zd ZdZdS )zTenantMixin.MetaTN__name__
__module____qualname__abstract r!   r!   R/var/www/Befach/backend/venv/lib/python3.10/site-packages/django_tenants/models.pyMeta5       r#   c                 C      | j S N)schema_nameselfr!   r!   r"   __str__8      zTenantMixin.__str__c                 C   s$   t t  }| j|j |   | S )a  
        Syntax sugar which helps in celery tasks, cron jobs, and other scripts

        Usage:
            with Tenant.objects.get(schema_name='test') as tenant:
                # run some code in tenant test
            # run some code in previous tenant (public probably)
        )r   r   _previous_tenantappendtenantactivater)   
connectionr!   r!   r"   	__enter__;   s   
	zTenantMixin.__enter__c                 C   s   t t  }|| j  d S r&   )r   r   
set_tenantr,   pop)r)   exc_typeexc_valexc_tbr1   r!   r!   r"   __exit__J   s   
zTenantMixin.__exit__c                 C   s   t t  }||  dS )z
        Syntax sugar that helps at django shell with fast tenant changing

        Usage:
            Tenant.objects.get(schema_name='test').activate()
        N)r   r   r3   r0   r!   r!   r"   r/   O   s   
zTenantMixin.activatec                 C   s   t t  }|  dS )z
        Syntax sugar, return to public schema

        Usage:
            test_tenant.deactivate()
            # or simpler
            Tenant.deactivate()
        N)r   r   set_schema_to_public)clsr1   r!   r!   r"   
deactivateY   s   

zTenantMixin.deactivater
   c                    sD  t t  }| jj}t|d}|r|r|jt krtd|j |r3|s3|j| jt fvr3td|j t j	|i | |re|re| j
rez| jd|d tjt|  d W d S  tyd   | jdd  w |rrtjt|  d d S |s| j
rt| jsz| jd|d tjt|  d W d S  ty   |    w d S d S d S )Nr'   zDCan't create tenant outside the public schema. Current schema is %s.zWCan't update tenant outside it's own schema or the public schema. Current schema is %s.T)check_if_exists	verbosity)senderr.   )
force_drop)r   r   _stateaddinghasattrr'   r   	Exceptionsupersaveauto_create_schemacreate_schemar   sendr   serializable_fieldsdeleter   r   _drop_schema)r)   r=   argskwargsr1   is_new
has_schema	__class__r!   r"   rE   f   s>   

zTenantMixin.savec                 C   s   | S )zX in certain cases the user model isn't serializable so you may want to only send the id r!   r(   r!   r!   r"   rI      s   zTenantMixin.serializable_fieldsc                 C   s   t t  }t|d}|r|j| jt fvrtd|j |r:t| jr<| js(|r>|   |	 }|
d| j  dS dS dS dS )z Drops the schemar'   zWCan't delete tenant outside it's own schema or the public schema. Current schema is %s.zDROP SCHEMA "%s" CASCADEN)r   r   rB   r'   r   rC   r   auto_drop_schemapre_dropcursorexecute)r)   r?   r1   rO   rT   r!   r!   r"   rK      s   

zTenantMixin._drop_schemac                 C   s   dS )zz
        This is a routine which you could override to backup the tenant schema before dropping.
        :return:
        Nr!   r(   r!   r!   r"   rS      s    zTenantMixin.pre_dropc                    s   |  | t j|i |S )zt
        Deletes this row. Drops the tenant's schema if the attribute
        auto_drop_schema set to True.
        )rK   rD   rJ   )r)   r?   rL   rM   rP   r!   r"   rJ      s   
zTenantMixin.deletec           	      C   s   t t  }t| j | }|rt| jrdS t }|rK|r9t }t }|	|| j| j
 tddd| jd|d n|d| j  tdd| jd|d |  dS )z
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        Fmigrate_schemasT)r.   faker'   interactiver=   zCREATE SCHEMA "%s")r.   r'   rX   r=   N)r   r   r   r'   rT   r   r   r   r	   clone_schema
clone_moder   rU   r9   )	r)   r<   sync_schemar=   r1   rT   fake_migrationsbase_schemarY   r!   r!   r"   rG      s8   
	

zTenantMixin.create_schemac                 C   s.   z
| j jdd}|W S  t jy   Y dS w )z:
        Returns the primary domain of the tenant
        T
is_primaryN)domainsgetr   DoesNotExist)r)   domainr!   r!   r"   get_primary_domain   s   zTenantMixin.get_primary_domainc                 C   s8   |  rdnd}t|j}d|| jd|t|f}|S )z1
        Returns the URL of this tenant.
        zhttps://zhttp:// .)	is_securer   rc   joinr'   r   )r)   request	view_name	http_typerc   urlr!   r!   r"   r      s   
zTenantMixin.reversec                 C   s   t | tjS )zd
        Get the type of tenant. Will only work for multi type tenants
        :return: str
        )getattrr   MULTI_TYPE_DATABASE_FIELDr(   r!   r!   r"   get_tenant_type   s   zTenantMixin.get_tenant_type)r
   )F)FTr
   )r   r   r   __doc__rR   rF   rZ   r   	CharFieldr   r'   
domain_urldomain_subfolderr,   r#   r*   r2   r8   r/   classmethodr;   rE   rI   rK   rS   rJ   rG   rd   r   ro   __classcell__r!   r!   rP   r"   r      sD    


%

,
r   c                       sp   e Zd ZdZejddddZejej	ddej
dZejdddZej fdd	ZG d
d dZdd Z  ZS )DomainMixinzC
    All models that store the domains must inherit this class
       T)r   r   r   r`   )r   related_name	on_delete)defaultr   c                    sX   | j jj| jddj| jd}| jp|  | _| jr!|jdd t	 j
|i | d S )NT)r.   r_   )pkFr^   )rQ   objectsfilterr.   excluder{   r_   existsupdaterD   rE   )r)   rL   rM   domain_listrP   r!   r"   rE      s
   zDomainMixin.savec                   @   r   )zDomainMixin.MetaTNr   r!   r!   r!   r"   r#     r$   r#   c                 C   r%   r&   )rc   r(   r!   r!   r"   r*     r+   zDomainMixin.__str__)r   r   r   rp   r   rq   rc   
ForeignKeyr   TENANT_MODELCASCADEr.   BooleanFieldr_   r   atomicrE   r#   r*   ru   r!   r!   rP   r"   rv      s    
rv   N)django.confr   django.contrib.sites.shortcutsr   django.core.managementr   	django.dbr   r   r   django.urlsr   django_tenants.cloner	   postgresql_backend.baser   signalsr   r   utilsr   r   r   r   r   r   Modelr   rv   r!   r!   r!   r"   <module>   s     h