o
    NfC-                  	   @   s   d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddlm
Z
 dd	lmZ d
Zdd ZG dd deZG dd dZG dd deZ							dddZde	dddddddf	ddZdS )z6Tools for generating forms based on SQLAlchemy models.    N)inspect)fields)
validators)Form   QuerySelectFieldQuerySelectMultipleField)model_fields
model_formc                     s    fdd}|S )Nc                    s   t  | _| S N)	frozenset_converter_for)funcargs O/home/ubuntu/webapp/venv/lib/python3.10/site-packages/wtforms_sqlalchemy/orm.py_inner   s   
zconverts.<locals>._innerr   )r   r   r   r   r   converts   s   r   c                   @   s   e Zd Zdd ZdS )ModelConversionErrorc                 C   s   t | | d S r   )	Exception__init__)selfmessager   r   r   r      s   zModelConversionError.__init__N)__name__
__module____qualname__r   r   r   r   r   r      s    r   c                   @   s(   e Zd Zd	ddZdd Zd
ddZdS )ModelConverterBaseTc                 C   sN   || _ |si }t| D ]}t| |}t|dr!|jD ]}|||< qq|| _d S )Nr   )use_mrodirgetattrhasattrr   
converters)r   r$   r    nameobj	classnamer   r   r   r       s   




zModelConverterBase.__init__c                 C   s   | j rtt|j}nt|jg}|D ]"}|j d|j }|dr*|dd }|| jv r6| j|   S q|D ]}|j| jv rI| j|j   S q9td|j	|d f )zjSearches `self.converters` for a converter method with an argument
        that matches the column's type..zsqlalchemy.   Nz2Could not find field converter for column %s (%r).r   )
r    r   getmrotyper   r   
startswithr$   r   r%   )r   columntypescol_typetype_stringr   r   r   get_converter.   s&   

z ModelConverterBase.get_converterNc                    s|  t |dst |dsd S t |dst|jdkrtdg g d |jd}|r+|| |d r7t|d |d< d }d }t |ds|jd }t|dd }	|	d urct|	d	d }
|
d urct|
ra|
d n|
}	|	|d< |j	rt|d 
t  n	|d 
t  | |}n2 d u rtd
|j |jjd}|jD ]	}|d j	sd}q|| fddd | j|jj }||||||dS )Ncolumns	directionr   z?Do not know how to convert multiple-column properties currently)r   filtersdefaultdescriptionr   r   r5   argz)Cannot convert field %s, need DB session.TFc                      s      S r   )queryallr   
db_sessionforeign_modelr   r   <lambda>   s    z,ModelConverterBase.convert.<locals>.<lambda>)allow_blankquery_factory)modelmapperpropr-   
field_args)r#   lenr2   	TypeErrordocupdatelistr"   callablenullableappendr   OptionalInputRequiredr1   r   keyrA   class_local_remote_pairsr$   r3   r%   )r   r@   rA   rB   rC   r;   kwargs	converterr-   r5   callable_defaultrJ   pairr   r:   r   convertK   sf   






zModelConverterBase.convert)Tr   )r   r   r   r   r1   rU   r   r   r   r   r      s    
r   c                       s  e Zd Zd: fdd	Zedd Zeddd	 Zed
dddd Zedddd Z	eddd Z
eddd Zeddd Zeddd Zedd d! Zed"d#d$d% Zed&d'd(d) Zed*d+d,d- Zed.d/d0d1d2 Zed3d4d5 Zed6d7d8d9 Z  ZS );ModelConverterNTc                    s   t  j||d d S )N)r    )superr   )r   extra_convertersr    	__class__r   r   r      s   zModelConverter.__init__c                 K   s<   t |jjtr|jjr|d tj|jjd d S d S d S )Nr   )max)
isinstancer+   lengthintrK   r   Length)clsr-   rC   extrar   r   r   _string_common   s   zModelConverter._string_commonStringc                 K   $   | j dd|i| tjdi |S NrC   r   )rb   wtforms_fieldsStringFieldr   rC   ra   r   r   r   conv_String      zModelConverter.conv_StringTextLargeBinaryBinaryc                 K   rd   re   )rb   rf   TextAreaFieldrh   r   r   r   	conv_Text   rj   zModelConverter.conv_TextBooleanzdialects.mssql.base.BITc                 K      t jdi |S Nr   )rf   BooleanFieldrh   r   r   r   conv_Boolean      zModelConverter.conv_BooleanDatec                 K   rq   rr   )rf   	DateFieldrh   r   r   r   	conv_Date   ru   zModelConverter.conv_DateDateTimec                 K   rq   rr   )rf   DateTimeFieldrh   r   r   r   conv_DateTime   ru   zModelConverter.conv_DateTimeEnumc                 K   s&   dd |j jD |d< tjdi |S )Nc                 S   s   g | ]}||fqS r   r   ).0er   r   r   
<listcomp>   s    z,ModelConverter.conv_Enum.<locals>.<listcomp>choicesr   )r+   enumsrf   SelectFieldr   r-   rC   ra   r   r   r   	conv_Enum   s   zModelConverter.conv_EnumIntegerc                 K   s8   t |jdd}|r|d tjdd tjdi |S )NunsignedFr   r   )minr   )r"   r+   rK   r   NumberRangerf   IntegerField)r   r-   rC   ra   r   r   r   r   handle_integer_types   s   z#ModelConverter.handle_integer_typesNumericc                 K   s   | dd  tjdi |S )Nplacesr   )
setdefaultrf   DecimalFieldr   r   r   r   handle_decimal_types   s   z#ModelConverter.handle_decimal_typeszdialects.mysql.types.YEARzdialects.mysql.base.YEARc                 K   s(   |d  tjddd tjdi |S )Nr   im  ik  )r   r[   r   )rK   r   r   rf   rg   rh   r   r   r   conv_MSYear   s   zModelConverter.conv_MSYearzdialects.postgresql.types.INETzdialects.postgresql.base.INETc                 K   .   | dd |d t  tjdi |S )Nlabelz
IP Addressr   r   )r   rK   r   	IPAddressrf   rg   rh   r   r   r   conv_PGInet      zModelConverter.conv_PGInetz!dialects.postgresql.types.MACADDRz dialects.postgresql.base.MACADDRc                 K   r   )Nr   zMAC Addressr   r   )r   rK   r   
MacAddressrf   rg   rh   r   r   r   conv_PGMacaddr   r   zModelConverter.conv_PGMacaddrzsql.sqltypes.UUIDzdialects.postgresql.types.UUIDzdialects.postgresql.base.UUIDc                 K   r   )Nr   UUIDr   r   )r   rK   r   r   rf   rg   rh   r   r   r   conv_PGUuid   s   zModelConverter.conv_PGUuid	MANYTOONEc                 K      t di |S rr   r   rh   r   r   r   conv_ManyToOne      zModelConverter.conv_ManyToOne
MANYTOMANY	ONETOMANYc                 K   r   rr   r	   rh   r   r   r   conv_ManyToMany   r   zModelConverter.conv_ManyToMany)NT)r   r   r   r   classmethodrb   r   ri   ro   rt   rx   r{   r   r   r   r   r   r   r   r   r   __classcell__r   r   rY   r   rV      sH    














rV   Fc              	      s   t | }|pt }|pi }g }	|j D ]"}
t|
ddr.|r%|
jd jr%q|r.|
jd jr.q|	|
j	|
f qrCfdd|	D }	n rN fdd|	D }	i }|	D ]\}}
|
| ||
|||}|durj|||< qR|S )zGenerate a dictionary of fields for a given SQLAlchemy model.

    See `model_form` docstring for description of parameters.
    r2   Nr   c                 3   s     | ]}|d   v r|V  qdS r   Nr   r}   x)onlyr   r   	<genexpr>      zmodel_fields.<locals>.<genexpr>c                 3   s     | ]}|d   vr|V  qdS r   r   r   )excluder   r   r     r   )	sainspectrV   attrsvaluesr"   r2   foreign_keysprimary_keyrK   rN   rU   get)r@   r;   r   r   rC   rR   
exclude_pk
exclude_fkrA   
propertiesrB   
field_dictr%   fieldr   )r   r   r   r      s,   
r   Tc
              
   C   sJ   t | ds	td|	pt| jd }	t| |||||||d}
t|	|f|
S )a  
    Create a wtforms Form for a given SQLAlchemy model class::

        from wtforms_sqlalchemy.orm import model_form
        from myapp.models import User
        UserForm = model_form(User)

    :param model:
        A SQLAlchemy mapped model class.
    :param db_session:
        An optional SQLAlchemy Session.
    :param base_class:
        Base form class to extend from. Must be a ``wtforms.Form`` subclass.
    :param only:
        An optional iterable with the property names that should be included in
        the form. Only these properties will have fields.
    :param exclude:
        An optional iterable with the property names that should be excluded
        from the form. All other properties will have fields.
    :param field_args:
        An optional dictionary of field names mapping to keyword arguments used
        to construct each field object.
    :param converter:
        A converter to generate the fields based on the model properties. If
        not set, ``ModelConverter`` is used.
    :param exclude_pk:
        An optional boolean to force primary key exclusion.
    :param exclude_fk:
        An optional boolean to force foreign keys exclusion.
    :param type_name:
        An optional string to set returned type name.
    _sa_class_managerz'model must be a sqlalchemy mapped modelr   )r   r   )r#   rE   strr   r   r+   )r@   r;   
base_classr   r   rC   rR   r   r   	type_namer   r   r   r   r     s   
,
r   )NNNNNFF)__doc__r   
sqlalchemyr   wtformsr   rf   r   wtforms.formr   r   r
   __all__r   r   r   r   rV   r   r   r   r   r   r   <module>   s>    ~W
-