Python: ORM: Handle <Model>.objects.create and friends

This commit is contained in:
Rasmus Wriedt Larsen
2022-02-17 13:45:29 +01:00
parent 9b458b54aa
commit fea46b642d
2 changed files with 33 additions and 4 deletions

View File

@@ -836,6 +836,35 @@ module PrivateDjango {
nodeTo = call
)
or
// attribute store in `<Model>.objects.create`, `get_or_create`, and `update_or_create`
// see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#create
// see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#get-or-create
// see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#update-or-create
// TODO: This does currently not handle values passed in the `defaults` dictionary
exists(
DataFlow::CallCfgNode call, API::Node modelClass, string fieldName,
string methodName
|
modelClass = Model::subclassRef() and
methodName in ["create", "get_or_create", "update_or_create"] and
call = modelClass.getMember("objects").getMember(methodName).getACall() and
nodeFrom = call.getArgByName(fieldName) and
c.(DataFlow::AttributeContent).getAttribute() = fieldName and
(
// -> object created
(
methodName = "create" and nodeTo = call
or
// TODO: for these two methods, the result is a tuple `(<Model>, bool)`,
// which we need flow-summaries to model properly
methodName in ["get_or_create", "update_or_create"] and none()
)
or
// -> DB store on synthetic node
nodeTo.(SyntheticDjangoOrmModelNode).getModelClass() = modelClass
)
)
or
// synthetic -> method-call that returns collection of ORM models (all/filter/...)
exists(API::Node modelClass |
nodeFrom.(SyntheticDjangoOrmModelNode).getModelClass() = modelClass and

View File

@@ -113,11 +113,11 @@ class TestSave5(models.Model):
def test_save5_store():
# note: positional args not possible
obj = TestSave5.objects.create(text=SOURCE)
SINK(obj.text) # $ MISSING: flow
SINK(obj.text) # $ flow="SOURCE, l:-1 -> obj.text"
def test_save5_load():
obj = TestSave5.objects.first()
SINK(obj.text) # $ MISSING: flow
SINK(obj.text) # $ flow="SOURCE, l:-5 -> obj.text"
# --------------------------------------
# <Model>.objects.get_or_create()
@@ -135,7 +135,7 @@ def test_save6_store():
def test_save6_load():
obj = TestSave6.objects.first()
SINK(obj.text) # $ MISSING: flow
SINK(obj.email) # $ MISSING: flow
SINK(obj.email) # $ flow="SOURCE, l:-7 -> obj.email"
# --------------------------------------
# <Model>.objects.update_or_create()
@@ -153,7 +153,7 @@ def test_save7_store():
def test_save7_load():
obj = TestSave7.objects.first()
SINK(obj.text) # $ MISSING: flow
SINK(obj.email) # $ MISSING: flow
SINK(obj.email) # $ flow="SOURCE, l:-7 -> obj.email"
# --------------------------------------
# <Model>.objects.[<QuerySet>].update()