This repository was archived by the owner on Jun 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 71
Expand file tree
/
Copy pathflask.py
More file actions
138 lines (111 loc) · 4.99 KB
/
flask.py
File metadata and controls
138 lines (111 loc) · 4.99 KB
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
"""Flask integration that avoids the need to hard-code URLs for links.
This includes a Flask-specific schema with custom Meta options and a
relationship field for linking to related resources.
"""
import flask
from werkzeug.routing import BuildError
from .fields import Relationship as GenericRelationship
from .schema import Schema as DefaultSchema, SchemaOpts as DefaultOpts
from .utils import resolve_params
class SchemaOpts(DefaultOpts):
"""Options to use Flask view names instead of hard coding URLs."""
def __init__(self, meta, *args, **kwargs):
if getattr(meta, "self_url", None):
raise ValueError(
"Use `self_view` instead of `self_url` " "using the Flask extension."
)
if getattr(meta, "self_url_kwargs", None):
raise ValueError(
"Use `self_view_kwargs` instead of `self_url_kwargs` "
"when using the Flask extension."
)
if getattr(meta, "self_url_many", None):
raise ValueError(
"Use `self_view_many` instead of `self_url_many` "
"when using the Flask extension."
)
if getattr(meta, "self_view_kwargs", None) and not getattr(
meta, "self_view", None
):
raise ValueError(
"Must specify `self_view` Meta option when "
"`self_view_kwargs` is specified."
)
# Transfer Flask options to URL options, to piggy-back on its handling
meta.self_url = getattr(meta, "self_view", None)
meta.self_url_kwargs = getattr(meta, "self_view_kwargs", None)
meta.self_url_many = getattr(meta, "self_view_many", None)
super().__init__(meta, *args, **kwargs)
class Schema(DefaultSchema):
"""A Flask specific schema that resolves self URLs from view names."""
OPTIONS_CLASS = SchemaOpts
class Meta:
"""Options object that takes the same options as `marshmallow-jsonapi.Schema`,
but instead of ``self_url``, ``self_url_kwargs`` and ``self_url_many``
has the following options to resolve the URLs from Flask views:
* ``self_view`` - View name to resolve the self URL link from.
* ``self_view_kwargs`` - Replacement fields for ``self_view``. String
attributes enclosed in ``< >`` will be interpreted as attributes to
pull from the schema data.
* ``self_view_many`` - View name to resolve the self URL link when a
collection of resources is returned.
"""
pass
def generate_url(self, view_name, **kwargs):
"""Generate URL with any kwargs interpolated."""
return flask.url_for(view_name, **kwargs) if view_name else None
class Relationship(GenericRelationship):
r"""Field which serializes to a "relationship object"
with a "related resource link".
See: http://jsonapi.org/format/#document-resource-object-relationships
Examples: ::
author = Relationship(
related_view='author_detail',
related_view_kwargs={'author_id': '<author.id>'},
)
comments = Relationship(
related_view='posts_comments',
related_view_kwargs={'post_id': '<id>'},
many=True, include_resource_linkage=True,
type_='comments'
)
This field is read-only by default.
:param str related_view: View name for related resource link.
:param dict related_view_kwargs: Path kwargs fields for `related_view`. String arguments
enclosed in `< >` will be interpreted as attributes to pull from the target object.
:param str self_view: View name for self relationship link.
:param dict self_view_kwargs: Path kwargs for `self_view`. String arguments
enclosed in `< >` will be interpreted as attributes to pull from the target object.
:param \*\*kwargs: Same keyword arguments as `marshmallow_jsonapi.fields.Relationship`.
"""
def __init__(
self,
related_view=None,
related_view_kwargs=None,
*,
self_view=None,
self_view_kwargs=None,
**kwargs
):
self.related_view = related_view
self.related_view_kwargs = related_view_kwargs or {}
self.self_view = self_view
self.self_view_kwargs = self_view_kwargs or {}
super().__init__(**kwargs)
def get_url(self, obj, view_name, view_kwargs):
if view_name:
kwargs = resolve_params(obj, view_kwargs, default=self.dump_default)
kwargs["endpoint"] = view_name
try:
return flask.url_for(**kwargs)
except BuildError:
if (
None in kwargs.values()
): # most likely to be caused by empty relationship
return None
raise
return None
def get_related_url(self, obj):
return self.get_url(obj, self.related_view, self.related_view_kwargs)
def get_self_url(self, obj):
return self.get_url(obj, self.self_view, self.self_view_kwargs)