Pydantic: [Question] Looping through a nested model object returns dictionaries?

Created on 5 May 2019  路  4Comments  路  Source: samuelcolvin/pydantic

Question

Hi Samuel, sorry to bother you with one more question:

I just ran into the issue where I have a Model with other nested Models and want to loop through the nested models.

An example to illustrate:

class NestedModel(BaseModel):
    foo: int

class MyModel(BaseModel):
    one: NestedModel
    two: NestedModel

my_model = MyModel(one=NestedModel(foo=1), two=NestedModel(foo=2))

When doing the following

for key, nested_model in my_model:
    print(nested_model)

it turns out that nested_model is a dictionary and not an object of class NestedModel.
I found that a little surprising, since if I wanted to work with dicts I could explicitly call my_model.dict()

The only way I found for now to loop through the NestedModel objects was like this

for key, value in my_model:
    print(my_model.__getattr__(key))

is there a better way to do this?


and just a side note, since pydantic Models seem to be somewhat similar to dictionaries, I would have expected

for key in my_model:
    print(key)

to return the string keys of the fields instead of a tuple with string and dictionary.
I guess in my current world understanding, I would prefer

for key, nested_model in my_model.items():
    print(nested_model)

to be the syntax for looping through the fields (and getting pydantic models instead of dictionaries)

all this being said, there are probably some good reasons for this being different that I dont understand, but this is why I am asking :)

feature request

Most helpful comment

is there a better way to do this?

Sadly not really, you can use getattr() but that's really not much better.

This was so that dict(model) return a dictionary that recursively converted sub-models to dicts.

Based on the (potentially flawed) logic "if you call dict() on the model, you'll probably want sub-models as dicts too".

But I agree it can be annoying that pydantic is a little eager to convert things to dicts.

The problem is:

  • if we change how current methods work, it will break a lot of peoples code
  • if we add more methods (eg. items), someone will come along and quite understandably complain "but I want model.items", they can use aliases, but I get it's still annoying

That said this does seem mad, and the who point in being "pre v1" is that we can break things. Therefore I'd be happy to consider changing .__iter__() to return models, as long as .dict() doesn't change behaviour.

I think it should return tuples of key and value, not just keys.

Anyone else hate this idea?

All 4 comments

is there a better way to do this?

Sadly not really, you can use getattr() but that's really not much better.

This was so that dict(model) return a dictionary that recursively converted sub-models to dicts.

Based on the (potentially flawed) logic "if you call dict() on the model, you'll probably want sub-models as dicts too".

But I agree it can be annoying that pydantic is a little eager to convert things to dicts.

The problem is:

  • if we change how current methods work, it will break a lot of peoples code
  • if we add more methods (eg. items), someone will come along and quite understandably complain "but I want model.items", they can use aliases, but I get it's still annoying

That said this does seem mad, and the who point in being "pre v1" is that we can break things. Therefore I'd be happy to consider changing .__iter__() to return models, as long as .dict() doesn't change behaviour.

I think it should return tuples of key and value, not just keys.

Anyone else hate this idea?

That said this does seem mad, and the who point in being "pre v1" is that we can break things.

Exactly

I'd be happy to consider changing .__iter__() to return models, as long as .dict() doesn't change behaviour.

I'm all for it (both first and second part). Working hard to define all those types and then loose them during iteration will be too bad.

I think it should return tuples of key and value, not just keys.

Agree with this :heavy_check_mark:

It would mean that dict(model) would still return a dict. Just that now it would be a dict of str keys and values would be models, instead of sub-dicts. But it would still be sort of "dict-compliant".

And then when someone needs a pure dict of dicts (not models) he can use model.dict().

733 changes the behaviour, feedback on that very welcome.

I think it should return tuples of key and value, not just keys.

It would be impossible to change this without implementing the whole Mapping abc for a models, which would involve adding .keys(), .get(), .__getitem__(), .values() etc. which would be massively confusing and clash with lots of field names, so it's not an option.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DrPyser picture DrPyser  路  19Comments

sm-Fifteen picture sm-Fifteen  路  45Comments

samuelcolvin picture samuelcolvin  路  30Comments

Yolley picture Yolley  路  18Comments

rrbarbosa picture rrbarbosa  路  35Comments