1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
|
Advanced Usage
==============
This section includes guides for advanced usage patterns.
Custom Location Handlers
------------------------
To add your own custom location handler, write a function that receives a request, and a :class:`Schema <marshmallow.Schema>`, then decorate that function with :func:`Parser.location_loader <webargs.core.Parser.location_loader>`.
.. code-block:: python
from webargs import fields
from webargs.flaskparser import parser
@parser.location_loader("data")
def load_data(request, schema):
return request.data
# Now 'data' can be specified as a location
@parser.use_args({"per_page": fields.Int()}, location="data")
def posts(args):
return "displaying {} posts".format(args["per_page"])
.. NOTE::
The schema is passed so that it can be used to wrap multidict types and
unpack List fields correctly. If you are writing a loader for a multidict
type, consider looking at
:class:`MultiDictProxy <webargs.multidictproxy.MultiDictProxy>` for an
example of how to do this.
"meta" Locations
~~~~~~~~~~~~~~~~
You can define your own locations which mix data from several existing
locations.
The `json_or_form` location does this -- first trying to load data as JSON and
then falling back to a form body -- and its implementation is quite simple:
.. code-block:: python
def load_json_or_form(self, req, schema):
"""Load data from a request, accepting either JSON or form-encoded
data.
The data will first be loaded as JSON, and, if that fails, it will be
loaded as a form post.
"""
data = self.load_json(req, schema)
if data is not missing:
return data
return self.load_form(req, schema)
You can imagine your own locations with custom behaviors like this.
For example, to mix query parameters and form body data, you might write the
following:
.. code-block:: python
from webargs import fields
from webargs.multidictproxy import MultiDictProxy
from webargs.flaskparser import parser
@parser.location_loader("query_and_form")
def load_data(request, schema):
# relies on the Flask (werkzeug) MultiDict type's implementation of
# these methods, but when you're extending webargs, you may know things
# about your framework of choice
newdata = request.args.copy()
newdata.update(request.form)
return MultiDictProxy(newdata, schema)
# Now 'query_and_form' means you can send these values in either location,
# and they will be *mixed* together into a new dict to pass to your schema
@parser.use_args({"favorite_food": fields.String()}, location="query_and_form")
def set_favorite_food(args):
... # do stuff
return "your favorite food is now set to {}".format(args["favorite_food"])
marshmallow Integration
-----------------------
When you need more flexibility in defining input schemas, you can pass a marshmallow `Schema <marshmallow.Schema>` instead of a dictionary to `Parser.parse <webargs.core.Parser.parse>`, `Parser.use_args <webargs.core.Parser.use_args>`, and `Parser.use_kwargs <webargs.core.Parser.use_kwargs>`.
.. code-block:: python
from marshmallow import Schema, fields
from webargs.flaskparser import use_args
class UserSchema(Schema):
id = fields.Int(dump_only=True) # read-only (won't be parsed by webargs)
username = fields.Str(required=True)
password = fields.Str(load_only=True) # write-only
first_name = fields.Str(load_default="")
last_name = fields.Str(load_default="")
date_registered = fields.DateTime(dump_only=True)
@use_args(UserSchema())
def profile_view(args):
username = args["username"]
# ...
@use_kwargs(UserSchema())
def profile_update(username, password, first_name, last_name):
update_profile(username, password, first_name, last_name)
# ...
# You can add additional parameters
@use_kwargs({"posts_per_page": fields.Int(load_default=10)}, location="query")
@use_args(UserSchema())
def profile_posts(args, posts_per_page):
username = args["username"]
# ...
.. _advanced_setting_unknown:
Setting `unknown`
-----------------
webargs supports several ways of setting and passing the `unknown` parameter
for `handling unknown fields <https://marshmallow.readthedocs.io/en/stable/quickstart.html#handling-unknown-fields>`_.
You can pass `unknown=...` as a parameter to any of
`Parser.parse <webargs.core.Parser.parse>`,
`Parser.use_args <webargs.core.Parser.use_args>`, and
`Parser.use_kwargs <webargs.core.Parser.use_kwargs>`.
.. note::
The `unknown` value is passed to the schema's `load()` call. It therefore
only applies to the top layer when nesting is used. To control `unknown` at
multiple layers of a nested schema, you must use other mechanisms, like
the `unknown` argument to `fields.Nested`.
Default `unknown`
~~~~~~~~~~~~~~~~~
By default, webargs will pass `unknown=marshmallow.EXCLUDE` except when the
location is `json`, `form`, `json_or_form`, or `path`. In those cases, it uses
`unknown=marshmallow.RAISE` instead.
You can change these defaults by overriding `DEFAULT_UNKNOWN_BY_LOCATION`.
This is a mapping of locations to values to pass.
For example,
.. code-block:: python
from flask import Flask
from marshmallow import EXCLUDE, fields
from webargs.flaskparser import FlaskParser
app = Flask(__name__)
class Parser(FlaskParser):
DEFAULT_UNKNOWN_BY_LOCATION = {"query": EXCLUDE}
parser = Parser()
# location is "query", which is listed in DEFAULT_UNKNOWN_BY_LOCATION,
# so EXCLUDE will be used
@app.route("/", methods=["GET"])
@parser.use_args({"foo": fields.Int()}, location="query")
def get(args):
return f"foo x 2 = {args['foo'] * 2}"
# location is "json", which is not in DEFAULT_UNKNOWN_BY_LOCATION,
# so no value will be passed for `unknown`
@app.route("/", methods=["POST"])
@parser.use_args({"foo": fields.Int(), "bar": fields.Int()}, location="json")
def post(args):
return f"foo x bar = {args['foo'] * args['bar']}"
You can also define a default at parser instantiation, which will take
precedence over these defaults, as in
.. code-block:: python
from marshmallow import INCLUDE
parser = Parser(unknown=INCLUDE)
# because `unknown` is set on the parser, `DEFAULT_UNKNOWN_BY_LOCATION` has
# effect and `INCLUDE` will always be used
@app.route("/", methods=["POST"])
@parser.use_args({"foo": fields.Int(), "bar": fields.Int()}, location="json")
def post(args):
unexpected_args = [k for k in args.keys() if k not in ("foo", "bar")]
return f"foo x bar = {args['foo'] * args['bar']}; unexpected args={unexpected_args}"
Using Schema-Specfied `unknown`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you wish to use the value of `unknown` specified by a schema, simply pass
``unknown=None``. This will disable webargs' automatic passing of values for
``unknown``. For example,
.. code-block:: python
from flask import Flask
from marshmallow import Schema, fields, EXCLUDE, missing
from webargs.flaskparser import use_args
class RectangleSchema(Schema):
length = fields.Float()
width = fields.Float()
class Meta:
unknown = EXCLUDE
app = Flask(__name__)
# because unknown=None was passed, no value is passed during schema loading
# as a result, the schema's behavior (EXCLUDE) is used
@app.route("/", methods=["POST"])
@use_args(RectangleSchema(), location="json", unknown=None)
def get(args):
return f"area = {args['length'] * args['width']}"
You can also set ``unknown=None`` when instantiating a parser to make this
behavior the default for a parser.
When to avoid `use_kwargs`
--------------------------
Any `Schema <marshmallow.Schema>` passed to `use_kwargs <webargs.core.Parser.use_kwargs>` MUST deserialize to a dictionary of data.
If your schema has a `post_load <marshmallow.decorators.post_load>` method
that returns a non-dictionary,
you should use `use_args <webargs.core.Parser.use_args>` instead.
.. code-block:: python
from marshmallow import Schema, fields, post_load
from webargs.flaskparser import use_args
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
class RectangleSchema(Schema):
length = fields.Float()
width = fields.Float()
@post_load
def make_object(self, data, **kwargs):
return Rectangle(**data)
@use_args(RectangleSchema)
def post(rect: Rectangle):
return f"Area: {rect.length * rect.width}"
Packages such as `marshmallow-sqlalchemy <https://github.com/marshmallow-code/marshmallow-sqlalchemy>`_ and `marshmallow-dataclass <https://github.com/lovasoa/marshmallow_dataclass>`_ generate schemas that deserialize to non-dictionary objects.
Therefore, `use_args <webargs.core.Parser.use_args>` should be used with those schemas.
Schema Factories
----------------
If you need to parametrize a schema based on a given request, you can use a "Schema factory": a callable that receives the current `request` and returns a `marshmallow.Schema` instance.
Consider the following use cases:
- Filtering via a query parameter by passing ``only`` to the Schema.
- Handle partial updates for PATCH requests using marshmallow's `partial loading <https://marshmallow.readthedocs.io/en/latest/quickstart.html#partial-loading>`_ API.
.. code-block:: python
from flask import Flask
from marshmallow import Schema, fields
from webargs.flaskparser import use_args
app = Flask(__name__)
class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str(required=True)
password = fields.Str(load_only=True)
first_name = fields.Str(load_default="")
last_name = fields.Str(load_default="")
date_registered = fields.DateTime(dump_only=True)
def make_user_schema(request):
# Filter based on 'fields' query parameter
fields = request.args.get("fields", None)
only = fields.split(",") if fields else None
# Respect partial updates for PATCH requests
partial = request.method == "PATCH"
# Add current request to the schema's context
return UserSchema(only=only, partial=partial, context={"request": request})
# Pass the factory to .parse, .use_args, or .use_kwargs
@app.route("/profile/", methods=["GET", "POST", "PATCH"])
@use_args(make_user_schema)
def profile_view(args):
username = args.get("username")
# ...
Reducing Boilerplate
~~~~~~~~~~~~~~~~~~~~
We can reduce boilerplate and improve [re]usability with a simple helper function:
.. code-block:: python
from webargs.flaskparser import use_args
def use_args_with(schema_cls, schema_kwargs=None, **kwargs):
schema_kwargs = schema_kwargs or {}
def factory(request):
# Filter based on 'fields' query parameter
only = request.args.get("fields", None)
# Respect partial updates for PATCH requests
partial = request.method == "PATCH"
return schema_cls(
only=only, partial=partial, context={"request": request}, **schema_kwargs
)
return use_args(factory, **kwargs)
Now we can attach input schemas to our view functions like so:
.. code-block:: python
@use_args_with(UserSchema)
def profile_view(args):
# ...
get_profile(**args)
Custom Fields
-------------
See the "Custom Fields" section of the marshmallow docs for a detailed guide on defining custom fields which you can pass to webargs parsers: https://marshmallow.readthedocs.io/en/latest/custom_fields.html.
Using ``Method`` and ``Function`` Fields with webargs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using the :class:`Method <marshmallow.fields.Method>` and :class:`Function <marshmallow.fields.Function>` fields requires that you pass the ``deserialize`` parameter.
.. code-block:: python
@use_args({"cube": fields.Function(deserialize=lambda x: int(x) ** 3)})
def math_view(args):
cube = args["cube"]
# ...
.. _custom-loaders:
Custom Parsers
--------------
To add your own parser, extend :class:`Parser <webargs.core.Parser>` and implement the `load_*` method(s) you need to override. For example, here is a custom Flask parser that handles nested query string arguments.
.. code-block:: python
import re
from webargs.flaskparser import FlaskParser
class NestedQueryFlaskParser(FlaskParser):
"""Parses nested query args
This parser handles nested query args. It expects nested levels
delimited by a period and then deserializes the query args into a
nested dict.
For example, the URL query params `?name.first=John&name.last=Boone`
will yield the following dict:
{
'name': {
'first': 'John',
'last': 'Boone',
}
}
"""
def load_querystring(self, req, schema):
return _structure_dict(req.args)
def _structure_dict(dict_):
def structure_dict_pair(r, key, value):
m = re.match(r"(\w+)\.(.*)", key)
if m:
if r.get(m.group(1)) is None:
r[m.group(1)] = {}
structure_dict_pair(r[m.group(1)], m.group(2), value)
else:
r[key] = value
r = {}
for k, v in dict_.items():
structure_dict_pair(r, k, v)
return r
Parser pre_load
---------------
Similar to ``@pre_load`` decorated hooks on marshmallow Schemas,
:class:`Parser <webargs.core.Parser>` classes define a method,
`pre_load <webargs.core.Parser.pre_load>` which can
be overridden to provide per-parser transformations of data.
The only way to make use of `pre_load <webargs.core.Parser.pre_load>` is to
subclass a :class:`Parser <webargs.core.Parser>` and provide an
implementation.
`pre_load <webargs.core.Parser.pre_load>` is given the data fetched from a
location, the schema which will be used, the request object, and the location
name which was requested. For example, to define a ``FlaskParser`` which strips
whitespace from ``form`` and ``query`` data, one could write the following:
.. code-block:: python
from webargs.flaskparser import FlaskParser
import typing
def _strip_whitespace(value):
if isinstance(value, str):
value = value.strip()
elif isinstance(value, typing.Mapping):
return {k: _strip_whitespace(value[k]) for k in value}
elif isinstance(value, (list, tuple)):
return type(value)(map(_strip_whitespace, value))
return value
class WhitspaceStrippingFlaskParser(FlaskParser):
def pre_load(self, location_data, *, schema, req, location):
if location in ("query", "form"):
return _strip_whitespace(location_data)
return location_data
Note that `Parser.pre_load <webargs.core.Parser.pre_load>` is run after location
loading but before ``Schema.load`` is called. It can therefore be called on
multiple types of mapping objects, including
:class:`MultiDictProxy <webargs.MultiDictProxy>`, depending on what the
location loader returns.
Returning HTTP 400 Responses
----------------------------
If you'd prefer validation errors to return status code ``400`` instead
of ``422``, you can override ``DEFAULT_VALIDATION_STATUS`` on a :class:`Parser <webargs.core.Parser>`.
Subclass the parser for your framework to do so. For example, using Falcon:
.. code-block:: python
from webargs.falconparser import FalconParser
class Parser(FalconParser):
DEFAULT_VALIDATION_STATUS = 400
parser = Parser()
use_args = parser.use_args
use_kwargs = parser.use_kwargs
Bulk-type Arguments
-------------------
In order to parse a JSON array of objects, pass ``many=True`` to your input ``Schema`` .
For example, you might implement JSON PATCH according to `RFC 6902 <https://tools.ietf.org/html/rfc6902>`_ like so:
.. code-block:: python
from webargs import fields
from webargs.flaskparser import use_args
from marshmallow import Schema, validate
class PatchSchema(Schema):
op = fields.Str(
required=True,
validate=validate.OneOf(["add", "remove", "replace", "move", "copy"]),
)
path = fields.Str(required=True)
value = fields.Str(required=True)
@app.route("/profile/", methods=["patch"])
@use_args(PatchSchema(many=True))
def patch_blog(args):
"""Implements JSON Patch for the user profile
Example JSON body:
[
{"op": "replace", "path": "/email", "value": "mynewemail@test.org"}
]
"""
# ...
Multi-Field Detection
---------------------
If a ``List`` field is used to parse data from a location like query parameters --
where one or multiple values can be passed for a single parameter name -- then
webargs will automatically treat that field as a list and parse multiple values
if present.
To implement this behavior, webargs will examine schemas for ``marshmallow.fields.List``
fields. ``List`` fields get unpacked to list values when data is loaded, and
other fields do not. This also applies to fields which inherit from ``List``.
.. note::
In webargs v8, ``Tuple`` will be treated this way as well, in addition to ``List``.
What if you have a list which should be treated as a "multi-field" but which
does not inherit from ``List``? webargs offers two solutions.
You can add the custom attribute `is_multiple=True` to your field or you
can add your class to your parser's list of `KNOWN_MULTI_FIELDS`.
First, let's define a "multiplexing field" which takes a string or list of
strings to serve as an example:
.. code-block:: python
# a custom field class which can accept values like List(String()) or String()
class CustomMultiplexingField(fields.String):
def _deserialize(self, value, attr, data, **kwargs):
if isinstance(value, str):
return super()._deserialize(value, attr, data, **kwargs)
return [
self._deserialize(v, attr, data, **kwargs)
for v in value
if isinstance(v, str)
]
def _serialize(self, value, attr, **kwargs):
if isinstance(value, str):
return super()._serialize(value, attr, **kwargs)
return [self._serialize(v, attr, **kwargs) for v in value if isinstance(v, str)]
If you control the definition of ``CustomMultiplexingField``, you can just add
``is_multiple=True`` to it:
.. code-block:: python
# option 1: define the field with is_multiple = True
from webargs.flaskparser import parser
class CustomMultiplexingField(fields.Field):
is_multiple = True # <----- this marks this as a multi-field
... # as above
If you don't control the definition of ``CustomMultiplexingField``, for example
because it comes from a library, you can add it to the list of known
multifields:
.. code-block:: python
# option 2: add the field to the parer's list of multi-fields
class MyParser(FlaskParser):
KNOWN_MULTI_FIELDS = list(FlaskParser.KNOWN_MULTI_FIELDS) + [
CustomMultiplexingField
]
parser = MyParser()
In either case, the end result is that you can use the multifield and it will
be detected as a list when unpacking query string data:
.. code-block:: python
# gracefully handles
# ...?foo=a
# ...?foo=a&foo=b
# and treats them as ["a"] and ["a", "b"] respectively
@parser.use_args({"foo": CustomMultiplexingField()}, location="query")
def show_foos(foo): ...
Mixing Locations
----------------
Arguments for different locations can be specified by passing ``location`` to each `use_args <webargs.core.Parser.use_args>` call:
.. code-block:: python
# "json" is the default, used explicitly below
@app.route("/stacked", methods=["POST"])
@use_args({"page": fields.Int(), "q": fields.Str()}, location="query")
@use_args({"name": fields.Str()}, location="json")
def viewfunc(query_parsed, json_parsed):
page = query_parsed["page"]
name = json_parsed["name"]
# ...
To reduce boilerplate, you could create shortcuts, like so:
.. code-block:: python
import functools
query = functools.partial(use_args, location="query")
body = functools.partial(use_args, location="json")
@query({"page": fields.Int(), "q": fields.Int()})
@body({"name": fields.Str()})
def viewfunc(query_parsed, json_parsed):
page = query_parsed["page"]
name = json_parsed["name"]
# ...
Argument Passing and ``arg_name``
---------------------------------
.. NOTE::
This section describes behaviors which are planned to change in ``webargs``
version 9. In version 8, behavior will be as follows. In version 9,
``USE_ARGS_POSITIONAL`` will be removed and will always be ``False``.
By default, ``webargs`` provides two ways of passing arguments via decorators,
`Parser.use_args <webargs.core.Parser.use_args>`, and `Parser.use_kwargs <webargs.core.Parser.use_kwargs>`.
``use_args`` passes parsed arguments as positionals, and ``use_kwargs`` expands
dict-like parsed arguments into keyword arguments.
For ``use_args``, the result is that sometimes it is non-obvious which order
arguments will be passed in. Consider the following nearly identical example
snippets:
.. code-block:: python
# correct ordering, top-to-bottom
@use_args({"foo": fields.Int(), "bar": fields.Str()}, location="query")
@use_args({"baz": fields.Str()}, location="json")
def viewfunc(query_args, json_args): ...
# incorrect ordering, bottom-to-top
@use_args({"foo": fields.Int(), "bar": fields.Str()}, location="query")
@use_args({"baz": fields.Str()}, location="json")
def viewfunc(json_args, query_args): ...
To resolve this ambiguity, ``webargs`` version 9 will pass arguments from
``use_args`` as keyword arguments. You can opt-in to this behavior today by
setting ``USE_ARGS_POSITIONAL = False`` on a parser class. This will cause
webargs to pass arguments named ``{location}_args`` for each location used.
For example,
.. code-block:: python
from webargs.flaskparser import FlaskParser
from flask import Flask
class KeywordOnlyParser(FlaskParser):
USE_ARGS_POSITIONAL = False
app = Flask(__name__)
parser = KeywordOnlyParser()
@app.route("/")
@parser.use_args({"foo": fields.Int(), "bar": fields.Str()}, location="query")
@parser.use_args({"baz": fields.Str()}, location="json")
def myview(*, query_args, json_args): ...
You can also customize the names of passed arguments using the ``arg_name``
parameter:
.. code-block:: python
@app.route("/")
@parser.use_args(
{"foo": fields.Int(), "bar": fields.Str()}, location="query", arg_name="query"
)
@parser.use_args({"baz": fields.Str()}, location="json", arg_name="payload")
def myview(*, query, payload): ...
Note that ``arg_name`` is available even on parsers where
``USE_ARGS_POSITIONAL`` is not set.
Using an Alternate Argument Name Convention
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As described above, the default naming convention for ``use_args`` arguments is
``{location}_args``. You can customize this by creating a parser class and
overriding the ``get_default_arg_name`` method.
``get_default_arg_name`` takes the ``location`` and the ``schema`` as
arguments. The default implementation is:
.. code-block:: python
def get_default_arg_name(self, location, schema):
return f"{location}_args"
You can customize this to set different arg names. For example,
.. code-block:: python
from webargs.flaskparser import FlaskParser
class MyParser(FlaskParser):
USE_ARGS_POSITIONAL = False
def get_default_arg_name(self, location, schema):
if location in ("json", "form", "json_or_form"):
return "body"
elif location in ("query", "querystring"):
return "query"
return location
@app.route("/")
@parser.use_args({"foo": fields.Int(), "bar": fields.Str()}, location="query")
@parser.use_args({"baz": fields.Str()}, location="json")
def myview(*, query, body): ...
Additionally, this makes it possible to make custom schema classes which
provide an argument name. For example,
.. code-block:: python
from marshmallow import Schema
from webargs.flaskparser import FlaskParser
class RectangleSchema(Schema):
webargs_arg_name = "rectangle"
length = fields.Float()
width = fields.Float()
class MyParser(FlaskParser):
USE_ARGS_POSITIONAL = False
def get_default_arg_name(self, location, schema):
if hasattr(schema, "webargs_arg_name"):
if isinstance(schema.webargs_arg_name, str):
return schema.webargs_arg_name
return super().get_default_arg_name(location, schema)
@app.route("/")
@parser.use_args({"foo": fields.Int(), "bar": fields.Str()}, location="query")
@parser.use_args(RectangleSchema, location="json")
def myview(*, rectangle, query_args): ...
Next Steps
----------
- See the :doc:`Framework Support <framework_support>` page for framework-specific guides.
- For example applications, check out the `examples <https://github.com/marshmallow-code/webargs/tree/dev/examples>`_ directory.
|