o 3a&M@sddlZddlmZmZddlmZmZddlmZddlm Z ddl m Z m Z m Z ddlmZmZmZGdd d e ZGd d d e Zd d ZddZddZddZddZddZddZddZGdddZdS)N)Counter defaultdict)partialreduce)chain) attrgetter)IntegrityError connections transaction) query_utilssignalssqlceZdZfddZZS)ProtectedErrorc||_t||dSN)protected_objectssuper__init__)selfmsgr __class__;/usr/lib/python3/dist-packages/django/db/models/deletion.pyr zProtectedError.__init____name__ __module__ __qualname__r __classcell__rrrrr rcr)RestrictedErrorcrr)restricted_objectsrr)rrr#rrrrrzRestrictedError.__init__rrrrrr"r!r"cCsH|j||jj|j|jdd|jr t|jjs"||d|dSdSdS)NF)source source_attrnullablefail_on_restricted) collect remote_fieldmodelnamenullr featurescan_defer_constraint_checksadd_field_update collectorfieldsub_objsusingrrrCASCADEs r5cCs$td|jjj|djj|jf|)NzoCannot delete some instances of model '%s' because they are referenced through a protected foreign key: '%s.%s'r)rr)r*rrr+r0rrrPROTECT sr6cCs"|||||jj|jdSr)add_restricted_objectsadd_dependencyr)r*r0rrrRESTRICT*s r9cs4tr fdd}nfdd}fdd|_|S)Ncs|||dSrr/r0valuerr set_on_delete1szSET..set_on_deletecs|||dSrr:r0r;rrr=4cs dfifS)Nzdjango.db.models.SETrrr;rr6s zSET..)callable deconstruct)r<r=rr;rSET/s  rBcCs||d|dSrr:r0rrrSET_NULL:r>rCcCs||||dSr)r/ get_defaultr0rrr SET_DEFAULT>srEcCsdSrrr0rrr DO_NOTHINGBsrFcCsdd|jddDS)Ncss,|]}|jr|js|js|jr|VqdSr) auto_createdconcrete one_to_one one_to_many).0frrr Is z4get_candidate_relations_to_delete..T)include_hidden) get_fields)optsrrr!get_candidate_relations_to_deleteFs rQc@seZdZddZd"ddZd#ddZd d Zd d Zd dZddZ ddZ d$ddZ ddZ   d%ddZ ddZddZddZd d!ZdS)& CollectorcCsD||_tt|_tttt|_tttt|_g|_tt|_dSr) r4rsetdatar field_updatesr# fast_deletes dependencies)rr4rrrrPs  zCollector.__init__NFc Csf|sgSg}|dj}|j|}|D] }||vr||q|||dur1|s1|j|||d|S)a7 Add 'objs' to the collection of objects to be deleted. If the call is the result of a cascade, 'source' should be the model that caused it, and 'nullable' should be set to True if the relation can be null. Return a list of all objects that were not already collected. rNreverse_dependency)rrTappendupdater8) robjsr$r&rYnew_objsr* instancesobjrrraddcs     z Collector.addcCs>|r||}}|j|jj|jj|j||jdSr)rW_metaconcrete_modelr`rT setdefaultdefault_factory)rr* dependencyrYrrrr8{s zCollector.add_dependencycCs.|sdS|dj}|j|||f|dS)z Schedule a field update. 'objs' must be a homogeneous iterable collection of model instances (e.g. a QuerySet). Nr)rrUr[)rr2r<r\r*rrrr/s zCollector.add_field_updatecCs*|r|dj}|j|||dSdS)Nr)rr#r[)rr2r\r*rrrr7s z Collector.add_restricted_objectscs4||jvrfdd|j|D|j|<dSdS)Ncsi|] \}}||qSrr)rKr2itemsr\rr sz?Collector.clear_restricted_objects_from_set..)r#rf)rr*r\rrgr!clear_restricted_objects_from_sets   z+Collector.clear_restricted_objects_from_setcCsB||jvrt|jdd|j|Dd}|||dSdS)NcSsg|] }|D]}|jqqSrpk)rKr\r_rrr s zDCollector.clear_restricted_objects_from_queryset..)pk__in)r#rSfiltervaluesri)rr*qsr\rrr&clear_restricted_objects_from_querysets    z0Collector.clear_restricted_objects_from_querysetcCstj|p tj|Sr)r pre_delete has_listeners post_delete)rr*rrr_has_signal_listenerss  zCollector._has_signal_listenerscsr jjtur dSt|dr|jj}nt|dr"t|dr"|j}ndS||r+dS|j}tfdd|jjj DoStddt |DoSt dd|j D S) a Determine if the objects in the given queryset-like or single object can be fast-deleted. This can be done if there are no cascades, no parents and no signal listeners for the object class. The 'from_field' tells where we are coming from - we need this to determine if the objects are in fact to be deleted. Allow also skipping parent -> child -> parent chain preventing fast delete of the child. Frar* _raw_deletec3s|]}|kVqdSrr)rKlink from_fieldrrrMsz,Collector.can_fast_delete..css|] }|jjjtuVqdSr)r2r) on_deleterF)rKrelatedrrrrMs  css|]}t|dVqdS)bulk_related_objectsN)hasattrrKr2rrrrMs)r)rzr5r}rar*ruallrbparentsrorQanyprivate_fields)rr\ryr*rPrrxrcan_fast_deletes"     zCollector.can_fast_deletecsZdd|D}tt|jj|dtkr*fddtdtDSgS)zT Return the objs in suitably sized batches for the used connection. cSg|]}|jqSr)r+r~rrrrlz-Collector.get_del_batches..csg|] }||qSrr)rKiconn_batch_sizer\rrrlsr)maxr r4opsbulk_batch_sizelenrange)rr\fields field_namesrrrget_del_batchess  zCollector.get_del_batchesTc  sl||r |j|dS|j||||d} | sdS| dj} |sF| jj} | jjD]rEfdd| D} |j | | j j ddddq+|sJdS|rSt | j } tt}tt}t| jD]}|rj|j| vrjq`|j}|j jtkrtq`|j}|j||d r|||q`|| |g}|D]\}|||g|}|jjs||st td d t|jD}|jt|}|rz |j ||||jWqt y}zd |jj!|j"f}|||j#7<WYd}~qd}~wwqq`|rt d | j!d$|ft t||%D]\}}|| |}|D]}||||}|j|qq| jj&D]}t'|drC|(| |j}|j || dddq+|r|j)%D] \}}|*||qM|jD] }|+|j|q\|j,rtt}|j,%D]"\}}|%D]\}}|rd |j!|j"f}|||7<q~qv|rt-d| j!d$|ft t|dSdSdS)a Add 'objs' to the collection of objects to be deleted as well as all parent instances. 'objs' must be a homogeneous iterable collection of model instances (e.g. a QuerySet). If 'collect_related' is True, related objects will be handled by their respective on_delete handler. If the call is the result of a cascade, 'source' should be the model that caused it and 'nullable' should be set to True, if the relation can be null. If 'reverse_dependency' is True, 'source' will be deleted before the current model, rather than after. (Needed for cascading to parent models, the one case in which the cascade follows the forwards direction of an FK rather than the reverse direction.) If 'keep_parents' is True, data of parent model's will be not deleted. If 'fail_on_restricted' is False, error won't be raised even if it's prohibited to delete such objects due to RESTRICT, that defers restricted object checking in recursive calls where the top-level call may need to collect more objects to determine whether restricted ones can be deleted. NrXrcsg|]}t|jqSr)getattrr+rKr_ptrrrrlz%Collector.collect..FT)r$r%collect_relatedrYr'rxcss"|] }dd|jjDVqdS)css|]}|jVqdSr)attname)rKrfrrrrM#sz.Collector.collect...N)r2foreign_related_fields)rKrelrrrrM"s  z$Collector.collect..z'%s.%s'zhCannot delete some instances of model %r because they are referenced through protected foreign keys: %s.z, r|)r$r&r'ziCannot delete some instances of model %r because they are referenced through restricted foreign keys: %s.).rrVrZr`rrarbrror(r) related_namerSget_parent_listrlistrQr*r2rzrF related_modelrrelated_objectsqueryselect_relatedrur from_iterableonlytupler4rrr+rjoinrfrr}r|rTrirqr#r")rr\r$r&rr%rY keep_parentsr'r]r*rb parent_objsrmodel_fast_deletesrr{r2rbatchesbatchr3referenced_fieldserrorkeyrelated_fieldsr^rpr#rrrrr(s            zCollector.collectcs.ttjfdd|D}|j|j|S)zQ Get a QuerySet of the related model to objs via related fields. c3s*|]}tjdid|jiVqdS)z%s__inNr)r Qr+)rK related_fieldrgrrrM^s  z,Collector.related_objects..)roperatoror_ _base_managerr4rn)rrrr\ predicaterrgrrZszCollector.related_objectsccs.|jD]\}}|D]}||fVq qdSr)rTrf)rr*r^r_rrrinstances_with_modelds  zCollector.instances_with_modelcsg}t}tj}t|t|krGd}|D]$}||vrqj|jj}|r,||s:| || |jjd}q|s?dSt|t|ksfdd|D_dS)NFTcsi|]}|j|qSr)rT)rKr*rrrrhyrz"Collector.sort..) rSrrTrrWgetrarb differencerZr`)r sorted_modelsconcrete_modelsmodelsfoundr*rWrrrsortis$   zCollector.sortc Cs|jD]\}}t|tdd|j|<q|t}t|jdkrgt|dkrgt|d}||rgt |j t ||jg|j }Wdn1sQwYt||jjjd||jj|ifSt j|j dd|D]\}}|jjstjj|||j dqt|jD]}|j|j d}|r||jjj|7<q|jD]$\}}|D]\\} } }t |} | d d |D| j | i|j qq|j!D]}|"q|jD]8\}}t |} d d |D} | | |j }|r||jj|7<|jjs|D] }tj#j|||j dqqWdn 1s wY|j!D]}|D]\\} } }|D] }t|| j| q8q0q*|jD]\}}|D] }t||jjjdqRqLt$|!t%|fS) Nrk)rrrF)r4 savepoint)senderinstancer4)r4cSrrrjrrrrrlrz$Collector.delete..cSrrrjrrrrrlr)&rTrfsortedrrrrrrr mark_for_rollback_on_errorr4r DeleteQuery delete_batchrksetattrrarlabelatomicrrGr rrsendrVrvr*rU UpdateQuery update_batchr+roreversertsumdict) rr*r^deleted_counterrcountr_rpinstances_for_fieldvaluesr2r<rpk_listrrrdelete{st         (zCollector.delete)NFF)Fr)NFTNFFT)rrrrr`r8r/r7rirqrurrr(rrrrrrrrrROs(    $    rR)r collectionsrr functoolsrr itertoolsrr django.dbrr r django.db.modelsr r r rr"r5r6r9rBrCrErFrQrRrrrrs$