Creating model instance does not respect "viewonly" relationship attribute
I have a semi-complex relationship using a secondary. This relationship is useful to me because when querying, but I do not want to write to it. SQLAlchemy has the viewonly option that I can set on the relationship to bypass setting that relationship when I insert a new record. Eve-SQLAlchemy, however, has issues when building the model instance for a resource that has this relationship associated with it. Eve-SQLAlchemy finds this relationship as a list, which is fine, and during insert time, building the model instance fails. This is unfortunate because evaluating this field when inserting is not necessary, since I've already set this as a "viewonly" field. Following is an example of my model. The relationship in question is "organization":
class CommonColumns(Base):
__abstract__ = True
_created = Column(DateTime, default=func.now())
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
_etag = Column(String(40))
@declared_attr
def created_by_id(cls):
return Column(Integer,
ForeignKey('users.id'),
default=get_current_user_id)
@declared_attr
def updated_by_id(cls):
return Column(Integer,
ForeignKey('users.id'),
default=get_current_user_id,
onupdate=get_current_user_id)
@declared_attr
def created_by(cls):
return relationship(
'Users',
foreign_keys='{}.created_by_id'.format(cls.__name__))
@declared_attr
def updated_by(cls):
return relationship(
'Users',
foreign_keys='{}.updated_by_id'.format(cls.__name__))
@declared_attr
def organization(cls):
return relationship(
'Organizations',
primaryjoin='{}.created_by_id==Users.id'.format(cls.__name__),
secondary='join(Users, Organizations, Users.organization_id == Organizations.id)', # noqa
viewonly=True)
class Users(Base):
__tablename__ = 'users'
_created = Column(DateTime, default=func.now())
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
id = Column(Integer, primary_key=True, autoincrement=True)
organization_id = Column(Integer,
ForeignKey('organizations.id'),
nullable=False)
organization = relationship('Organizations',
back_populates='users')
class Organizations(Base):
__tablename__ = 'organizations'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(128))
users = relationship('Users', back_populates='organization')
Is there a better way to set up this relationship and/or how can we properly handle building up the model instead of it failing to do so?
I've never used viewonly myself, thanks for bringing this up. I've just tried to reproduce your problems with this (your example is incomplete, so I had to do some guesswork, e.g. you never use CommonColumns and get_current_user_id is not defined).
I've come up with https://github.com/pyeve/eve-sqlalchemy/tree/viewonly/eve_sqlalchemy/examples/viewonly and tried to POST to /nodes, which works fine and GET-ing gives created_by and organization (see below). Can you maybe amend this example to show your problems with viewonly?
$ curl -i -X POST -H "Content-Type: application/json" -d '{}' localhost:5000/nodes
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 227
Location: http://localhost:5000/nodes/1
Server: Eve/0.7.10 Werkzeug/0.11.15 Python/3.6.6
Date: Mon, 12 Nov 2018 07:54:55 GMT
{"_updated": "Mon, 12 Nov 2018 07:54:55 GMT", "_created": "Mon, 12 Nov 2018 07:54:55 GMT", "_etag": "d4c403081de4d25f9005fa33ef10fcaa4f2b0063", "id": 1, "_links": {"self": {"title": "Node", "href": "nodes/1"}}, "_status": "OK"}
$ curl -i -X POST -H "Content-Type: application/json" -d '{}' localhost:5000/nodes
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 227
Location: http://localhost:5000/nodes/2
Server: Eve/0.7.10 Werkzeug/0.11.15 Python/3.6.6
Date: Mon, 12 Nov 2018 07:54:57 GMT
{"_updated": "Mon, 12 Nov 2018 07:54:57 GMT", "_created": "Mon, 12 Nov 2018 07:54:57 GMT", "_etag": "9901a9d0f565369c2e49774aa3b3e3b4764f5aaf", "id": 2, "_links": {"self": {"title": "Node", "href": "nodes/2"}}, "_status": "OK"}
$ curl localhost:5000/nodes | python -m json.tool
{
"_items": [
{
"created_by": 1,
"updated_by": 1,
"organization": [
1
],
"id": 1,
"_updated": "Mon, 12 Nov 2018 07:54:55 GMT",
"_created": "Mon, 12 Nov 2018 07:54:55 GMT",
"_etag": "d4c403081de4d25f9005fa33ef10fcaa4f2b0063",
"_links": {
"self": {
"title": "Node",
"href": "nodes/1"
}
}
},
{
"created_by": 1,
"updated_by": 1,
"organization": [
1
],
"id": 2,
"_updated": "Mon, 12 Nov 2018 07:54:57 GMT",
"_created": "Mon, 12 Nov 2018 07:54:57 GMT",
"_etag": "9901a9d0f565369c2e49774aa3b3e3b4764f5aaf",
"_links": {
"self": {
"title": "Node",
"href": "nodes/2"
}
}
}
],
"_links": {
"parent": {
"title": "home",
"href": "/"
},
"self": {
"title": "nodes",
"href": "nodes"
}
},
"_meta": {
"page": 1,
"max_results": 25,
"total": 2
}
}