3

I was wondering if I'm only one struggling with such problem.

Lets take dict for example:

data = {'totalSize': 3000, 'freq': 2400,
        'distribution':
            {'ram1': {'size': 200, 'status': 'OK'},
             'ram2': {'size': 100, 'status': 'OK'}
             }
        }

Please not that ram1/2 is dynamic keys that can not be known in advance

Question, how should my api.model look like ? I have:

wild = {"*": fields.Wildcard(fields.String())}
hw_memory = api.model('Memory', {
    'totalSize': fields.Integer(description='total memory size in MB',
                                example=1024),
    'freq': fields.Integer(description='Speed of ram in mhz', example=800),
    'distribution': fields.Nested(wild),
})

It is working, however it does not validate anything below "distribution", in other words, works like wildcard, anything there will be accepted. Is there a way to nest dicts in such way having wildcard dynamic key ?

Devourer
  • 33
  • 1
  • 3

1 Answers1

1

First of all, Wildcard type of field accepts the definition of the dict values, not the definition of the keys, i.e fields.Wildcard(fields.String()) validates that dict values can be only of string type (in your case you need to provide definition of distribution).

The second mistake is that you are defining distribution field as Nested object instead of using Wilcard.

The following code should work for validation purpose:


DISTRIBUTION_MODEL = NAMESPACE.model("Distribution", dict(
    size=fields.Integer(),
    status=fields.String(),
))

MEMORY_MODEL = NAMESPACE.model("Memory", dict(
    totalSize=fields.Integer(description='total memory size in MB',
                             example=1024),
    freq=fields.Integer(description='Speed of ram in mhz', example=800),
    distribution=fields.Wildcard(fields.Nested(DISTRIBUTION_MODEL))
))

Unfortunately, it doesn't work for marshaling. The next code should work for marshaling, but doesn't for validation input payload:


OUTPUT_MEMORY_MODEL = NAMESPACE.model("OutputMemory", dict(
    totalSize=fields.Integer(description='total memory size in MB',
                             example=1024),
    freq=fields.Integer(description='Speed of ram in mhz', example=800),
    distribution=flask_utils.fields.Nested(
        NAMESPACE.model(
            "distributions", {
                "*": fields.Wildcard(
                    # DISTRIBUTION_MODEL is taken from previous snippet
                    fields.Nested(DISTRIBUTION_MODEL)
                )
            }
        )
    )
))
  • *update* I have removed comment because it was my stupid mistake (passed model to marshal() in a wrong place. Anyway - question is still valid, solution you have provided doesn't have wildcard KEY in nested dict, if I try to marshal with this model, i get "{"totalSize": 12, "freq": 2400, "distribution": {"size": null, "status": null}}" which is not right. it should be "{"totalSize": 12, "freq": 2400, "distribution": {'ram1': {"size": null, "status": null}}} – Devourer Aug 18 '20 at 06:52
  • You said nothing about marshaling in your question :) The following snippet works fine for validation of input data. It is quite strange that the same model doesn't work for marshaling. Sounds like a bug of flask-restx . The only thing that I can suggest - provide 2 different models for validation and marshaling (I updated the reply with a valid model for marshaling) – Andrey Kurilin Aug 18 '20 at 12:09
  • Kudos Andrey, you helped a lot ! – Devourer Aug 18 '20 at 13:39