@@ -836,6 +836,35 @@ module PrivateDjango {
836836 nodeTo = call
837837 )
838838 or
839+ // attribute store in `<Model>.objects.create`, `get_or_create`, and `update_or_create`
840+ // see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#create
841+ // see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#get-or-create
842+ // see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#update-or-create
843+ // TODO: This does currently not handle values passed in the `defaults` dictionary
844+ exists (
845+ DataFlow:: CallCfgNode call , API:: Node modelClass , string fieldName ,
846+ string methodName
847+ |
848+ modelClass = Model:: subclassRef ( ) and
849+ methodName in [ "create" , "get_or_create" , "update_or_create" ] and
850+ call = modelClass .getMember ( "objects" ) .getMember ( methodName ) .getACall ( ) and
851+ nodeFrom = call .getArgByName ( fieldName ) and
852+ c .( DataFlow:: AttributeContent ) .getAttribute ( ) = fieldName and
853+ (
854+ // -> object created
855+ (
856+ methodName = "create" and nodeTo = call
857+ or
858+ // TODO: for these two methods, the result is a tuple `(<Model>, bool)`,
859+ // which we need flow-summaries to model properly
860+ methodName in [ "get_or_create" , "update_or_create" ] and none ( )
861+ )
862+ or
863+ // -> DB store on synthetic node
864+ nodeTo .( SyntheticDjangoOrmModelNode ) .getModelClass ( ) = modelClass
865+ )
866+ )
867+ or
839868 // synthetic -> method-call that returns collection of ORM models (all/filter/...)
840869 exists ( API:: Node modelClass |
841870 nodeFrom .( SyntheticDjangoOrmModelNode ) .getModelClass ( ) = modelClass and
0 commit comments