o 3a@sddlZddlZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZmZdd lmZGd d d ZdS)N)chain)settings)models) operations) Migration)AlterModelOptions)MigrationOptimizer)MigrationQuestioner)COMPILED_REGEX_TYPE RegexObject)stable_topological_sortc@steZdZdZdXddZdYddZddZd d ZdZd d Zd dZ ddZ e ddZ dXddZ ddZddZddZd[ddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Z dd?Z"d@dAZ#dBdCZ$dDdEZ%dFdGZ&dHdIZ'dJdKZ(dLdMZ)dNdOZ*dPdQZ+dXdRdSZ,dTdUZ-e.dVdWZ/dS)\MigrationAutodetectora  Take a pair of ProjectStates and compare them to see what the first would need doing to make it match the second (the second usually being the project's current state). Note that this naturally operates on entire projects at a time, as it's likely that changes interact (for example, you can't add a ForeignKey without having a migration to add the table it depends on first). A user interface may offer single-app usage if it wishes, with the caveat that it may not always be possible. NcCs.||_||_|p t|_dd|jD|_dS)NcSsh|]\}}|qSr).0appmodelrrC/usr/lib/python3/dist-packages/django/db/migrations/autodetector.py !z1MigrationAutodetector.__init__..) from_stateto_stater questionerr existing_apps)selfrrrrrr__init__s zMigrationAutodetector.__init__cCs.|||}||||}|r|||}|S)z Main entry point to produce a list of applicable changes. Take a graph to base names on and an optional set of apps to try and restrict to (restriction is not guaranteed) )_detect_changesarrange_for_graph _trim_to_apps)rgraph trim_to_apps convert_appsmigration_namechangesrrrr"#s  zMigrationAutodetector.changescst|trfdd|DSt|trtfdd|DSt|tr.fdd|DSt|tjrB|j|j |j fSt|t rKt |St|t rR|St|dr|}t|tjrg|dd }|\}}}|fd d|Dfd d|DfS|S) z Recursive deconstruction for a field and its arguments. Used for full comparison for rename/alter; sometimes a single-level deconstruction will not compare correctly. cg|]}|qSrdeep_deconstructrvaluerrr 6z:MigrationAutodetector.deep_deconstruct..c3s|]}|VqdSNr$r&r(rr 8sz9MigrationAutodetector.deep_deconstruct..ci|] \}}||qSrr$rkeyr'r(rr : z:MigrationAutodetector.deep_deconstruct.. deconstructNcr#rr$r&r(rrr)Nr*cr-rr$r.r(rrr0Or1) isinstancelisttupledictitems functoolspartialfuncr%argskeywordsr r typehasattrr2rField)robj deconstructedpathr<kwargsrr(rr%/s4             z&MigrationAutodetector.deep_deconstructcCsJg}t|D]\}}||}|jr|jjr|dd=||q|S)z Return a definition of the fields that ignores field names and what related fields actually relate to. Used for detecting renames (as the related fields change during renames). to)sortedr8r% remote_fieldrappend)rfields fields_defnamefielddeconstructionrrronly_relation_agnostic_fieldsWs   z3MigrationAutodetector.only_relation_agnostic_fieldscCsi|_i|_i|_|jj|_|jj|_t |_ t |_ t |_ t |_ t |_t |_|jjD]3\}}|j||}|jjsG|j ||fq/||jjvrb|jjrZ|j ||fq/|j ||fq/|jjD]9\}}|j||}|jjs|j||fqg||jjvs|r||vr|jjr|j||fqg|j ||fqg|||||||||| |!|"|#|$|%|&|'|(|)|*|+|,|-|.|/||0|j1S)aX Return a dict of migration plans which will achieve the change from from_state to to_state. The dict has app labels as keys and a list of migrations as values. The resulting migrations aren't specially named, but the names do matter for dependencies inside the set. convert_apps is the list of apps to convert to use migrations (i.e. to make initial migrations for, in the usual case) graph is an optional argument that, if provided, can help improve dependency generation and avoid potential circular dependencies. )2generated_operationsaltered_indexesaltered_constraintsr concrete_appsold_appsrappsnew_appssetold_model_keysold_proxy_keysold_unmanaged_keysnew_model_keysnew_proxy_keysnew_unmanaged_keysr get_model_metamanagedadd real_appsproxygenerate_renamed_models_prepare_field_lists_generate_through_model_mapgenerate_deleted_modelsgenerate_created_modelsgenerate_deleted_proxiesgenerate_created_proxiesgenerate_altered_optionsgenerate_altered_managerscreate_altered_indexescreate_altered_constraintsgenerate_removed_constraintsgenerate_removed_indexesgenerate_renamed_fieldsgenerate_removed_fieldsgenerate_added_fieldsgenerate_altered_fields&generate_altered_order_with_respect_to generate_altered_unique_togethergenerate_altered_index_togethergenerate_added_indexesgenerate_added_constraintsgenerate_altered_db_table_sort_migrations_build_migration_list_optimize_migrations migrations)rr ralmnrrrrresv     z%MigrationAutodetector._detect_changescs`jj@_jj@_jj@_i_ fddjD_ fddjD_ dS)z Prepare field lists and a list of the fields that used through models in the old state so dependencies can be made from the through model deletion to the field that uses it. cs@h|]\}}jj|j||f|fjD]}|||fqqSr)rrrenamed_modelsgetrJr app_label model_name field_namer(rrrsz=MigrationAutodetector._prepare_field_lists..cs2h|]\}}jj||fjD]}|||fqqSr)rrrJrr(rrrsN) rXr[kept_model_keysrYr\kept_proxy_keysrZr]kept_unmanaged_keys through_usersold_field_keysnew_field_keysr(rr(rres   z*MigrationAutodetector._prepare_field_listscCst|jD]L\}}|j||f|}|jj||f}|jD]3}|j||j |}t |drPt |j ddrP|j jj jsP|j jj j|j jj jf}|||f|j|<qqdS)zThrough model map generation.rHthroughN)rGrXrrrrrJrTr^r_ get_fieldr?getattrrHr auto_createdrrr)rrrold_model_nameold_model_stater old_field through_keyrrrrfs    z1MigrationAutodetector._generate_through_model_mapcCsH|ddkr |dfStt|dd\}}||f|dddfS) zp Return the resolved dependency and a boolean denoting whether or not it was swappable. r __setting__Fr3.rENT)rrsplitlower) dependencyresolved_app_labelresolved_object_namerrr_resolve_dependencys z)MigrationAutodetector._resolve_dependencyc Cs\i|_tdd|jD}d}|r,t|jD]}g}t}t|j|D]}d}t} |jD]v} | } || \} } | d|kr|j | dgD] } | | | rWd}nqK|s\nL| rj| | d| dfq1| d|jvr| | d|j| ddj fq1|r|r| | dr| | | ddq1| | ddfq1d}q1|r|||| |j|d=q'|s|r|j|r|rtd tfggd }|d t|j |gd|}t||_||_||jv|_|j|g|d}q||j||j|<qtd d|jD}||kr&|sd}ntd |j|}|sdSdS)ag Chop the lists of operations up into migrations with dependencies on each other. Do this by going through an app's list of operations until one is found that has an outgoing dependency that isn't in another app's migration yet (hasn't been chopped off its list). Then chop off the operations before it into a migration and move onto the next app. If the loops completes without doing anything, there's a circular dependency (which _should_ be impossible as the operations are all split at this point so they can't depend and be depended on). cs|]}t|VqdSr+lenrxrrrr,z>MigrationAutodetector._build_migration_list..FTrr3 __first__r)r dependencieszauto_%icsrr+rrrrrr,Grz)Cannot resolve operation dependencies: %rN)r~sumrPvaluesrGrWr5 _auto_depsrrcheck_dependencyrarL leaf_nodesrIupdater>rrrrrinitial setdefault ValueError)rrnum_ops chop_moderchoppedr operationdeps_satisfiedoperation_dependenciesdep original_depis_swappable_depother_operationsubclassinstance new_num_opsrrrr|sl    $        z+MigrationAutodetector._build_migration_listcCst|jD]=\}}dd|D}|D]'}|jD]!}||d}|d|kr:|D]}|||r9|||q*qqt|||j|<qdS)z{ Reorder to make things possible. Reordering may be needed so FKs work nicely inside the same app. cSsi|]}|tqSr)rW)roprrrr0Vrz:MigrationAutodetector._sort_migrations..rN)rGrPr8rrrrar )rropsdependency_graphrrop2rrrr{Os    z&MigrationAutodetector._sort_migrationscCs|jD]\}}t||ddD] \}}|j||jfqq|jD]}|D] }tt|j|_q*q&|jD]\}}|D] }t |j ||_ qAq;dS)Nr3) r~r8ziprrIrLrr5rWroptimizer)rrr~m1m2 migrationrrrr}dsz*MigrationAutodetector._optimize_migrationscsddurddurt|tjo|jdkSddurZddurZt|tjoA|jdkoAtfdd|jDpYt|tjoY|jdkoY|jdkSddur~ddur~t|tj o}|jdko}|jdkSddurddurt|tj o|jdkSddurdd krt|tj o|jdko|jdkSddurdd krt|tj o|jdko|j pd dkSddurdd krt|tjtjfo|jdkStd f)zn Return True if the given operation depends on the given dependency, False otherwise. rENTr3c3s |] \}}d|kVqdS)rENr)rryrrrr,sz9MigrationAutodetector.check_dependency..Falterorder_wrt_unsetfoo_together_changezCan't handle dependency %r)r4r CreateModel name_lowerranyrJAddFieldmodel_name_lower RemoveField DeleteModel AlterFieldAlterOrderWithRespectToorder_with_respect_toAlterUniqueTogetherAlterIndexTogetherr)rrrrrrrtsX       z&MigrationAutodetector.check_dependencyFcCs@|pg|_|r|j|gd|dS|j|g|dS)Nr)rrPrinsertrI)rrrr beginningrrr add_operations z#MigrationAutodetector.add_operationcCszB|j|d|d}dd|jD}d|d|df}|jjs3d|vs3d|vs3tj|kr@d|dd|dfWSW|StyLY|Sw) z| Place potential swappable models first in lists of created models (only real way to solve #22783). rr3cSsg|]}|jqSr)__name__)rbaserrrr)sz=MigrationAutodetector.swappable_first_key..%s.%s AbstractUserAbstractBaseUser___) rVr^ __bases__r_ swappablerAUTH_USER_MODELr LookupError)ritemr base_namesstring_versionrrrswappable_first_keys  z)MigrationAutodetector.swappable_first_keycCsLi|_i|_|j|j}t|D]\}}|jj||f}||j}|j|j}|D]x\}}||kr|j j||f} || j} || kr|j | |r|j ||j} g} | D] } | jrf| || qY|j|tj| j|jd| d||j||f<d| j| jf}d|j|jf|j|<|j||f|j||fnq*qdS)z Find any renamed models, generate the operations for them, and remove the old entry from the model lists. Must be run before other model-level generation. )old_namenew_namerrN)rrenamed_models_relr[rXrGrrrOrJrrask_rename_modelrVr^r_ get_fields is_relationextend!_get_dependencies_for_foreign_keyrr RenameModelrLrrremovera)r added_modelsrr model_statemodel_fields_defremoved_models rem_app_labelrem_model_namerem_model_staterem_model_fields_def model_optsrrMrenamed_models_rel_keyrrrrdsR       z-MigrationAutodetector.generate_renamed_modelsc s|j|jB}|j|}|j|}tt||jddt||jdd}|D]\|jjf}|j j }id}|j D],}|j rk|j jrY|jrP|j j}n |j jsY||j<t|j ddrk|j jj jsk||j<q?|jD]}|j jrz||j<t|j ddr|j jj js||j<qo|jd} |jd} |jdd} |jdd} |jd d} dd fg}|jD]Q}t|tr d |vr |d d \}}|||ddf|jj||f}|jj||f}|r |r t|j !|j "|j }|D] }||||d fqq|r||j j#|j j$ddf|j%t&j'|jfd d|j (D|j|j|j)d|dd|j*s>q#t(D]%\}}|+|}|ddf|j%t&j,||dt-t|dqD| r|j%t&j.| d| dfddfgdfddtD}|ddf| D]}|j%t&j/|d|dq| D]}|j%t&j0|d|dq| r|j%t&j1| d|d| r|j%t&j2| d|df|j3vr |j4D]}|j%|j5j j#t&j6|j5j j$|j7j|j7dddfgdqq#dS)a Find all new models (both managed and unmanaged) and make create operations for them as well as separate operations to create any foreign key or M2M relationships (these are optimized later, if possible). Defer any model options that refer to collections of fields that might be deferred (e.g. unique_together, index_together). T)r/reverseNrindexes constraintsunique_togetherindex_togetherrFrr3csg|] }|dvr|qS)rrrd)related_fieldsrrr)KszAMigrationAutodetector.generate_created_models..rLrJoptionsbasesmanagers)rr)rrLrMrrLrcsg|]}|dfqS)Tr)rrL)rrrrr)ts rindexr constraintrLrrLr)8rXrZr[r]rrGrrrrVr^r_ local_fieldsrHr primary_key parent_linkrLrrrlocal_many_to_manyrpoprr4strrrIrrrWrJ difference intersectionr object_namerrrr8r r`rrr5rAddIndex AddConstraintrrrYrelated_objects related_modelrrM)rold_keysradded_unmanaged_modelsall_added_modelsrrprimary_key_relrMrrrrrrrbase_app_label base_nameold_base_model_statenew_base_model_stateremoved_base_fieldsremoved_base_fieldrLrelated_dependenciesr rrelated_objectr)rrrrrhs,                            z-MigrationAutodetector.generate_created_modelsc Cs|j|j}t|D]O\}}|jj||f}|jdsJ||ddfg}|jD]}t|t rDd|vrD| dd\}}| ||ddfq(|j |t j|jg|j|j|jd|dq dS) z Make CreateModel statements for proxy models. Use the same statements as that way there's less code duplication, but for proxy models it's safe to skip all the pointless field stuff and chuck out an operation. rcNFrr3Trr)r\rYrGrrrrrr4rrrIrrrrLr ) raddedrrrrrr"r#rrrrjs.   z.MigrationAutodetector.generate_created_proxiesc Cs8|j|jB}|j|}|j|}tt|t|}|D]\}}|jj||f}|j ||}i} |j j D] } | j rT| j j rB| | | j<t| j ddrT| j jj jsT| | | j<q4|j jD]} | j j rd| | | j<t| j ddrv| j jj jsv| | | j<qY|jdd} |jdd} | r||tj|dd| r||tj|ddt| D] } ||tj|| dqg}|j jD]%}|jj j}|jj j}|jj}||||df|j s||||d fqt| D] } |||| dfq|j!"||j#f}|r||d |d |d df|j|tj$|jd t%t&|dqdS)a Find all deleted models (managed and unmanaged) and make delete operations for them as well as separate operations to delete any foreign key or M2M relationships (these are optimized later, if possible). Also bring forward removal of any model options that refer to collections of fields - the inverse of generate_created_models(). rNrrrrrrLFrrr3rErLr)'r[r]rXrZrrGrrrTr^r_rrHrrLrrrrrrrrrrrrrrrrMrI many_to_manyrrrrr5rW)rnew_keysdeleted_modelsdeleted_unmanaged_modelsall_deleted_modelsrrrrrrMrrrLrr)related_object_app_labelrr through_userrrrrgs                z-MigrationAutodetector.generate_deleted_modelscCsX|j|j}t|D]\}}|jj||f}|jdsJ||tj |j dq dS)z*Make DeleteModel options for proxy models.rcr,N) rYr\rGrrrrrrrrL)rdeletedrrrrrrri%s z.MigrationAutodetector.generate_deleted_proxiesc Csi|_t|j|jD]\}}}|j||f|}|jj||f}|j ||j |}| |}t|j|jD]\}} } ||kr| |kr|j | } | | } |jrq|jjrqd| dvrq| dd} | |jvrq|j| | dd<| | | d}| |ks| dd|ddkrt| d|d|dkr|j|| ||r||tj|| |d|j|| | f|j|||f| |j|||f<nq9q dS)zWork out renamed fields.rFrEr3r) db_column)rrrN)renamed_fieldsrGrrrrrrrVr^r_rr%rJrHrrset_attributes_from_nameget_attname_columnr7r ask_renamerr RenameFieldrra)rrrrrrrM field_decrrrem_field_namer old_field_dec old_rel_to old_db_columnrrrrq2sD       z-MigrationAutodetector.generate_renamed_fieldscC.t|j|jD] \}}}||||qdS)zMake AddField operations.N)rGrr_generate_added_fieldrrrrrrrrsXz+MigrationAutodetector.generate_added_fieldscCs|j||j|}g}|jr|jjr|||tj tj tj f}|j p;| p;|jp;|jo3|jp;t||o;|j}|s[|}t||rS|jrS|j|||_n|j|||_|j|tj||||d|ddS)NrrLrMpreserve_defaultr)rVr^r_rrHrrrr DateField DateTimeField TimeFieldnull has_defaultr-blankempty_strings_allowedr4auto_nowclone auto_now_addrask_auto_now_add_additiondefaultask_not_null_additionrrr)rrrrrMr time_fieldsrErrrrA]s2  z+MigrationAutodetector._generate_added_fieldcCr@)zMake RemoveField operations.N)rGrr_generate_removed_fieldrBrrrrr|rCz-MigrationAutodetector.generate_removed_fieldscCs2|j|tj||d|||df|||dfgddS)Nr+rrr)rrrrBrrrrTs   z-MigrationAutodetector._generate_removed_fieldc sxtjj@D]0\}}}j||f|}j|||f|}j||j |}j ||j |}g}t |drt |j ddr|j jjj|j jjjfjvr\|j j|j _t |j dd} | r{| f} | jvr{|j j|j _|j j|j _t |dd} | r||ftfdd| D|_tfdd|jD|_||t |drt |j d dr|j jjj|j jjjfjvr|j j|j _|} |} | | kr9|jo|j}|j o|j }|s|r+d }|jr|js|s|js|}j||}|tj ur||_!d }n|}j"|t#j$||||d |d q%|||&|||qdS)zp Make AlterField operations, or possibly RemovedField/AddField if alter isn's possible. rHrNr from_fieldsc g|] }j|f|qSrr6r)r from_field)from_rename_keyrrrr)zAMigrationAutodetector.generate_altered_fields..crVrrW)rto_field) rename_keyrrrr)rZrTFrDr)'rGrrrrr6rTr^r_rrVr?rrHrrrrr6rU to_fieldsrrrr%r-rIrJrNrask_not_null_alterationr NOT_PROVIDEDrQrrrrTrA)rrrrrold_field_namer new_fieldrremote_field_nameto_field_rename_keyrUr= new_field_decboth_m2m neither_m2mrErM new_defaultr)rYr\rrrts                      z-MigrationAutodetector.generate_altered_fieldsc tjj}t|jD]F\}}|j||f|}|jj||f}|j j||f}|j ||j |fddD}fddD}|j ||f||diq dS)Ncg|]}|vr|qSrrridx) old_indexesrrr)z@MigrationAutodetector.create_altered_indexes..crirrrj) new_indexesrrr)rm) added_indexesremoved_indexes) rr option_namerGrrrrrrrrQr) rrqrrrrnew_model_stateadd_idxrem_idxr)rnrlrrm  z,MigrationAutodetector.create_altered_indexesc C@|jD]\\}}}|dD] }||tj||dqqdS)Nror )rQr8rrrrrr alt_indexesr rrrrx z,MigrationAutodetector.generate_added_indexesc CB|jD]\\}}}|dD]}||tj||jdqqdS)Nrpr+)rQr8rr RemoveIndexrLrwrrrrp z.MigrationAutodetector.generate_removed_indexesc rh)Ncrirrrc)old_constraintsrrr)rmzDMigrationAutodetector.create_altered_constraints..crirrr})new_constraintsrrr)rm)added_constraintsremoved_constraints) rrrqrGrrrrrrrrRr) rrqrrrrrradd_constraintsrem_constraintsr)rrrrn ruz0MigrationAutodetector.create_altered_constraintsc Crv)Nrr )rRr8rrrrrralt_constraintsrrrrryryz0MigrationAutodetector.generate_added_constraintsc Crz)Nrr+)rRr8rrRemoveConstraintrLrrrrro)r|z2MigrationAutodetector.generate_removed_constraintscCst|dd}|durd}|}n |jjjj}|jjjj}||ddfg}t|jddr@|jjjjs@||jjjj|jjjjddf|S)Nswappable_settingrTr) rrHrr_rrrrrI)rrMr dep_app_labeldep_object_namerrrrr4s     z7MigrationAutodetector._get_dependencies_for_foreign_keyc s|j}tjD]}\jf}jj|f}jjf}|j|}|r8fdd|Dnt }|j|}|rGt |nt }||krg}|D]!} | D]} j j | } | jrr| jjrr|| qVqRj|ddi||i|dqdS)Ncs&h|]}tfdd|DqS)c3s$|] }j|f|VqdSr+rW)rnrrrrrr,Qs  zQMigrationAutodetector._generate_altered_foo_together...)r6)runiquerrrrPs zGMigrationAutodetector._generate_altered_foo_together..rLrr)rqrGrrrrrrrrWrVr^r_rrHrrrr) rrrqrrrr old_value new_valuer foo_togethersrrMrrr_generate_altered_foo_togetherGsD  z4MigrationAutodetector._generate_altered_foo_togethercC|tjdSr+)rrrr(rrrrvlz6MigrationAutodetector.generate_altered_unique_togethercCrr+)rrrr(rrrrworz5MigrationAutodetector.generate_altered_index_togetherc Cs|j|j|j}t|D]8\}}|j||f|}|jj||f}|j j||f}|j d}|j d}||krE| |t j ||dq dS)Ndb_table)rLtable)runionrrrGrrrrrrrrAlterModelTable) rmodels_to_checkrrrrrrold_db_table_namenew_db_table_namerrrrzrs"  z/MigrationAutodetector.generate_altered_db_tablec Cs|j|j|j|j|j@|j|j@}t|D]@\}}|j ||f|}|j j ||f}|j j ||f}dd|jD}dd|jD}||krW||tj||dqdS)z Work out if any non-schema-affecting options have changed and make an operation to represent them in state changes (in case Python code in migrations needs them). cS i|] \}}|tjvr||qSrrALTER_OPTION_KEYSr.rrrr0  zBMigrationAutodetector.generate_altered_options..cSrrrr.rrrr0r)rLrN)rrrrrZr[rXr]rGrrrrrrr8rrr) rrrrrrrr old_options new_optionsrrrrks4   z.MigrationAutodetector.generate_altered_optionscCst|jD]N\}}|j||f|}|jj||f}|jj||f}|jd|jdkrSg}|jdrB||||jddf|j |t j ||jdd|dqdS)NrTr r) rGrrrrrrrrIrrr)rrrrrrrrrrrrus2    z.) rr5r8r ask_initialrL parse_number enumeraterrI suggest_namejoinr)rr"rr!leavesrr~app_leafleafr next_numberinew_name_partsrrrrrsL         z'MigrationAutodetector.arrange_for_graphc si|D]\}}|D]}|jD]\}}|t|qq qt|}d} | |kr@t|} |jfdd|D| |ks,t|D] }||vrM||=qD|S)a1 Take changes from arrange_for_graph() and set of app labels, and return a modified set of changes which trims out as many migrations that are not in app_labels as possible. Note that some other migrations may still be present as they may be required dependencies. Ncsg|]}|dqS)rr)rrapp_dependenciesrrr)rmz7MigrationAutodetector._trim_to_apps..)r8rrrWrarr5) rr" app_labelsrr~rrrL required_appsold_required_appsrrrrs$ z#MigrationAutodetector._trim_to_appscCs td|}|rt|dSdS)z Given a migration name, try to extract a number from the beginning of it. If no number is found, return None. z^\d+rN)rematchint)clsrLrrrrrs  z"MigrationAutodetector.parse_numberr+)NNN)NN)NF)0r __module__ __qualname____doc__rr"r%rOrrerf staticmethodrr|r{r}rrrrdrhrjrgrirqrsrArrrTrtrmrxrprnryrorrrvrwrzrkrurlrr classmethodrrrrrr s^  ( a  W ?./!Y &S    %$ 2r )r9r itertoolsr django.confr django.dbrdjango.db.migrationsrdjango.db.migrations.migrationr&django.db.migrations.operations.modelsrdjango.db.migrations.optimizerrdjango.db.migrations.questionerr django.db.migrations.utilsr r django.utils.topological_sortr r rrrrs