-
Notifications
You must be signed in to change notification settings - Fork 301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Polymorphism in flask-restless #200
Comments
Thanks for the bug report. I will apply the minor fix you suggest in |
Two further suggestions: first, please provide only one problem per issue report, and second, please provide the complete error message and code which produced it, instead of just the last line of the error message ( |
@goranek Please provide a minimal example of the model class or classes that exhibit the incorrect behavior. |
I also solved this by setting
|
Thanks for the sample code. |
I'm learning about polymorphism in order to fix this bug, and I wonder what you expect the behavior of Flask-Restless to be in the following situation. Suppose I have version1 = Original(id=1)
version2 = Revision(id=2) (I believe the IDs must be distinct because each object represents a row of the single table GET /version/1 GET /original/1 GET /revision/1 GET /version/2 GET /original/2 GET /revision/2 There are two possibilities that I see:
In either case, we'll have to do some black magic on the model class provided to I suspect there may be further problems with other types of polymorphism... |
Or perhaps |
Okay, I've put some more thought into this and this is how I'm going to implement this for now. If it doesn't make sense, we can change it in the future. As for the original issue, I have fixed it in my local repository, but I'd like to get the following semantics down before I push my solution. Executive summaryCreating, updating, deleting, and fetching an individual resource will require the URL endpoint to match the actual type of the resource (so no updating an instance of a subclass at the URL for the superclass). However, fetching from a collection endpoint will fetch all instances of the superclass and any subclasses. Other ways of designing this API are possible (for example, updating a subclass instance from the URL for the superclass), and I'm open to suggestions if this doesn't make sense. But for now, this is how I'm going to implement it. Example setup codeSuppose I have the following models: class Employee(Base):
id = Column(Integer, primary_key=True)
type = Column(Enum(u'employee', u'manager'), nullable=False)
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'employee'
}
class Manager(Employee):
__mapper_args__ = {
'polymorphic_identity': 'manager'
} and I create the APIs like this: apimanager.create_api(Employee, method=['POST', 'DELETE', 'PATCH', 'GET'])
apimanager.create_api(Manager, method=['POST', 'DELETE', 'PATCH', 'GET']) We have several variables to deal with:
Creating resourcesAt the superclass endpointThe request POST /employee HTTP/1.1
{"data": {"type": "employee"}} yields the response HTTP/1.1 201 Created
Location: http://example.com/employee/1
Content-Type: application/vnd.api+json
{"data": {"type": "employee", "id": "1"}} However, the request POST /employee HTTP/1.1
{"data": {"type": "manager"}} yields a At the subclass endpointThe request POST /manager HTTP/1.1
{"data": {"type": "manager"}} yields the response HTTP/1.1 201 Created
Location: http://example.com/api/manager/1
Content-Type: application/vnd.api+json
{"data": {"type": "manager", "id": "1"}} However, the request POST /manager HTTP/1.1
{"data": {"type": "employee"}} yields a Deleting resourcesAssume we have created an employee resource at At the superclass endpointThe request DELETE /employee/1 HTTP/1.1 yields a However, the request DELETE /employee/2 HTTP/1.1 yields a At the subclass endpointThe request DELETE /manager/1 HTTP/1.1 yields a The request DELETE /manager/2 HTTP/1.1 yields a Updating resourcesAssume we have created an employee resource at At the superclass endpointWith superclass typeThe request PATCH /employee/1 HTTP/1.1
{"data": {"type": "employee", "id": "1"}} yields a However, the request PATCH /employee/2 HTTP/1.1
{"data": {"type": "employee", "id": "2"}} yields a With subclass typeThe request PATCH /employee/1 HTTP/1.1
{"data": {"type": "manager", "id": "1"}} yields a The request PATCH /employee/2 HTTP/1.1
{"data": {"type": "manager", "id": "2"}} yields a At the subclass endpointWith superclass typeThe request PATCH /manager/1 HTTP/1.1
{"data": {"type": "employee", "id": "1"}} yields a The request PATCH /manager/2 HTTP/1.1
{"data": {"type": "employee", "id": "2"}} yields a With subclass typeThe request PATCH /manager/1 HTTP/1.1
{"data": {"type": "manager", "id": "1"}} yields a The request PATCH /manager/2 HTTP/1.1
{"data": {"type": "manager", "id": "2"}} yields a Fetching collections of resourcesAssume we have created an employee resource at At the superclass endpointCollection of resourcesThe request GET /employee HTTP/1.1 yields the response HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"data": [
{
"type": "employee",
"id": "1",
"links": {
"self": "http://example.com/employee/1"
}
},
{
"type": "manager",
"id": "2",
"links": {
"self": "http://example.com/manager/2"
}
}
]
} Individual resourcesThe request GET /employee/1 HTTP/1.1 yields the response HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"data": {
"type": "employee",
"id": "1",
"links": {
"self": "http://example.com/employee/1"
}
}
} The request GET /employee/2 HTTP/1.1 yields a At the subclass endpointCollection of resourcesThe request GET /manager HTTP/1.1 yields the response HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"data": [
{
"type": "manager",
"id": "2",
"links": {
"self": "http://example.com/manager/2"
}
}
]
} Individual resourcesThe request GET /manager/1 HTTP/1.1 yields a The request GET /manager/2 HTTP/1.1 yields the response HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"data": {
"type": "manager",
"id": "2",
"links": {
"self": "http://example.com/manager/2"
}
}
} |
I have a SQLAlchemy model named
Version
, and it has atype
column.Based on that column I have two polymorphic objects called
Revision
(iftype == "revision"
) andOriginal
(iftype == "original"
). It is polymorphism in the same table.When you call
create_api()
for objectsVersion
,Revision
, andOriginal
they will all use the prefix/version/
, which is wrong. This happens because they are all using same table.Flask-restless should a) somehow figure this out, and use model name for API prefix, or b) you should write a note about this in the documentation and tell people to use custom names.
It took me a while to figure out why i always got an HTTP 404 error when making requests to
/original
and/revision
.I didn't check for polymorphism with different tables but it should probably work.
I also found another serious error.
I've fixed this by changing line 246, in file
views.py
, in function_to_dict
fromto
The text was updated successfully, but these errors were encountered: