a
    Dgr                     @   s   d dl Z d dlmZmZ d dlm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 d d
lmZ d dlmZ d dlmZ G dd dZG dd dejZG dd dejZde_ dS )    N)GenericForeignKey
GenericRel)ContentType)
connectionmodels)cached_property)capfirst)gettext_lazy)ParentalKey)ClusterableModelget_all_child_relations)ItemBase)StreamBlock)StreamFieldc                   @   sP   e Zd ZdZdd Zdd Zdd Zedd	 Zed
d Z	dd Z
dd ZdS )ReferenceGroupsa  
    Groups records in a ReferenceIndex queryset by their source object.

    Args:
        qs: (QuerySet[ReferenceIndex]) A QuerySet on the ReferenceIndex model

    Yields:
        A tuple (source_object, references) for each source object that appears
        in the queryset. source_object is the model instance of the source object
        and references is a list of references that occur in the QuerySet from
        that source object.
    c                 C   s   | dd| _d S Nbase_content_type	object_id)Zorder_byqs)selfr    r   ]/var/www/lab.imftr.de/x/nb_venv/lib/python3.9/site-packages/wagtail/models/reference_index.py__init__   s    zReferenceGroups.__init__c                 c   s   d }g }| j D ]`}||j|jfkrd|d urXtj|d }|j|d d}||fV  g }|j|jf}|| q|rtj|d }|j|d d}||fV  d S )Nr      )pk)r   base_content_type_idr   r   objects
get_for_idZget_object_for_this_typeappend)r   Zreference_fk
references	referencecontent_typeobjectr   r   r   __iter__"   s    

zReferenceGroups.__iter__c                 C   s   | j S N)_countr   r   r   r   __len__6   s    zReferenceGroups.__len__c                 C   s   | j dd  S r   )r   valuesZdistinctcountr&   r   r   r   r%   9   s    zReferenceGroups._countc                 C   s   t dd | jD S )Nc                 s   s   | ]}|j tjkV  qd S r$   )	on_deleter   PROTECT).0r    r   r   r   	<genexpr>?       z/ReferenceGroups.is_protected.<locals>.<genexpr>)anyr   r&   r   r   r   is_protected=   s    zReferenceGroups.is_protectedc                 C   s   t | S )z
        Returns the number of rows that will be returned by iterating this
        ReferenceGroups.

        Just calls len(self) internally, this method only exists to allow
        instances of this class to be used in a Paginator.
        )lenr&   r   r   r   r)   A   s    zReferenceGroups.countc                 C   s   t | | S r$   )list)r   keyr   r   r   __getitem__K   s    zReferenceGroups.__getitem__N)__name__
__module____qualname____doc__r   r#   r'   r   r%   r0   r)   r4   r   r   r   r   r      s   


r   c                   @   s   e Zd Zdd ZdS )ReferenceIndexQuerySetc                 C   s   t | S )z
        Returns a ReferenceGroups object for this queryset that will yield
        references grouped by their source instance.
        )r   r&   r   r   r   group_by_source_objectP   s    z-ReferenceIndexQuerySet.group_by_source_objectN)r5   r6   r7   r:   r   r   r   r   r9   O   s   r9   c                   @   s  e Zd ZdZejeejddZejeejddZ	ej
deddZejeejddZej
deddZe Ze Ze Ze ZdZe Ze ZG dd	 d	Zed
d Zed6d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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+d-d. Z0e+d/d0 Z1d1d2 Z2d3d4 Z3d5S )7ReferenceIndexa6  
    Records references between objects for quick retrieval of object usage.

    References are extracted from Foreign Keys, Chooser Blocks in StreamFields, and links in Rich Text Fields.
    This index allows us to efficiently find all of the references to a particular object from all of these sources.
    +)r*   Zrelated_name   z	object id)
max_lengthverbose_nameTc                   @   s   e Zd ZdgZdS )zReferenceIndex.Meta)r   r   to_content_typeto_object_idcontent_path_hashN)r5   r6   r7   Zunique_togetherr   r   r   r   Meta   s   rC   c                 C   s6   |j  }|r"tjj|d ddS tjj|ddS dS )aJ  
        Returns the ContentType record that represents the base model of the
        given model or object.

        For a model that uses multi-table-inheritance, this returns the model
        that contains the primary key. For example, for any page object, this
        will return the content type of the Page model.
        FZfor_concrete_modelN)_metaget_parent_listr   r   get_for_model)clsmodel_or_objectparentsr   r   r   _get_base_content_type   s    

z%ReferenceIndex._get_base_content_typeFc                 C   s   t |ddrdS |s0tdd |j D r0dS |j D ]T}|jr~|jr~t |ddrXq:t |jddrhq:t|tt	frxq: dS t
|dr: dS q:t|trt|D ]}| j|jddr dS qdS )a	  
        Returns True if the given model may have outbound references that we would be interested in recording in the index.


        Args:
            model (type): a Django model class
            allow_child_models (boolean): Child models are not indexable on their own. If you are looking at
                                          a child model from the perspective of indexing it through its parent,
                                          set this to True to disable checking for this. Default False.
        wagtail_reference_index_ignoreFc                 s   s   | ]}t |tV  qd S r$   )
isinstancer
   )r,   fieldr   r   r   r-      s   z4ReferenceIndex.model_is_indexable.<locals>.<genexpr>Textract_referencesallow_child_models)getattrr/   rF   
get_fieldsis_relationmany_to_onerelated_modelrN   r
   r   hasattr
issubclassr   r   model_is_indexable)rI   modelrR   rO   child_relationr   r   r   rZ      s6    

z!ReferenceIndex.model_is_indexablec                 C   s2   || j v rdS | |r.| j | | | dS )z3
        Registers the model for indexing.
        N)indexed_modelsrZ   add_register_as_tracked_modelrI   r[   r   r   r   register_model   s
    

zReferenceIndex.register_modelc                 C   s\   || j v rdS ddlm} | j | || t|D ] }| j|jddr6| |j q6dS )z
        Add the model and all of its ParentalKey-linked children to the set of
        models to be tracked by signal handlers.
        Nr   )1connect_reference_index_signal_handlers_for_modelTrQ   )tracked_modelsZwagtail.signal_handlersrb   r^   r   rZ   rW   r_   )rI   r[   rb   r\   r   r   r   r_     s    
z)ReferenceIndex._register_as_tracked_modelc                 C   s
   || j v S r$   )r]   r`   r   r   r   
is_indexed  s    zReferenceIndex.is_indexedc           
      #   s  |j  D ]8jrjrtddr.q
tjddr>q
tttfrNq
tt	r|j 
j}|j 
j}||}||}|dur
|dur
tj| }|jt|jjfV  q
ttrq
|}|durjjt|jjfV  tdr
|}|dur
fdd|D E dH  q
t|trt|D ]H}| t| }	|	D ]&  fdd D E dH  qxqZdS )a  
        Generator that scans the given object and yields any references it finds.

        Args:
            object (Model): an instance of a Django model to scan for references

        Yields:
            A tuple (content_type_id, object_id, model_path, content_path) for each
            reference found.

            content_type_id (int): The ID of the ContentType record representing
                                   the model of the referenced object

            object_id (str): The primary key of the referenced object, converted
                             to a string

            model_path (str): The path to the field on the model of the source
                              object where the reference was found

            content_path (str): The path to the piece of content on the source
                                object instance where the reference was found
        rM   FNrP   c                 3   sB   | ]:\}}}}  |j|j d | j d | fV  qdS ).N)rL   idname)r,   Zto_modelrA   
model_pathcontent_path)rI   rO   r   r   r-   k  s   

zAReferenceIndex._extract_references_from_object.<locals>.<genexpr>c              	   3   sB   | ]:\}}}}|| d |  dt  j d| fV  qdS )z.item.re   N)strrf   r,   to_content_type_idrA   rh   ri   )child_objectrelation_namer   r   r-   ~  s   
)rF   rT   rU   rV   rS   rW   rN   r
   r   r   	get_fieldct_fieldfk_fieldZvalue_from_objectr   r   r   model_classrL   rf   rj   rg   rX   rP   r   r   Zget_accessor_nameall_extract_references_from_object)
rI   r"   rp   rq   Zct_valueZfk_valuer[   valuer\   Zchild_objectsr   )rm   rI   rO   rn   r   rt     sd    








z.ReferenceIndex._extract_references_from_objectc                 C   s   t t d|S )a  
        Returns a UUID for the given content path. Used to enforce uniqueness.

        Note: MySQL has a limit on the length of fields that are used in unique keys so
              we need a separate hash field to allow us to support long content paths.

        Args:
            content_path (str): The content path to get a hash for

        Returns:
            A UUID instance containing the hash of the given content path
        z$bdc70d8b-e7a2-4c2a-bf43-2a3e3fcbbe86)uuiduuid5UUID)rI   ri   r   r   r   _get_content_path_hash  s    
z%ReferenceIndex._get_content_path_hashc              	      s  t }dd gj  D }|d |d  dd |D }dd jj jdd	d
ddddD }|t |  }i }t	j
jrd|d< jj fdd|D fi | g }| D ]*\}	\}
}|	|v rq|
|vrq|| qʈjj|d  dS )a  
        Creates or updates ReferenceIndex records for the given object.

        This method will extract any outbound references from the given object
        and insert/update them in the database.

        Note: This method must be called within a `django.db.transaction.atomic()` block.

        Args:
            object (Model): The model instance to create/update ReferenceIndex records for
        c                 S   s   g | ]}t jj|d dqS )FrE   )r   r   rH   )r,   rJ   r   r   r   
<listcomp>  s   z>ReferenceIndex.create_or_update_for_object.<locals>.<listcomp>r   rD   c                 S   s   g | ]
}|j qS r   )rf   )r,   ctr   r   r   rz     r.   c                 S   s*   i | ]"\}}}}}}||||f||fqS r   r   )r,   rf   content_type_idrl   rA   rh   ri   r   r   r   
<dictcomp>  s
   
z>ReferenceIndex.create_or_update_for_object.<locals>.<dictcomp>r   r   rf   r|   r@   rA   rh   ri   TZignore_conflictsc                    s4   g | ],\}}}} j |||||d qS ))r!   r   r   rl   rA   rh   ri   rB   )r   ry   rk   r   rI   r!   r"   r   r   rz     s   
)Zid__inN)setrt   rF   rG   r   filterr   Zvalues_listkeysr   featuresZsupports_ignore_conflictsZbulk_createitemsr   delete)rI   r"   r   Zcontent_typesZknown_content_type_idsZexisting_referencesZnew_referencesZbulk_create_kwargsZdeleted_reference_idsZreference_datar|   rf   r   r   r   create_or_update_for_object  sL    z*ReferenceIndex.create_or_update_for_objectc                 C   s$   |  |}| jj||jd  dS )z
        Deletes all outbound references for the given object.

        Use this before deleting the object itself.

        Args:
            object (Model): The model instance to delete ReferenceIndex records for
        r~   N)rL   r   r   r   r   )rI   r"   r   r   r   r   remove_for_object   s    

z ReferenceIndex.remove_for_objectc                 C   s   | j j| ||jdS )z
        Returns all outbound references for the given object.

        Args:
            object (Model): The model instance to fetch ReferenceIndex records for

        Returns:
            A QuerySet of ReferenceIndex records
        )r   r   r   r   rL   r   rI   r"   r   r   r   get_references_for_object  s    z(ReferenceIndex.get_references_for_objectc                 C   s   | j j| ||jdS )z
        Returns all inbound references for the given object.

        Args:
            object (Model): The model instance to fetch ReferenceIndex records for

        Returns:
            A QuerySet of ReferenceIndex records
        )rl   rA   r   r   r   r   r   get_references_to  s    z ReferenceIndex.get_references_toc                 C   s   |  | S )a  
        Returns all inbound references for the given object, grouped by the object
        they are found on.

        Args:
            object (Model): The model instance to fetch ReferenceIndex records for

        Returns:
            A ReferenceGroups object
        )r   r:   r   r   r   r   get_grouped_references_to/  s    z(ReferenceIndex.get_grouped_references_toc                 C   s   t j| jS r$   )r   r   r   r|   r&   r   r   r   _content_type=  s    zReferenceIndex._content_typec                 C   s   | j jS )a  
        The model name of the object from which the reference was extracted.
        For most cases, this is also where the reference exists on the database
        (i.e. ``related_field_model_name``). However, for ClusterableModels, the
        reference is extracted from the parent model.

        Example:
        A relationship between a BlogPage, BlogPageGalleryImage, and Image
        is extracted from the BlogPage model, but the reference is stored on
        on the BlogPageGalleryImage model.
        )r   rg   r&   r   r   r   
model_nameD  s    zReferenceIndex.model_namec                 C   s   | j jjjS )zL
        The model name where the reference exists on the database.
        )related_fieldr[   rF   r?   r&   r   r   r   related_field_model_nameS  s    z'ReferenceIndex.related_field_model_namec                 C   s(   z
| j jW S  ty"   tj Y S 0 d S r$   )reverse_related_fieldr*   AttributeErrorr   ZSET_NULLr&   r   r   r   r*   Z  s    
zReferenceIndex.on_deletec                 C   s*   | j d}|d }| j j|}|S )z
        The field from which the reference was extracted.
        This may be a related field (e.g. ForeignKey), a reverse related field
        (e.g. ManyToOneRel), a StreamField, or any other field that defines
        extract_references().
        re   r   )rh   splitr   rr   rF   ro   )r   model_path_components
field_namerO   r   r   r   source_fieldc  s    zReferenceIndex.source_fieldc                 C   s   t | jtjr| jjS | jS r$   )rN   r   r   ZForeignObjectRelremote_fieldr&   r   r   r   r   p  s    zReferenceIndex.related_fieldc                 C   s   | j jS r$   )r   r   r&   r   r   r   r   z  s    z$ReferenceIndex.reverse_related_fieldc           	      C   s   | j }| jd}t|tjr:|jj|d }t	|j
S t|trt	|j
 }|j}d}t|tr|j||  }t	|j}|d| 7 }|d7 }qZ|S z
|j
}W n  ty   |jdd}Y n0 t	|S dS )a   
        Returns a string describing the field that this reference was extracted from.

        For StreamField, this returns the label of the block that contains the reference.
        For other fields, this returns the verbose name of the field.
        re      r   u    → _ N)r   rh   r   rN   r   ZManyToOneRelrW   rF   ro   r   r?   r   Zstream_blockr   Zchild_blockslabelr   rg   replace)	r   rO   r   Zchild_fieldr   blockZ	block_idxZblock_labelr   r   r   r   describe_source_field  s(    





z$ReferenceIndex.describe_source_fieldc                 C   s   | j tjkrtdd| ji S | j tjkr2tdS | j tjkrPtdd| ji S | j tjkrdtdS | j tjkrxtdS t	| j dr| j 
 d d	krtd
d| ji S tdS )zr
        Returns a string describing the action that will be taken when the referenced object is deleted.
        z'the %(model_name)s will also be deletedr   zprevents deletionz)will be set to the default %(model_name)szwill do nothingzmay prevent deletiondeconstructr   zdjango.db.models.SETz7will be set to a %(model_name)s specified by the systemzwill unset the reference)r*   r   CASCADEr   r   r+   ZSET_DEFAULTZ
DO_NOTHINGZRESTRICTrX   r   r&   r   r   r   describe_on_delete  s,    	
z!ReferenceIndex.describe_on_deleteN)F)4r5   r6   r7   r8   r   Z
ForeignKeyr   r   r!   r   Z	CharFieldr   r   r@   rA   Z	TextFieldrh   ri   Z	UUIDFieldrB   r9   Z
as_managerr   rM   r   rc   r]   rC   classmethodrL   rZ   ra   r_   rd   rt   ry   r   r   r   r   r   propertyr   r   r   r   r*   r   r   r   r   r   r   r   r   r   r;   X   s   
0



j

c









	
!r;   T)!rv   Z"django.contrib.contenttypes.fieldsr   r   Z"django.contrib.contenttypes.modelsr   Z	django.dbr   r   Zdjango.utils.functionalr   Zdjango.utils.textr   Zdjango.utils.translationr	   r   Zmodelcluster.fieldsr
   Zmodelcluster.modelsr   r   Ztaggit.modelsr   Zwagtail.blocksr   Zwagtail.fieldsr   r   ZQuerySetr9   ZModelr;   rM   r   r   r   r   <module>   s&   >	    |