
    i                     ~    d dl Z d dlmZ d dlZd dl d dl d dlmZ  G d dej                  j                        Zy)    N)defaultdict)*)timeitc            	          e Zd ZdZdZdZ eedddddd      Z eedd      Z	 ee
d	
      Z eedd      Z ee
d
      Z eed
      Z ee
d
      Z ee
d
      Z ee
d
      Z ee
d
      Z ee
d
      Z ee
d
      Zed+d       Zed,d       Zed+d       Ze	 d-d       Zed        Zej:                   G d d             Zi ZdZ ed        Z!ed.d       Z"ed        Z#ed        Z$ed e%d!e&fd"       Z'ed/d e%d!e&d#e(jR                  jT                  fd$       Z+ed%        Z,ed&        Z-e e.de/j`                  d'(      d)               Z1e2d*        Z3y)0RelationCacheu  
    Мастер таблица всех деревянных связей объектов. В т.ч. непрямых. Т.е. дерего развёрнутое.
    Не заменяет m2m таблицы.
    Работа с данными этой таблицы только через методы этой модели. Вся магия деревьев здесь.

    TODO: Мультиколоночные индексы id+field

    TODO: какой-нить лок на изменение дерева, т.к. одновременные изменения его поломают.
        Сейчас защита на select for update, но нет уверенности что этого достаточно.
    Fu)   Идентификатор объектаu3   Автоматически генерируетсяT)captioncommentnullableprimary_keyreadonlyvisibleu   ID родителя)r   indexu$   Поле связи родителя)r   u   ID потомкаu"   Поле связи потомкаu   Глубина связиu   Модель родителяu   Имя родителяu   Код родителяu   Модель потомкаu.   Опциональное имя потомкаu   Код потомкаNc                 d   dg}ddl m} ddlm} |j	                  |      }	t        |	|      }
g }|j                  r`t        |
dd      rR|rt        d      t        |
t        j                  j                        st        d      |
j                  r:|
j                         j                  |d	g
      D cg c]  }|j                   }}n9|
j                         j                  |dg      D cg c]  }|j                    }}|sg S g }|
j"                  D cg c]  }|j%                  d       c}D ]  \  }}|j'                  dd|gdd|gg         t)        |      dkD  rdg|}ddd|g|g}|r'|D cg c]  }|j%                  d      d   |v s| }}n|}nddd|gdd|gg}|rddd|g|g}|r|g dz  }| j+                  |||      }|r|S t+        |D ch c]  }|j,                  j.                   c}      }|D ]  }|j'                  |        |S c c}w c c}w c c}w c c}w c c}w )u  
        full=True - возвращаем список экземпляров RelationCacheModel со всеми полями
        иначе только список child_id
        fixme: фильтр по child_field - нужен ли? Возможно
        r   r   cmfutil)confignested_fields_is_edge_parentFu]   get_children(full=True) не поддерживается для nested_fields_is_edge_parentuZ   TODO Тип поля не поддерживается для nested_fields_is_edge_parentright_id)left_idfieldsr   )r   r   .parent_model=parent_field   ORAND	parent_idIN:==child_model)
r   r   r   parent_nameparent_codechild_fieldr"   
child_name
child_codedepthr   filter
for_update)cmf.utilr   cmf.includer   get_model_by_idgetattrRELATION_CACHE_EDGE_OPTIMIZE	Exception
issubclasscmfr   
CmfM2MBaseleftm2m_model_clsslistr   r   nested_fieldssplitappendlenlistchild_idvalue)clsr   parent_field_namechild_modelsfullr+   r   r   r   r   r   additional_children_idsinested_ids_depth0parent_meta_filternested_model_namenested_field_namequery_filterresultrowresadditional_ids                         "./cmf/fields/cmf_relation_cache.pyget_childrenzRelationCache.get_children7   s    $& ..y9|->?"$..7<Igin3o"  B  BlCJJ,A,AB"|~~  9E9S9S9U9[9[dm  xB  wC9[  :D  %EAQZZ  %E!  %E8D8R8R8T8Z8Zdm  xA  wB8Z  9C  %D1QYY  %D!  %D$	 "$O[OiOi8j!8j @4!#4"))NCAR+SVdfik|U}*~@%&*&*%@-?%@"!K7H#IK]^L6G*k177SV<XY?^jKj1*k'*k*;' "Ky#ANTXZkClmL!M4#FUL S SF TM&93CLL&&9:4 	&MJJ}%	&
K %E %D 9k +l" :s$   6H0HH#6H(H(H-c                    t        t              }| j                  |||      D ](  }||j                  d      d      j	                  |       * |s-|j                         D ci c]  \  }}|t        |       c}}S |S c c}}w )u   
        get_children с разбитием по классам, потом удобней фильтровать, подгружать.
        result = {"child_model1": ["child_id1", ...], ...}
        )rA   r    r   )r   setrO   r9   additemsr<   )	r?   r   r@   rA   
return_setrJ   rK   
model_nameids_sets	            rN   get_children_dictzRelationCache.get_children_dictw   s     S!##I/@|#\ 	/C399S>!$%))#.	/IOX2E*gJW-XX Ys   $B c                     dg}ddd|gdd|gg}|rddd|g|g}| j                  |||      }|r|S t        |D 	ch c]  }	|	j                  j                   c}	      S c c}	w )	u   
        full=True - возвращаем список экземпляров RelationCacheModel со всеми полями
        иначе только список parent_id
        r   r   r=   r!   r%   r   r   r)   )r<   r   r>   )
r?   r=   child_field_nameparents_modelsrB   r+   r   rI   rJ   rK   s
             rN   get_parentszRelationCache.get_parents   s{     
D(;mTSc=de!ND.#I<XLTMF;SS]]((;<<;s   Ac	                    |r|s%t        d| d| d| d| d ||h|h|h       
      | j                  ||||dddg      }	|	ry	| j                  ||dd
      }
| j                  ||dd
      } | |||j	                  d      d   |||||j	                  d      d   ||d      }d}||gz   D ]  }|
|gz   D ]  }|j
                  |j
                  z   }|j                  |j                  f|j                  |j                  fk7  r|dz  }|j                  |j                  f|j                  |j                  fk7  r|dz  }|j                  |j                  k(  rtd}|d|j                   d|j                   d|j                   d|j                   d	z  }|dz  }|sddlm} |j!                  |       d}t"        j%                  d|         | |j                  |j                  |j&                  |j                  |j                  |j                  |j                  |j(                  |j                  |j                  |      j+                            y	)u   Добавим прямую связь между полями двух объектов, а также связи между родителями и детьми.z%add_relation: try add None relation, (z, z) -> r   Tr   r   r   r=   r%   r(   r+   r   N)rB   r+   r    )r   r   r   r#   r$   r=   r%   r"   r&   r'   r(   Fr   ud   Объект вложен сам в себя через промежуточные сущности: z) -> ... -> z).u    Зацикливание может привести к поблемам с производительностью, устраните зацикливание.r   z"ERROR RelationCache cycle detect: )CmfOrmErrorr<   rO   r[   	partitionr(   r   r   r=   r%   r#   r$   r&   r'   r,   r   admin_alertgdebugr   r"   save)r?   r   r@   r=   rY   r#   r$   r&   r'   direct_linkschildrenparentsdirect_linklinked_objects_cycle_alarmparentchildr(   error_messager   s                      rN   add_relationzRelationCache.add_relation   s    :Q/0:,b M "3!4{mk]STVW W
 xx.?+;cU   4   ##H.>TVZ#[//)->TVZ/[ .?iNaNabeNfghNi#+;I[I[\_I`abIc!j
 &+"- 	F![M1 u{{2$$f&9&9:{?T?TVaVnVn>ooQJENNE$5$56;;O;OQ\QhQh:iiQJE ##u~~5 'KM!q););(<Af>P>P=QQ]^c^n^n]oopqv  rB  rB  qC  CE  &F  FM!  (I  JM54++M:592GG@PQ$..V=P=P_e_r_r & 2 2@R@R"^^9J9J % 1 1$//E<L<L $&9	    c                    | j                  ||||dddg      }|syt        |      dkD  r't        dt        |       d| d	| d
| d	| 
||||      |d   }| j                  ||d      }| j	                  ||d      }||z   D ]S  }	||z   D ]G  }
|	j
                  |
j
                  z   }|	j                  |	j                  f|j                  |j                  fk7  r|dz  }|
j                  |
j                  f|j                  |j                  fk7  r|dz  }| j                  |	j                  |	j                  |
j                  |
j                  |ddg      }|r|j                          t        d|	j                  j                   d	|	j                  j                   d
|
j                  j                   d	|
j                  j                   d| 
|	|
|       V y)u3   
        TODO: пакетный режим
        r   Tr   r^   Nr   ztoo many relation (z) z::z => )rB   zrelation absent z depth )r<   r;   LookupErrorr[   rO   r(   r   r   r=   r%   getdeleteFileNotFoundErrorr>   )r?   r   r@   r=   rY   rf   ri   rh   rg   rk   rl   r(   links                rN   remove_relationzRelationCache.remove_relation   s,    xx.?+;cU   4  "%c,&7%8 9;b!2 3xj#3"46 ,h8H	J J
 #1o//)->T/J##H.>T#J, 	.F!L0 .u{{2$$f&9&9:{?T?TVaVnVn>ooQJENNE$5$56;;O;OQ\QhQh:iiQJE ww$..V=P=P"^^9J9JD#  @ KKM ,",,2232f6I6I6O6O5Pu~~334Bu7H7H7N7N6OwW\V]_ u	. .'.	.ro   c                       e Zd ZU dZeed<    ej                  e      Z	eed<    ej                  e      Z
eed<   dZeed<   y)	RelationCache.FieldCacheu~   Данные по полю модели Cmf, отражающие его связи и положение в иерархии.field_class)default_factoryrg   	right_forFrecursion_doneN)__name__
__module____qualname____doc__CmfTypeMeta__annotations__dataclassesfieldr<   rg   r{   r|   bool ro   rN   
FieldCacherx   &  sH     	M  ***4@$@
 ,+++DA	4A$$ro   r   c                     t        |dg       }t        |dd      r|t        |d      gz  }t        |t              r+||j                         D cg c]  }|j                   c}z  }t        t        |            S c c}w )u$   Список имён related_modelsmodelsmodelN)r/   r2   CmfSubclassedGenericRelationrelated_models
class_namer<   rQ   )r?   r   field_models_names	sub_models       rN   get_field_models_namesz$RelationCache.get_field_models_names6  s{     %UHb95'4(75'#:";;e9:I]I]I_"`I9#7#7"``C*+,, #as   A:c                 D   | j                   |   j                  j                  |       |rGd|vr|j                  d      d    d| }| j                   |   j                  j                  ||f       | j                   |   j
                  }t        |dd      rt        d| d|       t        |t              rht        |dd      sZ| j                   |   j                  s@d| j                   |   _
        | j                  |      D ]  }| j                  || d	        yyyy)
uA   Используется при создании cls.fields_cacher   r   r   Nu   Нельзя ссылаться с помощью nested_fields на поле, помеченное как nested_fields_is_edge_parent: z -> r8   Tz.id)_fields_cacherg   r:   ra   r{   ry   r/   r1   r2   CmfRelationBaser|   r   
_add_child)r?   rk   rl   backrefr%   field_model_names         rN   r   zRelationCache._add_childA  sU    	&!**11%8'!"__S1!45Qwi@g&0077H ''.::; >E  h  io  hp  pt  u@  tA  B  C  Ck?3_dC))%0??6:Ce$3$'$>$>{$K @ u)9(:#&>?@ @ D 4ro   c           	         t         }t        t        j                  |            | _        | j                  D ]  }|j
                  j                         D ]z  }t        |t        j                  j                  j                        s|j                  dk(  sA|j                   d|j                   }| j                  |      | j                  |<   |  t        | j                        }|D ]  }| j                  |   }|j                   }t        |t              s/|j"                  s<| j%                  |      }t        |t&        t(        f      r|D ]~  }	d}
|j"                  D ]7  }|j+                  |	dz         s| j-                  |||j.                         d}
9 |
rN| j-                  ||	 d|j.                  xs d |j.                          t1        d|       y	)
ud   
        Вызывается после загрузки моделей при создании app)model_filteridr   )ry   F)r   Tz#Unsupported nested_fields for fieldN)r   r<   r   iter_models_models_listr   valuesr2   r3   r   
base_model
CmfRelBaser   r   r   sortedry   r8   r   CmfBackrefBaser4   
startswithr   r   	TypeError)r?   r   r   r   field_full_namesorted_fields
field_namefield_cachefield_modelsfield_modelfoundrH   s               rN   build_fields_cachez RelationCache.build_fields_cacheW  s       3 3 3 NO
 %% 	WE,,. W"5#***?*?*J*JKuO_O_cgOg%*%5%5$6a8H8H7I"J58^^PU^5V!!/2	W	W s001' 	WJ++J7K++E %,1D1D"99%@enj%AB'3 	m %161D1D --0;;KOL #z;LV[VcVc d(,-  %NN *{m1U]]=Rd<S,T^c^k^k + m	m $$I:VV'	Wro   c                     | j                   j                  |      }|r<|j                  ry|j                  r"t	        |j
                  t        t        f      ryy y y )NT)r   rr   r{   rg   r2   ry   r   r4   )r?   r   fcs      rN   _is_tree_fieldzRelationCache._is_tree_field  sN    ""?3||{{z"..?J:WX  Y{ ro   
inst_field	target_idc                    |j                   j                  }|j                  }| d| }| j                  |   }|j                  }|j	                  d      d   }t
        j                  r|j                  r	 |j                  D ]  \  }	}
|
j	                  d      \  }}}|	j	                  d      \  }}}t        |t        t        f      r9||k(  sL| j                  |||j                   j                  j                  |       t        d|       |j                   D ]q  }|j	                  d      \  }}}t        |t        t        f      r9||k(  s4| j                  |j                   j                  j                  |||       gt        d|       y)uk  
        Рвём связь между field.instance и target_id, если она существует
        По field и fields_cache мы должны понять:
          - есть ли такая связь в кеше
          - поля, между которыми связь
          - кто родитель и кто потомок
        r   r    r   Unsupported right_for for fieldUnsupported children for fieldN)instancer   r   ry   ra   r   r0   r   r{   r2   r   r4   rv   r   r>   r   rg   )r?   r   r   r   r   r   r   r   target_model_nameparent_field_full_namechild_field_full_namechild_model_name_rY   parent_model_namer@   child_full_field_names                    rN   remove_field_referencez$RelationCache.remove_field_reference  s    &..99**
-.a
|</%//4Q7 ..:3Z3Z  >@\\ 	T9"$94I4S4STW4X1a!16L6V6VWZ6[3q"3%/:!>?$(99''	3DjFYFYF\F\FbFbdtu A?SS	T &([[ 	S!4I4S4STW4X1a!1%/:!>?$(88''
(;(;(>(>(D(DjR[]mn @/RR	Sro   targetc                    |j                   j                  }|j                  }| d| }| j                  |   }|j                  s|j                  syd}d}	|rs|j
                  j                  }t        |t        j                  j                        r,|j                  j                  }|j                  j                  }	|j                  }
n|j                  d      d   \  }
}}|j                  }|j                   }d}d}t        |t        j                  j                        r,|j                  j                  }|j                  j                  }t        j                   r|j"                  ry|j                  D ]  \  }}|j                  d      \  }}}|j                  d      \  }}}t%        |t&        t(        f      r4|
|k(  sL| j+                  |||j
                  j                  |||	||       zt-        d|       |j                  D ]l  }|j                  d      \  }}}t%        |t&        t(        f      r4|
|k(  s4| j+                  |j
                  j                  |||||||	       bt-        d|       y)u`  
        Создаём связь между field.instance и target_id, если нужно
        По field и fields_cache мы должны понять:
          - есть ли такая связь в кеше
          - поля, между которыми связь
          - кто родитель и кто потомок
        r   Nr    r   r#   r$   r&   r'   r   r   )r   r   r   rg   r{   r   r>   
isinstancer3   r   	CmfEntitynamecodera   ry   r   r0   r   r2   r   r4   rn   r   )r?   r   r   r   r   r   r   r   target_nametarget_coder   r   r   r   instance_nameinstance_coder   r   r   rY   r   r@   r   s                          rN   add_field_referencez!RelationCache.add_field_reference  se    &..99**
-.a
|</{{2<<		I&#**"6"67$kk//$kk// & 1 1&/&9&9#&>q&A#q!&&h

 4 45$MM//M$MM//M..:3Z3Z >@\\ 	T9"$94I4S4STW4X1a!16L6V6VWZ6[3q"3%/:!>?$(99$$!#4hkk6G6GIY$/[#0] % L
   A?SS	T &([[ 
	S!4I4S4STW4X1a!1%/:!>?$(88$$ )):yBR$1}#.; % H
   @/RR
	Sro   c                    d }d }t        |t        j                  j                        r,|j                  j
                  }|j                  j
                  }|j                  d      \  }}}| j                  |   }|j                  }	t        ||	j                        }
|
sy d }d }t        |
t              rnt        |
j
                  t        j                  j                        r@|
j
                  j                  j
                  }|
j
                  j                  j
                  }|j                  D ]  \  }}|j                  d      \  }}}|j                  d      \  }}}t        |	t              rf|
j
                  j                  |k(  sZ| j                  |
j
                  j                   j
                  ||j                   j
                  |||||       t        |	t"              rt%        d|       |j&                  D ]`  }|j                  d      \  }}}t        |	t              rf|
j
                  j                  |k(  sC| j                  |j                   j
                  ||
j
                  j                   j
                  |||||       t        |	t"              r|
j
                  D ]  }|j                  |k(  sd }d }t        |t        j                  j                        r,|j                  j
                  }|j                  j
                  }| j                  |j                   j
                  ||j                   j
                  |||||        Wt%        d|       y )Nr   r   r   r   )r   r3   r   r   r   r>   r   ra   r   ry   r/   r   r   r{   r2   rn   r   r4   r   rg   )r?   r   inst	inst_name	inst_coder   r   r   r   fr   inst_field_nameinst_field_coder   r   r   rY   r   r@   r   rel_instrel_inst_namerel_inst_codes                          rN   _make_field_relationsz#RelationCache._make_field_relations  s   
 		dCJJ001		I		I*9*C*CC*H'!Z/NNT1<<0
j/2z*BRBRTWT^T^ThTh7i(..3399O(..3399O >@\\ 	T9"$94I4S4STW4X1a!16L6V6VWZ6[3q"3!_-##..2CC $$"((++113D'7$3#,	 % D Az* A?SS#	T& &([[ 	S!4I4S4STW4X1a!1!_-##..2BB $$z"((++113C$-9#2	 % P Az* * 0 0 PH**.>>(,(,%h

0D0DE,4MM,?,?M,4MM,?,?M (( GGMM:$KK--/?(1y'4	 ) PP   @/RR;	Sro   c           	      d   d}d}d}| j                   D ]	  }t        |t        j                  j                        s)t        d|j                          |dz  }|j                  }|j                  j                  |      j                  |j                  j                  j                  d             j                         }||j                  j                  |      j                  |j                  j                  j                  d             j                         z  }t               }g }|j                  j                  |j                   |j"                  |j$                        D ];  \  }	}
}|
|f|v r|dz  }|dz  }|j'                  |	       )|j)                  |
|f       = |j                  j                  |      j                  |j                   j+                  |            j                  d       |s|dz  }t        |j                   d| d| d        t        | d	| d
       y )Nr   zClear r   F)synchronize_sessionr_   z
 deleted, z duplicate refs/z m2m tables cleared)r   r2   r3   r   BaseM2MModelprintr   dp_modeldpquery_deprecatedr*   r   isnotrs   root_idrQ   r   r   r   r:   rR   in_)r?   models_count	dup_countclearedr   r   deleteduniq_reldup_idsrel_idr   r   s               rN   clear_old_m2m_treez RelationCache.clear_old_m2m_treeR  s    	%% !	[EeSZZ%<%<=F5++,-.AL~~Hhh//9@@AYAYA_A_`dAefmmoGuxx00:AA%..BXBXB^B^_cBdellnnG uHG-2XX-F-Fx{{T\TdTdfnfwfw-x 6)X&(2qLGNINN6*LL'8!456 HH%%h/66x{{w7OPWWlqWr1))*!G9JykYZC!	[D 		<.(;<=ro   <   	log_startalarm_levelalarm_thresholdc                 t    t         j                          t        j                  j	                  d      }dt        j                  d<   t        d        j                  j                   j                        j                         }t        d| d        j                          t        dt        j                  d       fd	       } j                  D ]   |j                           j!                          |t        j                  d= n|t        j                  d<   t         j                          y
)u  
        Актуализация данных в таблице. Требуется монопольный режим для обеспечения целостности.
            TODO: Лок на таблицу
        Пока лучше выключать срм на время ребилда:
            systemctl stop eva-app
            cd /opt/eva-app
            python3 ./manage.py shell <<<"models.RelationCache.recalculate()"
        Есть смысл делать при обновлении, после наката миграций.

        TODO: clear=True - предварительно очистить таблицу.
        TODO: выборочный пересчёт
        NO_CACHE1zClear relation_cachez  z ClearedFr   r   c                    d}g }g }	j                   j                         D ]y  }t        j                  rt	        |dd      r!	j
                   d|j
                   }j                  |      sN|j                  |       |j                  |j
                         { |sy 	j                  dddg|      D ]   }|d	z  }|D ]  }j                  ||        " t        d
	j
                   d| d       y )Nr   r   Fr   r   r   r   r   r   zBuild relations from z done, z objects)r   r   r   r0   r/   r   r   r:   r<   r   r   )
_model_namecount_tree_fields_full_namestree_fields_namesr   r   r   r   r?   r   s
           rN   create_model_relationsz9RelationCache.recalculate.<locals>.create_model_relations  s    F%'" ",,. ?6675Jhjo;p%*%5%5$6a8H8H7I"J%%o6*11/B%,,U-=-=>? *!JJtVV.XFW.XJY D!"8 DJ--j(CDD
 )%*:*:);76((STro   N)	CMF_CACHEflushdbosenvironrr   r   r   r   r   rs   r   r   loggingWARNINGr   r   fix_relation_locations)r?   	cache_oldcountr   r   s   `   @rN   recalculatezRelationCache.recalculate|  s     	 JJNN:.	!$

:
 	$%''5<<>5'"# 	 	%W__a	P	U 
Q	U2 %% 	5E"5#3#34	5 	""$

:&%.BJJz" 	ro   c            
         ddl m} m} ddlm} t        |      j                         D ]  }t        |t              st        ||       rQt        d|j                          d}d}d}|j                  dg      D ]  }|dz  }|j                  r|j                  sa|dz  }t        d|j                   d	|j                  j                    d
|j                  j                           |j#                          |dz  }|j                  j                   j%                  d      d   }|j                  j                   j%                  d      d   }	|j                  | |	 k7  s|dz  }t        d|j                   d	| d
|	         t        | d| d| d       t        ||      st        d|j                          d}d}d}|j                  dg      D ]  }|dz  }|j                  j                   j%                  d      d   }
|j                  j                   j%                  d      d   }|j                  j                   j%                  d      d   }	|j                  j'                  |      r|dz  }t        d|j                   d	| d
|	        t)        ||
d      rt)        ||d      rt)        ||d      r|j#                          |dz  } t        | d| d| d        y)u6  
        TODO: временно, после патчинга баз - убрать.
        Из-за бага, м2м связи могут быть в 'чужой' таблице. Найдём их и исправим.
        python3 ./manage.py shell "models.RelationCache.fix_relation_locations()"
        r   )CmfM2MModelCmfGM2MModel)r   zCheck Model r   r   r   zInvalid z: z - r    r   z rows invalid, z fixedN)
cmf.modelsr   r  r-   r   varsr   r   typer2   r   r   r<   r   r   r   r>   rs   ra   r   r/   )r   r  r   r   	all_countinvalid_countfixed_countr   left_model_nameright_model_nameid_model_names              rN   r   z$RelationCache.fix_relation_locations  s    	9&&\((* *	XEeT*%-U%5%5$678	 ! %

3%
 8 `HNI#++83D3D%*R8H8H8N8N7OsS[SdSdSjSjRklm )#q( &.&6&6&<&<&F&Fs&KA&NO'/'8'8'>'>'H'H'Ma'P$''o->?O>P+QQ%*R7HL\K]^_` q?;-vVW%.U%5%5$678	 ! %

3%
 8 -HNI$,KK$5$5$?$?$DQ$GM&.&6&6&<&<&F&Fs&KA&NO'/'8'8'>'>'H'H'Ma'P$ ++66G%*R7HL\K]^_&v}dC'.v'M'.v'M$OO-'1,K- q?;-vVWU*	Xro   )NNN)NF)NNNN)N)NN)4r}   r~   r   r   abstract	api_allowFieldCmfTUUIDr   r   CmfTextr   r=   r%   CmfIntr(   r   r#   r$   r"   r&   r'   classmethodrO   rW   r[   rn   rv   r   	dataclassr   r   r   r   r   r   r   r   strr   r3   r   CmfModelr   r   r   r   r   r   r   staticmethodr   r   ro   rN   r   r      s   	 HI	E  PED4
HB h(=TJI*PQLX':$GH)MNK&"=>E *IJL)BCK)BCK)FGKw(XYJw(?@J = =~ 
 
 = =,  MQJ JX 7. 7.x 	% 	% 	% ML- - @ @* (W (W^   +S
 +Ss +S +SZ BSZ BSC BSX[XbXbXkXk BS BSH JS JSX '> '>R e"ME N EP 3X 3Xro   r   )r   collectionsr   cmf.models.base_modelr3   cmf.fields.base_fieldsr-   cmf.cmf_profiler   r   	BaseModelr   r   ro   rN   <module>r     s1     #  $  "iXCJJ(( iXro   