o
    »ïØej  ã                   @   s2   d Z ddlmZ ddlmZ G dd„ dejƒZdS )a÷  
tl;dr: See FutureModelForm's docstring.

Many apps provide new related managers to extend your django models with. For
example, django-tagulous provides a TagField which abstracts an M2M relation
with the Tag model, django-gm2m provides a GM2MField which abstracts an
relation, django-taggit provides a TaggableManager which abstracts a relation
too, django-generic-m2m provides RelatedObjectsDescriptor which abstracts a
relation again.

While that works pretty well, it gets a bit complicated when it comes to
encapsulating the business logic for saving such data in a form object. This is
three-part problem:

- getting initial data,
- saving instance attributes,
- saving relations like reverse relations or many to many.

Django's ModelForm calls the model field's ``value_from_object()`` method to
get the initial data. ``FutureModelForm`` tries the ``value_from_object()``
method from the form field instead, if defined. Unlike the model field, the
form field doesn't know its name, so ``FutureModelForm`` passes it when calling
the form field's ``value_from_object()`` method.

Django's ModelForm calls the form field's ``save_form_data()`` in two
occasions:

- in ``_post_clean()`` for model fields in ``Meta.fields``,
- in ``_save_m2m()`` for model fields in ``Meta.virtual_fields`` and
  ``Meta.many_to_many``, which then operate on an instance which as a PK.

If we just added ``save_form_data()`` to form fields like for
``value_from_object()`` then it would be called twice, once in
``_post_clean()`` and once in ``_save_m2m()``. Instead, ``FutureModelForm``
would call the following methods from the form field, if defined:

- ``save_object_data()`` in ``_post_clean()``, to set object attributes for a
  given value,
- ``save_relation_data()`` in ``_save_m2m()``, to save relations for a given
  value.

For example:

- a generic foreign key only sets instance attributes, its form field would do
  that in ``save_object_data()``,
- a tag field saves relations, its form field would do that in
  ``save_relation_data()``.
é    )Úchain)Úformsc                       sJ   e Zd ZdZ‡ fdd„Z‡ fdd„Zdd„ Zdd	d
„Zedd„ ƒZ	‡  Z
S )ÚFutureModelForma/  
    ModelForm which adds extra API to form fields.

    Form fields may define new methods for FutureModelForm:

    - ``FormField.value_from_object(instance, name)`` should return the initial
      value to use in the form, overrides ``ModelField.value_from_object()``
      which is what ModelForm uses by default,
    - ``FormField.save_object_data(instance, name, value)`` should set instance
      attributes. Called by ``save()`` **before** writing the database, when
      ``instance.pk`` may not be set, it overrides
      ``ModelField.save_form_data()`` which is normally used in this occasion
      for non-m2m and non-virtual model fields.
    - ``FormField.save_relation_data(instance, name, value)`` should save
      relations required for value on the instance. Called by ``save()``
      **after** writing the database, when ``instance.pk`` is necessarily set,
      it overrides ``ModelField.save_form_data()`` which is normally used in
      this occasion for m2m and virtual model fields.

    For complete rationale, see this module's docstring.
    c                    sN   t t| ƒj|i |¤Ž | j ¡ D ]\}}t|dƒsq| | j|¡| j|< qdS )z:Override that uses a form field's ``value_from_object()``.Úvalue_from_objectN)	Úsuperr   Ú__init__ÚfieldsÚitemsÚhasattrr   ÚinstanceÚinitial)ÚselfÚargsÚkwargsÚnameÚfield©Ú	__class__© úU/var/www/html/Testing_prj/Navya-Bakers/venv/lib/python3.10/site-packages/dal/forms.pyr   N   s   
üzFutureModelForm.__init__c              	      sL   t t| ƒ ¡  | j ¡ D ]\}}t|dƒsq| | j|| j 	|d¡¡ qdS )ú;Override that uses the form field's ``save_object_data()``.Úsave_object_dataN)
r   r   Ú_post_cleanr   r	   r
   r   r   Úcleaned_dataÚget)r   r   r   r   r   r   r   X   s   
ýüzFutureModelForm._post_cleanc           
      C   sè   | j }| jj}| jj}| jj}g }| j ¡ D ]\}}t|dƒs q| | j||| ¡ | |¡ qt	|dg ƒ}|s>t	|dg ƒ}t
|j|ƒD ]-}	|	j|v rLqDt|	dƒsRqD|rZ|	j|vrZqD|rb|	j|v rbqD|	j|v rq|	 | j||	j ¡ qDdS )r   Úsave_relation_dataÚvirtual_fieldsÚprivate_fieldsÚsave_form_dataN)r   Ú_metaÚexcluder   r   r	   r
   r   ÚappendÚgetattrr   Úmany_to_manyr   r   )
r   r   r    r   ÚoptsÚhandledr   r   r   Úfr   r   r   Ú	_save_m2mf   s<   
ý


€ôzFutureModelForm._save_m2mTc                 C   sZ   | j rtd| jjj| jjjrdf ƒ‚df ƒ‚|r&| j ¡  |  ¡  | jS | j| _	| jS )z"Backport from Django 1.9+ for 1.8.z8The %s could not be %s because the data didn't validate.ÚcreatedÚchanged)
ÚerrorsÚ
ValueErrorr   r   Úobject_nameÚ_stateÚaddingÚsaver'   Úsave_m2m)r   Úcommitr   r   r   r/      s    þÿþÿ
ÿzFutureModelForm.savec                    s   ‡ fdd„ˆ j d  ¡ D ƒS )zô
        Create a list of url patterns, to be called in url.py.

        Example::

            urlpattern.append(*ModelForm.as_url())

        Iterate over the fields to call the as_url() method from the
        GenericForeignKeyField
        c                    s&   g | ]\}}t |jd ƒr| ˆ ¡‘qS )Úas_url)r
   r   r2   )Ú.0ÚkeyÚvalue©Úclsr   r   Ú
<listcomp>®   s    
ýÿz+FutureModelForm.as_urls.<locals>.<listcomp>Údeclared_fields)Ú__dict__r	   r6   r   r6   r   Úas_urls¢   s   
þzFutureModelForm.as_urls)T)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r'   r/   Úclassmethodr;   Ú__classcell__r   r   r   r   r   7   s    

)r   N)r?   Ú	itertoolsr   Údjangor   Ú	ModelFormr   r   r   r   r   Ú<module>   s    1