B
    CVvg1                 @   s   d dl Z d dlmZ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mZmZmZ G dd	 d	ZG d
d deZdS )    N)NoReverseMatchreverse)	mark_safe)FormHelpersException)Layout)LayoutSlice)TEMPLATE_PACKflatattlist_differencerender_fieldc               @   sd   e Zd Zdd Zdd Zdd Zddd	d
dZdd Zdd Zdd Z	dd Z
dd Zdd ZdS )DynamicLayoutHandlerc             C   s   | j d krtdd S )Nz+You need to set a layout in your FormHelper)layoutr   )self r   D/tmp/pip-install-o3oxmrkh/django-crispy-forms/crispy_forms/helper.py_check_layout   s    
z"DynamicLayoutHandler._check_layoutc             C   s   |    | jd krtdd S )Nz3You need to pass a form instance to your FormHelper)r   formr   )r   r   r   r   _check_layout_and_form   s    
z+DynamicLayoutHandler._check_layout_and_formc             C   s$   |    t| jtdt| jjdS )zD
        Returns all layout objects of first level of depth
        r      )r   r   r   slicelenfields)r   r   r   r   all   s    zDynamicLayoutHandler.allr   F)	max_levelgreedyc            G   s&   |    | jj|||d}t| j|S )zX
        Returns a LayoutSlice pointing to layout objects of type `LayoutClass`
        )r   r   )r   r   Zget_layout_objectsr   )r   r   r   ZLayoutClassesZfiltered_layout_objectsr   r   r   filter   s    zDynamicLayoutHandler.filterc             C   sP   |    | j }g }x,|D ]$}t| jj|j j|r|| qW t	| j|S )zX
        Returns a LayoutSlice pointing to fields with widgets of `widget_type`
        )
r   r   get_field_names
isinstancer   r   namewidgetappendr   )r   widget_typelayout_field_namesfiltered_fieldspointerr   r   r   filter_by_widget&   s    

z%DynamicLayoutHandler.filter_by_widgetc             C   sP   |    | j }g }x,|D ]$}t| jj|j j|s|| qW t	| j|S )zb
        Returns a LayoutSlice pointing to fields with widgets NOT matching `widget_type`
        )
r   r   r   r   r   r   r   r   r    r   )r   r!   r"   r#   r$   r   r   r   exclude_by_widget5   s    

z&DynamicLayoutHandler.exclude_by_widgetc             C   sn   t |trbt| |rt| |S |   | j }g }x |D ]}|j|kr:|| q:W t	| j|S t	| j|S )z{
        Return a LayoutSlice that makes changes affect the current instance of the layout
        and not a copy.
        )
r   strhasattrgetattrr   r   r   r   r    r   )r   keyr"   Zfiltered_fieldr$   r   r   r   __getitem__D   s    





z DynamicLayoutHandler.__getitem__c             C   s   || j |< d S )N)r   )r   r*   valuer   r   r   __setitem__]   s    z DynamicLayoutHandler.__setitem__c             C   s   | j j|= d S )N)r   r   )r   r*   r   r   r   __delitem__`   s    z DynamicLayoutHandler.__delitem__c             C   s   | j d k	rt| j jS dS d S )Nr   )r   r   r   )r   r   r   r   __len__c   s    
zDynamicLayoutHandler.__len__N)__name__
__module____qualname__r   r   r   r   r%   r&   r+   r-   r.   r/   r   r   r   r   r      s   	r   c               @   s  e Zd ZdZdZdZdZdZdZdZ	dZ
dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdddZd	d
 Zedd Zej dd Zedd Z!e!j dd Z!edd Z"e"j dd Z"edd Z#e#j dd Z#dd Z$dd Z%e&fddZ'e&fddZ(dS ) 
FormHelperaq  
    This class controls the form rendering behavior of the form passed to
    the `{% crispy %}` tag. For doing so you will need to set its attributes
    and pass the corresponding helper object to the tag::

        {% crispy form form.helper %}

    Let's see what attributes you can set and what form behaviors they apply to:

        **form_method**: Specifies form method attribute.
            You can set it to 'POST' or 'GET'. Defaults to 'POST'

        **form_action**: Applied to the form action attribute:
            - Can be a named url in your URLconf that can be executed via the `{% url %}` template tag.             Example: 'show_my_profile'. In your URLconf you could have something like::

                path('show/profile/', 'show_my_profile_view', name = 'show_my_profile')

            - It can simply point to a URL '/whatever/blabla/'.

        **form_id**: Generates a form id for dom identification.
            If no id provided then no id attribute is created on the form.

        **form_class**: String containing separated CSS classes to be applied
            to form class attribute.

        **form_group_wrapper_class**: String containing separated CSS classes to be applied
            to each row of inputs.

        **form_tag**: It specifies if <form></form> tags should be rendered when using a Layout.
            If set to False it renders the form without the <form></form> tags. Defaults to True.

        **form_error_title**: If a form has `non_field_errors` to display, they
            are rendered in a div. You can set title's div with this attribute.
            Example: "Oooops!" or "Form Errors"

        **formset_error_title**: If a formset has `non_form_errors` to display, they
            are rendered in a div. You can set title's div with this attribute.

        **include_media**: Whether to automatically include form media. Set to False if
            you want to manually include form media outside the form. Defaults to True.

    Public Methods:

        **add_input(input)**: You can add input buttons using this method. Inputs
            added using this method will be rendered at the end of the form/formset.

        **add_layout(layout)**: You can add a `Layout` object to `FormHelper`. The Layout
            specifies in a simple, clean and DRY way how the form fields should be rendered.
            You can wrap fields, order them, customize pretty much anything in the form.

    Best way to add a helper to a form is adding a property named helper to the form
    that returns customized `FormHelper` object::

        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Submit

        class MyForm(forms.Form):
            title = forms.CharField(_("Title"))

            @property
            def helper(self):
                helper = FormHelper()
                helper.form_id = 'this-form-rocks'
                helper.form_class = 'search'
                helper.add_input(Submit('save', 'save'))
                [...]
                return helper

    You can use it in a template doing::

        {% load crispy_forms_tags %}
        {% crispy form %}
    post NTFc             C   s*   i | _ g | _|d k	r&|| _| || _d S )N)attrsinputsr   build_default_layoutr   )r   r   r   r   r   __init__   s
    zFormHelper.__init__c             C   s   t |j  S )N)r   r   keys)r   r   r   r   r   r8      s    zFormHelper.build_default_layoutc             C   s   | j S )N)_form_method)r   r   r   r   form_method   s    zFormHelper.form_methodc             C   s"   |  dkrtd|  | _d S )N)getr4   zSOnly GET and POST are valid in the                     form_method helper attribute)lowerr   r;   )r   methodr   r   r   r<      s    c             C   s&   y
t | jS  tk
r    | jS X d S )N)r   _form_actionr   )r   r   r   r   form_action   s    
zFormHelper.form_actionc             C   s
   || _ d S )N)r@   )r   actionr   r   r   rA      s    c             C   s   | j S )N)_help_text_inline)r   r   r   r   help_text_inline   s    zFormHelper.help_text_inlinec             C   s   || _ | | _d S )N)rC   _error_text_inline)r   flagr   r   r   rD      s    c             C   s   | j S )N)rE   )r   r   r   r   error_text_inline   s    zFormHelper.error_text_inlinec             C   s   || _ | | _d S )N)rE   rC   )r   rF   r   r   r   rG     s    c             C   s   | j | d S )N)r7   r    )r   Zinput_objectr   r   r   	add_input  s    zFormHelper.add_inputc             C   s
   || _ d S )N)r   )r   r   r   r   r   
add_layout	  s    zFormHelper.add_layoutc             C   s   t  |_| j|_| jj|||d}| js4| js4| jrt	|j
 }t||j}xN|D ]F}| js| jrr|j
| jjs| jrT|j
| jjrT|t||||d7 }qTW t|S )zB
        Returns safe html of the rendering of the layout
        )template_pack)setZrendered_fieldsfield_templateZcrispy_field_templater   renderrender_unmentioned_fieldsrender_hidden_fieldsrender_required_fieldstupler   r:   r
   r   Z	is_hiddenZis_requiredr   r   )r   r   contextrJ   htmlr   Zleft_fields_to_renderfieldr   r   r   render_layout  s    
zFormHelper.render_layoutc                s  | j r| j  ni }| jr(| j |d< | jr<| j |d< | jrP| j |d< | jr`| j|d< || j| j| j	| j
pzd| t|| j | j | j| j| j| j | j| j| j| jd}|dkrd| j krtd	| j}|rd
  fdd|D |d< n.td| j}|r,d  fdd|D |d< | jr>| j|d< x@| j D ]2\}}||krJ|dkrJ|dsJ|||< qJW |S )zD
        Used by crispy_forms_tags to get helper attributes
        rB   idclassform_group_wrapper_classz%s/field.html)r6   disable_csrfrG   field_classrL   Z
flat_attrsform_error_titler<   form_show_errorsform_show_labelsform_tagformset_error_titlerD   include_medialabel_classuse_custom_controlZ
bootstrap4zform-horizontalzcol(-(xl|lg|md|sm))?-(\d+)zoffset%s-%sc                s    g | ]} |d  |d f qS )r   r   ).0m)offset_patternr   r   
<listcomp>K  s    z-FormHelper.get_attributes.<locals>.<listcomp>Zbootstrap_checkbox_offsetszcol-(lg|md|sm|xs)-(\d+)zcol-%s-offset-%sc                s   g | ]} | qS r   r   )rd   re   )rf   r   r   rg   Q  s    r7   )r   r7   _)r6   copyrA   stripform_id
form_classrX   rY   rG   rZ   rL   r	   r[   r<   r\   r]   r^   r_   rD   r`   ra   rb   splitrefindallr7   __dict__items
startswith)r   rJ   r6   rq   Zbootstrap_size_matchZattribute_namer,   r   )rf   r   get_attributes$  sV    




zFormHelper.get_attributes)N))r0   r1   r2   __doc__r;   r@   r   rk   rl   rX   r   r^   r[   r_   r\   rN   rO   rP   rC   rE   r]   templaterL   rY   rb   ra   rZ   r`   r9   r8   propertyr<   setterrA   rD   rG   rH   rI   r   rU   rs   r   r   r   r   r3   j   sN   J

r3   )rn   Zdjango.urlsr   r   Zdjango.utils.safestringr   Zcrispy_forms.exceptionsr   Zcrispy_forms.layoutr   Zcrispy_forms.layout_slicer   Zcrispy_forms.utilsr   r	   r
   r   r   r3   r   r   r   r   <module>   s   ^