
    恕f                        d dl Z d dl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 d dlmZmZmZmZ d dlmZ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mZm Z  ddlm!Z!m"Z"m#Z#m$Z$m%Z%m&Z& d dlm'Z' ddl(m)Z)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/  G d de      Z0d Z1d Z2d Z3ejh                  ddddddfdZ5 G d de      Z6 G d de6      Z7y)    N)EnumEnumMeta)fields
validators)BooleanColumn)ColumnProperty)form)convertsModelConverterBaseInlineModelConverterBaseFieldPlaceholder)AjaxSelectFieldAjaxSelectMultipleField)prettify_name)get_property)	iteritems	text_type   )Uniquevalid_currencyvalid_colorTimeZoneValidator)QuerySelectFieldQuerySelectMultipleFieldInlineModelFormListInlineHstoreList
HstoreFormInlineModelOneToOneField)InlineFormField)has_multiple_pksfilter_foreign_columnsget_field_with_pathis_association_proxyis_relationship)create_ajax_loaderc                       e Zd ZdZ fdZd Zd Zd Zd Zd Z	d Z
ed	        Z ed
      d        Z ed      d        Z ed      d        Z edddd      d        Z edd      d        Z ed      d        Z ed      d        Z ed      d        Z ed      d        Z ed       d>d!       Z ed"      d#        Z ed$      d%        Z ed&      d'        Z ed(      d)        Z ed*      d+        Z ed,      d-        Z ed.      d/        Z ed0      d1        Z ed2      d3        Z  ed4d5      d6        Z! ed7d8      d9        Z" ed:      d;        Z# ed<      d=        Z$ xZ%S )?AdminModelConverterz0
        SQLAlchemy model to form converter
    c                 F    t         t        |           || _        || _        y N)superr(   __init__sessionview)selfr-   r.   	__class__s      \/var/www/feuerwehr-webapp/venv/lib/python3.12/site-packages/flask_admin/contrib/sqla/form.pyr,   zAdminModelConverter.__init__   s    !413	    c                     d|v r|d   S t        | j                  dd      }|r|j                  |      S t        | j                  dd      }|r ||      S t	        |      S )z
            Label for field name. If it is not specified explicitly,
            then the views prettify_name method is used to find it.

            :param field_args:
                Dictionary with additional field arguments
        labelcolumn_labelsrename_columnsr   N)r   r.   getgetattrr   )r/   name
field_argsr5   prettify_overrides        r1   
_get_labelzAdminModelConverter._get_label$   sj     j g&&$TYYAQR $$T**#DIIE$T**T""r2   c                 j    d|v r|d   S t        | j                  dd       }|r|j                  |      S y )Ndescriptioncolumn_descriptionsr8   r.   r7   )r/   r9   r:   r?   s       r1   _get_descriptionz$AdminModelConverter._get_description:   sB    J&m,,%dii1FM&**400 r2   c                 X    t        | j                  dd       }|r|j                  |      S y )Nform_overridesr@   )r/   r9   rC   s      r1   _get_field_overridez'AdminModelConverter._get_field_overrideC   s,     ,<dC!%%d++r2   c                      t         j                  di       j                  |j                        }|r|rt	        |fi |S t        |fi |S d|vr	 fd|d<   |rt        di |S t        di |S )N_form_ajax_refsquery_factoryc                  :    j                   j                         S r*   )r-   query)remote_modelr/   s   r1   <lambda>z9AdminModelConverter._model_select_field.<locals>.<lambda>U   s    dll.@.@.N r2    )r8   r.   r7   keyr   r   r   r   )r/   propmultiplerJ   kwargsloaders   `  `  r1   _model_select_fieldz'AdminModelConverter._model_select_fieldK   s|    $5r:>>txxH.v@@@&v888&(&NF?#+5f55#-f--r2   c                 Z   t        | j                  dd       }|r||vry |j                  j                  }|j                  d   d   }|j
                  s|j                  d   d   }| j                  ||      |d<   | j                  ||      |d<   t        j                  t        j                  ft        fd|d   D              }|s%|j                  s|j                  j                  dk7  r.d	|d
<   |sT|d   j                  t        j                                n-d|d
<   |s&|d   j                  t        j                                | j!                  |j"                        }	|	r |	di |S |xs& |j                  j                  dv xr |j$                  }
 | j&                  ||
|fi |S )Nform_columnsr   r   r4   r>   c              3   6   K   | ]  }t        |        y wr*   )
isinstance).0vrequirement_optionss     r1   	<genexpr>z8AdminModelConverter._convert_relation.<locals>.<genexpr>o   s     -oUVj<O.P-os   r   	MANYTOONETallow_blankF)	ONETOMANY
MANYTOMANYrL   )r8   r.   mapperclass_local_remote_pairsforeign_keysr<   rA   r   OptionalInputRequiredanynullable	directionr9   appendrD   rM   uselistrR   )r/   r9   rN   property_is_association_proxyrP   rT   rJ   columnrequirement_validator_specifiedoverriderO   rY   s              @r1   _convert_relationz%AdminModelConverter._convert_relation\   s   tyy.$?D4{{))((+A. "",,Q/2F//$7w $ 5 5dF C}  *22J4L4LM*--oZ`amZn-o*o'(FOOt~~?R?RVa?a$(F=!2|$++J,?,?,AB$)F=!2|$++J,D,D,FG ++DHH5%f%%1 Z^^((,GGXDLL 	't''hOOOr2   c                    t        |t              rt        j                  |j                        S g g d}|r|j                  |       |d   rt        |d         |d<   t        |d      st        |      rXt        |      }|r7t        |j                  d      st        d      |j                  j                  }| j                  ||||      S t        |d      rt        |j                        dkD  rzt        |t              sjt!        |j"                  |j                        }	t        |	      dk(  ry t        |	      dkD  r't%        j&                  d	|d
|j(                  d       y |	d   }
n|j                  d   }
t+        | j,                  dd       xs d}|
j.                  r|j(                  |vry t        |
t0              sy d}|
j2                  r[|rt5        j6                         S |j(                  |vry t9        |      s+|d   j;                  t=        | j>                  ||
             d}|
j@                  r+|s)|d   j;                  t=        | j>                  ||
             t+        | j,                  dtB        f      }|
jD                  sTt        |
jF                  |      s>|
jH                  s2|
jJ                  s&|d   j;                  tM        jN                                | j,                  jP                  |jR                  k(  r>| jU                  |j(                  |      |d<   | jW                  |j(                  |      |d<   t+        |
dd       d }1t+        dd       }|"t+        dd      rfd}nt+        dd      sd }|||d<   |
jD                  r&|d   j;                  tM        jX                                | j[                  |j(                        }|r |di |S t+        | j,                  dd       }|jR                  | j,                  jP                  k(  rA|r?|j]                  |j(                        }|r"t        j^                  d||
jD                  d|S | ja                  |
      }|y  |||||
|      S y )N)r   filtersr   rg   rN   zIAssociation proxy referencing another association proxy is not supported.columnsr   r   z,Can not convert multiple-column properties (.)rT   rL   FTform_optional_typesr4   r>   defaultargis_callablec                  &     j                  d       S r*   )rv   )ru   s   r1   rK   z-AdminModelConverter.convert.<locals>.<lambda>   s    D(9 r2   	is_scalarform_choices)choicesr\   )modelr_   rN   rk   r:   )1rV   r   r
   recreate_fieldfieldupdatelisthasattrr$   remote_attr	ExceptionrN   rn   lenrq   r	   r"   	__table__warningswarnrM   r8   r.   rb   r   primary_keyr   HiddenFieldr!   rh   r   r-   uniquer   rf   typeru   server_defaultr   rd   r|   r`   r<   rA   rc   rD   r7   Select2Fieldget_converter)r/   r|   r_   r9   rN   r:   	hidden_pkrP   rj   rq   rk   rT   r   optional_typesvaluerm   rz   r{   	converterru   s                      @r1   convertzAdminModelConverter.convert   s   d,-&&tzz22 

 MM*%,#'|(<#=F<  4%)=d)C,@,F),t//8#$opp'',,))$6SU[\\T9%4<< 1$Zn-M0$,,Ow<1$\A%MMZ_aeaiai"jk  a"499ndCIrL ""txx|'C ff-F!!!--// xx|3# ,E2|,33F4<<;@;A5C D "& }}V|$++F4<<3839-; < %TYY0EzRN OOv{{N;NN))|$++J,D,D,FG yy&--/"&//$((F"Cw(,(=(=dhh(O}% fi6GE"5$wu= 9&wTB$(E $)y! |$++J,?,?,AB //9H)&)) #499ndCL}}		/L&**4884,,  '$*OO !  **62I 5d$*v? ?r2   c                 "   t        |j                  d      ryt        |j                  j                  t              rT|j                  j                  r=|d   j                  t        j                  |j                  j                               y y y y )Nlengthr   )max)r   r   rV   r   intrh   r   Length)clsrk   r:   extras       r1   _string_commonz"AdminModelConverter._string_common  sg    6;;)j9K9KS.QV\VaVaVhVh|$++J,=,=&++BTBT,UV Wi.Q)r2   Stringc                     |j                   r)|j                  dg       }|j                  d        ||d<    | j                  d||d| t	        j
                  di |S )Nrp   c                     | xs d S r*   rL   xs    r1   rK   z1AdminModelConverter.conv_String.<locals>.<lambda>  
    QY$ r2   )rk   r:   rL   )rf   r7   rh   r   r   StringField)r/   rk   r:   r   rp   s        r1   conv_StringzAdminModelConverter.conv_String  s^    ?? nnY3GNN./$+Jy!J6jJEJ!!/J//r2   zsqlalchemy.sql.sqltypes.Enumc                    |j                   j                  D cg c]  }||f }}|D cg c]  }|d   	 }}|j                  rI|j                  |d<   |j                  d        |j	                  dg       }|j                  d        ||d<   ||d<   |d   j                  t        j                  |             d |d<   t        j                  d	i |S c c}w c c}w )
Nr   r\   rp   c                     | xs d S r*   rL   r   s    r1   rK   z2AdminModelConverter.convert_enum.<locals>.<lambda>$  r   r2   r{   r   c                 P    t        | t              r| j                  S t        |       S r*   )rV   r   r9   r   )rX   s    r1   rK   z2AdminModelConverter.convert_enum.<locals>.<lambda>)  s    :a3F IVWL r2   coercerL   )	r   enumsrf   rh   r7   r   AnyOfr
   r   )	r/   rk   r:   r   favailable_choiceschoiceaccepted_valuesrp   s	            r1   convert_enumz AdminModelConverter.convert_enum  s    -3[[->->?aV??3DE6!9EE??(.J}%""4( nnY3GNN./$+Jy! 1
9< ''
(8(8(IJX
8  .:.. @Es
   CCz(sqlalchemy_utils.types.choice.ChoiceTypec                    g }t        |j                  j                  t              r:|j                  j                  D cg c]  }|j                  |j
                  f }}n|j                  j                  }|D cg c]#  }t        |t              r|d   n|j                  % }}|j                  rI|j                  |d<   |j                  d        |j                  dg       }|j                  d        ||d<   ||d<   |d   j                  t        j                  |             t        |j                        |d<   t        j                  di |S c c}w c c}w )	Nr   r\   rp   c                     | xs d S r*   rL   r   s    r1   rK   z9AdminModelConverter.convert_choice_type.<locals>.<lambda>:  r   r2   r{   r   r   rL   )rV   r   r{   r   r   r9   tuplerf   rh   r7   r   r   choice_type_coerce_factoryr
   r   )	r/   rk   r:   r   r   r   r   r   rp   s	            r1   convert_choice_typez'AdminModelConverter.convert_choice_type,  s&   fkk))84<BKK<O<O Pq!''166!2 P P & 3 3bstX^
65(A6!9v||Stt??(.J}%""4( nnY3GNN./$+Jy! 1
9< ''
(8(8(IJ9&++F
8  .:.. !Q us   E;(ETextLargeBinaryBinaryCITextc                 T     | j                   dd|i| t        j                  di |S )Nr:   rL   )r   r   TextAreaFieldr/   r:   r   s      r1   	conv_TextzAdminModelConverter.conv_TextB  s.    ;z;U;##1j11r2   r   z"sqlalchemy.dialects.mssql.base.BITc                 ,    t        j                  di |S NrL   )r   BooleanFieldr   s      r1   conv_Booleanz AdminModelConverter.conv_BooleanG  s    ""0Z00r2   Datec                 Z    t        j                         |d<   t        j                  di |S )NwidgetrL   )r
   DatePickerWidgetr   	DateFieldr   s      r1   convert_datez AdminModelConverter.convert_dateK  s)    #446
8-*--r2   DateTimec                 ,    t        j                  di |S r   r
   DateTimeFieldr   s      r1   convert_datetimez$AdminModelConverter.convert_datetimeP      !!/J//r2   Timec                 ,    t        j                  di |S r   )r
   	TimeFieldr   s      r1   convert_timez AdminModelConverter.convert_timeT      ~~+
++r2   z&sqlalchemy_utils.types.arrow.ArrowTypec                 ,    t        j                  di |S r   r   r   s      r1   convert_arrow_timez&AdminModelConverter.convert_arrow_timeX  r   r2   z&sqlalchemy_utils.types.email.EmailTypec                     |j                   r)|j                  dg       }|j                  d        ||d<   |d   j                  t        j                                t        j                  di |S )Nrp   c                     | xs d S r*   rL   r   s    r1   rK   z3AdminModelConverter.convert_email.<locals>.<lambda>`  r   r2   r   rL   )rf   r7   rh   r   Emailr   r   )r/   r:   rk   r   rp   s        r1   convert_emailz!AdminModelConverter.convert_email\  s`    ?? nnY3GNN./$+Jy!< ''
(8(8(:;!!/J//r2   z"sqlalchemy_utils.types.url.URLTypec                     |d   j                  t        j                                t        g|d<   t	        j
                  di |S Nr   rp   rL   )rh   r   URLavoid_empty_stringsr   r   r   s      r1   convert_urlzAdminModelConverter.convert_urle  s=    < ''
(89!4 5
9!!/J//r2   z/sqlalchemy_utils.types.ip_address.IPAddressTypec                 x    |d   j                  t        j                                t        j                  di |S )Nr   rL   )rh   r   	IPAddressr   r   r   s      r1   convert_ip_addressz&AdminModelConverter.convert_ip_addressk  s2    < ''
(<(<(>?!!/J//r2   z&sqlalchemy_utils.types.color.ColorTypec                 p    |d   j                  t               t        g|d<   t        j                  di |S r   )rh   r   r   r   r   r   s      r1   convert_colorz!AdminModelConverter.convert_colorp  s6    < ''4!4 5
9!!/J//r2   z,sqlalchemy_utils.types.currency.CurrencyTypec                 p    |d   j                  t               t        g|d<   t        j                  di |S r   )rh   r   r   r   r   r   s      r1   convert_currencyz$AdminModelConverter.convert_currencyv  s6    < ''7!4 5
9!!/J//r2   z,sqlalchemy_utils.types.timezone.TimezoneTypec                     |d   j                  t        |j                  j                               t	        j
                  di |S )Nr   )coerce_functionrL   )rh   r   r   _coercer   r   r/   rk   r:   r   s       r1   convert_timezonez$AdminModelConverter.convert_timezone|  s;     	< ''(9&++J]J](^_!!/J//r2   Integerc                     t        |j                  dd      }|r(|d   j                  t        j                  d             t        j                  di |S )NunsignedFr   r   )minrL   )r8   r   rh   r   NumberRanger   IntegerField)r/   rk   r:   r   r   s        r1   handle_integer_typesz(AdminModelConverter.handle_integer_types  sI    6;;
E:|$++J,B,Bq,IJ""0Z00r2   Numericc                 P    |j                  dd        t        j                  di |S )NplacesrL   )
setdefaultr   DecimalFieldr   s       r1   handle_decimal_typesz(AdminModelConverter.handle_decimal_types  s(     	h-""0Z00r2   z(sqlalchemy.dialects.postgresql.base.INETc                     |j                  dd       |d   j                  t        j                                t	        j
                  di |S )Nr4   z
IP Addressr   rL   )r   rh   r   r   r   r   r   s      r1   conv_PGInetzAdminModelConverter.conv_PGInet  sB    g}5< ''
(<(<(>?!!/J//r2   z+sqlalchemy.dialects.postgresql.base.MACADDRc                     |j                  dd       |d   j                  t        j                                t	        j
                  di |S )Nr4   zMAC Addressr   rL   )r   rh   r   
MacAddressr   r   r   s      r1   conv_PGMacaddrz"AdminModelConverter.conv_PGMacaddr  sB    g~6< ''
(=(=(?@!!/J//r2   z(sqlalchemy.dialects.postgresql.base.UUIDz$sqlalchemy_utils.types.uuid.UUIDTypec                     |j                  dd       |d   j                  t        j                                t        g|d<   t        j                  di |S )Nr4   UUIDr   rp   rL   )r   rh   r   r   r   r   r   r   s      r1   conv_PGUuidzAdminModelConverter.conv_PGUuid  sO     	gw/< ''
(9:!4 5
9!!/J//r2   z)sqlalchemy.dialects.postgresql.base.ARRAYzsqlalchemy.sql.sqltypes.ARRAYc                 0    t        j                  dddi|S )Nsave_as_listTrL   )r
   Select2TagsFieldr   s      r1   
conv_ARRAYzAdminModelConverter.conv_ARRAY  s     $$E$E*EEr2   HSTOREc                 X    |j                  dt              }t        t        |      fi |S )Nr
   )popr   r   r    )r/   r:   r   
inner_forms       r1   conv_HSTOREzAdminModelConverter.conv_HSTORE  s'    ^^FJ7

 ;JzJJr2   JSONc                 ,    t        j                  di |S r   )r
   	JSONFieldr   s      r1   convert_JSONz AdminModelConverter.convert_JSON  r   r2   r*   )&__name__
__module____qualname____doc__r,   r<   rA   rD   rR   rn   r   classmethodr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r	  __classcell__r0   s   @r1   r(   r(      s   #,1."$PLHT W W h0 0 ,-/ ./  89/ :/* fmXx82 92 i=>1 ?1 f. . j0 0 f, , 670 80 670 80 230 40
 ?@0 A0 670 80
 <=0 >0
 <=0 >0
 i1 1 i1 1
 890 :0
 ;<0 =0
 846060 9-/F/F hK K f, ,r2   r(   c                 R    | r	 | j                         } | r| S dS # t        $ r Y w xY w)zM
    Return None if the incoming value is an empty string or whitespace.
    N)stripAttributeError)r   s    r1   r   r     s:     	KKME 5#t#  		s    	&&c                      ddl m}  j                  }t        |t              rt        |t              rd|cnd|c fd}|S )zw
    Return a function to coerce a ChoiceType column, for use by Select2Field.
    :param type_: ChoiceType object
    r   )Choicer   codec                 \    | y t        |       rt        |       S j                  |       S r*   )rV   r8   python_type)r   
choice_clsrM   type_s    r1   choice_coercez1choice_type_coerce_factory.<locals>.choice_coerce  s3    =eZ(5#&&  ''r2   )sqlalchemy_utilsr  r{   rV   r   
issubclassr   )r  r  r{   r  r  rM   s   `   @@r1   r   r     sG    
 (mmG'4 Z%>!7Z &Z( r2   c                 6    t        | d      r| j                  S | S )z\
        Resolve proxied property

        :param prop:
            Property to resolve
    _proxied_property)r   r  )rN   s    r1   _resolve_propr     s      t()%%%Kr2   FTc	           
          t         d      st        d       j                  j                  }	|xs i }d |	j                  D        }
|r fdfd|D        }
nrfd|
D        }
i }|
D ]Q  \  }}|r|j                  d      rt        |      }|j                   |	|||j                  |      |      }|M|||<   S |s-r+t              D ]  \  }}t        j                  |      ||<    t         j                  dz   |f|      S )	ac  
        Generate form from the model.

        :param model:
            Model to generate form from
        :param converter:
            Converter class to use
        :param base_class:
            Base form class
        :param only:
            Include fields
        :param exclude:
            Exclude fields
        :param field_args:
            Dictionary with additional field arguments
        :param hidden_pk:
            Generate hidden field with model primary key or not
        :param ignore_hidden:
            If set to True (default), will ignore properties that start with underscore
    _sa_class_managerz'model must be a sqlalchemy mapped modelc              3   8   K   | ]  }|j                   |f  y wr*   )rM   )rW   ps     r1   rZ   zget_form.<locals>.<genexpr>  s     @155!*@s   c                 F   r| v r| t        |          fS t        | d      \  }}|r0t        |      s%t        |      st	        dj                  |             t        |      r| |fS |j                  }|t        |d      r||j                  fS t        dd|       )NF)return_remote_proxy_attrzGform column is located in another table and requires inline_models: {0}propertyzInvalid model property name rr   )
r   r#   r%   r$   r   formatrM   r   r'  
ValueError)r9   rk   pathrelation_nameextra_fieldsr|   s       r1   findzget_form.<locals>.find  s     4-l4.@AAA.udUZ[LFD_V48LV8T !>>DfTlL L $F+V|#"JJM!gfj&A$foo55E4PQQr2   c              3   .   K   | ]  } |        y wr*   rL   )rW   r   r-  s     r1   rZ   zget_form.<locals>.<genexpr>!  s     ,!d1g,s   c              3   2   K   | ]  }|d    vs|  yw)r   NrL   )rW   r   excludes     r1   rZ   zget_form.<locals>.<genexpr>#  s     CAqt7/BaCs   _Form)r   	TypeErrorr"  r_   iterate_properties
startswithr   r   r7   r   r
   r}   r   r
  )r|   r   
base_classonlyr0  r:   r   ignore_hiddenr,  r_   
properties
field_dictr9   r$  rN   r~   r-  s   `   `   `       @r1   get_formr;    s    < 5-.ABB$$++F!rJ@f&?&?@J	R, -t,
	CC
J 	%aT__S1Q!!%tZ^^D=QS\]$Jt	% L$\2 	:KD%#2259Jt	: '*DDr2   c                   D     e Zd ZdZeZ	  fdZ fdZd Zd Z	d Z
 xZS )InlineModelConverterz'
        Inline model form helper.
    c                 H    t         t        |   |       || _        || _        y)aN  
            Constructor.

            :param session:
                SQLAlchemy session
            :param view:
                Flask-Admin view object
            :param model_converter:
                Model converter class. Will be automatically instantiated with
                appropriate `InlineFormAdmin` instance.
        N)r+   r=  r,   r-   model_converter)r/   r-   r.   r?  r0   s       r1   r,   zInlineModelConverter.__init__F  s$     	"D248.r2   c                    t         t        |   |      }|t        |d      r| j	                  |      S t        |dd       }|t        dt        |      z        t               }t        |      D ])  }|j                  d      r|dk7  st        ||      ||<   +  | j                  |fi |S | j                  |      |_        |S )Nr"  r|   zUnknown inline model admin: %sr1  )r+   r=  get_infor   form_admin_classr8   r   reprdictdirr5  process_ajax_refsrF   )r/   r$  infor|   attrsattrr0   s         r1   rA  zInlineModelConverter.get_infoV  s    )49!< <q-.,,Q//7D1=#$DtAw$NOOF 7D??3/DGO&-a&6d7 -t,,U<e<<
  $55d;r2   c                 f   t        |dd       }i }|rt        |      D ]  \  }}|j                  j                  j	                         d|}d }t        |t              r$t        |j                  | j                  |||      }n|}t        |d|       |||<   || j                  j                  |<    |S )Nform_ajax_refs-r9   )r8   r   r|   r
  lowerrV   rD  r&   r-   setattrr.   rF   )r/   rG  refsresultr9   optsnew_namerQ   s           r1   rF  z&InlineModelConverter.process_ajax_refsq  s    t-t4'o =
d&*jj&9&9&?&?&A4HdD)/

DLL(TXZ^_F!F FFH5%t6<		))(3!=$ r2   c                    |j                   j                  }|j                  j                   j                  j                  }d}|j                  D ]L  }t        |d      s|j                  j                  dv s)t        ||j                  j                        sJ|} n t        d|j                  z        d}|j                  j                  dk(  rd}nd}|j                  D ]P  }t        |d      s|j                  j                  |k(  s*|j                  j                  |j                  k(  sN|} n t        d|j                  z        |j                  |j                  fS )	a  
            Calculate mapping property key pair between `model` and inline model,
                including the forward one for `model` and the reverse one for inline model.
                Override the method to map your own inline models.

            :param model:
                Model class
            :param info:
                The InlineFormAdmin instance
            :return:
                A tuple of forward property key and reverse property key
        Nrg   )r[   r^   )Cannot find reverse relation for model %sr[   r]   r^   )Cannot find forward relation for model %s)r"  r_   r|   base_mapperr4  r   rg   r9   r  r`   r   rM   )	r/   r|   rG  r_   target_mapperreverse_proprN   forward_prop	candidates	            r1   _calculate_mapping_key_pairz0InlineModelConverter._calculate_mapping_key_pair  s@    ((// 

44;;GG!44 	VDt[)dnn.A.AE`.`eT[[%7%78#'L		V G$**TUU >>+-#I$I-- 	VDt[)dnn.A.AY.N;;%%)=)==#'L		V G$**TUU!1!111r2   c                     | j                  |      }| j                  ||      \  }}|g}|j                  r|t        |j                        z   }n|}| j	                  | j
                  |      }	|j                         }
|
Wt        |j                  |	|j                  xs t        j                  |j                  ||j                  d|j                        }
|j                  |
      }
t               }| j!                  ||      }|r||d<   | j"                  j                  r8| j"                  j                  j%                  |i       } |j&                  di | t)        || | j*                  |
| j
                  |j                  ||fi |       |S )a  
            Generate form fields for inline forms and contribute them to
            the `form_class`

            :param converter:
                ModelConverterBase instance
            :param session:
                SQLAlchemy session
            :param model:
                Model class
            :param form_class:
                Form to add properties to
            :param inline_model:
                Inline model. Can be one of:

                 - ``tuple``, first value is related model instance,
                 second is dictionary with options
                 - ``InlineFormAdmin`` instance
                 - Model class

            :return:
                Form class
        Tr6  r7  r0  r:   r   r,  r4   rL   )rA  r[  form_excluded_columnsr   r?  r-   r;  r|   form_base_classr
   BaseFormrT   	form_argsform_extra_fieldspostprocess_formrD  	get_labelr.   r7   r   rN  inline_field_list_type)r/   r|   
form_classinline_modelrG  forward_prop_keyreverse_prop_keyignorer0  r   
child_formrP   r4   r:   s                 r1   
contributezInlineModelConverter.contribute  s   2 }}\*-1-M-MeUY-Z** ##%%tD$>$>??GG ((t<	 ]]_
!$**"+-1-A-A-RT]]'+'8'8*1-1^^,0/3/E/EGJ **:6
t%56#F7O99,,001A2FJFMM'J' 	
 +++J,0LL,0JJ,<,0	6
 /56	7 r2   )r
  r  r  r  r   re  r,   rA  rF  r[  rl  r  r  s   @r1   r=  r=  9  s0     1/ 64-2^Lr2   r=  c                       e Zd ZeZd Zd Zy)InlineOneToOneModelConverterc                    |j                   j                  j                  j                  }|j                  j                  }t	               }|j
                  D ]  }t        |d      s|j                  j                  dk7  r+|j                  j                  |j                  k7  rOt        |d      }|st        |d      }|r|j                  ||<   {|j
                  D ]d  }t        |d      s|j                  j                  dk7  r*t        ||j                  j                        sK|j                  ||j                  <    n t        d|j                   z         n |st        d|j                   z        |S )Nrg   r[   backrefback_populatesr]   rT  rU  )r|   r"  r_   rV  rD  r4  r   rg   r9   r`   r8   rM   r  r   )	r/   r|   rG  r_   rW  inline_relationshiprY  refbackward_props	            r1   r[  z8InlineOneToOneModelConverter._calculate_mapping_key_pair  sx   --44@@//66"f"55 %	L<5%%**k9""))]-A-AA
 ,	2Cl,<=+7+;+;#C( "/!A!A N}k: **//;>e]%9%9%@%@A=I=M=M'(9(9:N  ?$**LN NK%	N #;djjHJ J #"r2   c                    | j                  |      }| j                  ||      }|j                         D cg c]  }| }}|j                  r|t	        |j                        z   }n|}| j                  | j                  |      }	|j                         }
|
Wt        |j                  |	|j                  xs t        j                  |j                  ||j                  d|j                        }
|j                  |
      }
t!               }|j#                         D ];  }t%        || | j&                  |
| j                  |j                  ||   |fi |       = |S c c}w )NTr]  )rA  r[  valuesr^  r   r?  r-   r;  r|   r_  r
   r`  rT   ra  rb  rc  rD  keysrN  re  )r/   r|   rf  rg  rG  inline_relationshipsr   rj  r0  r   rk  rP   rM   s                r1   rl  z'InlineOneToOneModelConverter.contribute@  sX   }}\*#??tL &:%@%@%BCE%CC%%tD$>$>??GG ((t<	 ]]_
!$**"+-1-A-A-RT]]'+'8'8*1-1^^,0/3/E/EGJ **:6
 (,,. 	CJ%@T%@%@

$S)& & 	 O Ds   	EN)r
  r  r  r   re  r[  rl  rL   r2   r1   rn  rn  	  s    52#h-r2   rn  )8r   enumr   r   wtformsr   r   
sqlalchemyr   r   sqlalchemy.ormr	   flask_adminr
   flask_admin.model.formr   r   r   r   flask_admin.model.fieldsr   r   flask_admin.model.helpersr   flask_admin._backwardsr   flask_admin._compatr   r   r   r   r   r   r   r   r   r   r   r   r    toolsr!   r"   r#   r$   r%   ajaxr&   r(   r   r   r   r`  r;  r=  rn  rL   r2   r1   <module>r     s      & & ) P P M 3 / 4 N N/ / 5P P $U,, U,p
$,  REjM3 M`d#7 dr2   