2

Playing with Flask, Graphene and am running into a problem. Consider the following.

The Model project.model.site:

from project import db
from project.models import user
from datetime import datetime

class Site(db.Model):
    __tablename__ = 'sites'
    id = db.Column(db.Integer(), primary_key=True)
    owner_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    name = db.Column(db.String(50))
    desc = db.Column(db.Text())
    location_lon = db.Column(db.String(50))
    location_lat = db.Column(db.String(50))
    creation_date = db.Column(db.DateTime(), default=datetime.utcnow())
    users = db.relationship(
        user,
        backref=db.backref('users',
                        uselist=True,
                        cascade='delete,all'))

The model schema (project.schemas.site_schema)

from graphene_sqlalchemy import SQLAlchemyObjectType
from project.models import site as site_model
import graphene

class SiteAttributes:
    owner_id = graphene.ID(description="Site owners user.id")
    name = graphene.String(description="Site Name")
    desc = graphene.String(description="Site description")
    location_lon = graphene.String(description="Site Longitude")
    location_lat = graphene.String(description="Site Latitude")
    creation_date = graphene.DateTime(description="Site Creation Date")

class Site(SQLAlchemyObjectType, SiteAttributes):
    """Site node."""
    class Meta:
        model = site_model
        interfaces = (graphene.relay.Node,)

and finally the main schema through which I plan to expose the GraphQL api (project.schemas.schema))

from graphene_sqlalchemy import SQLAlchemyConnectionField
import graphene
from project.schemas import site_schema, trade_schema, user_schema

class Query(graphene.ObjectType):
    """Query objects for GraphQL API."""

    node = graphene.relay.Node.Field()
    user = graphene.relay.Node.Field(user_schema.User)
    userList = SQLAlchemyConnectionField(user_schema.User)
    site = graphene.relay.Node.Field(site_schema.Site)
    siteList = SQLAlchemyConnectionField(site_schema.Site)
    trade = graphene.relay.Node.Field(trade_schema.Trade)
    tradeList = SQLAlchemyConnectionField(trade_schema.Trade)


schema = graphene.Schema(query=Query)

If I load the model as such when starting up all is well. Migrations happen, the application runs perfectly fine. If I load the model through the schema though the application fails with the following message:

AssertionError: You need to pass a valid SQLAlchemy Model in Site.Meta, received "<module 'project.models.site' from '/vagrant/src/project/models/site.py'>".

I initialized SQLAlchemy with flask_sqlalchemy. Which makes me wonder is the model that is created not considered a valid SQLAlchemy Model ? Or am I doing a basic error here that I am just not seeing. I am assuming it's the latter.

2 Answers2

4

Based on the error message, it seems that project.models.site (imported in the second snippet with from project.models import site as site_model) is a Python module rather than a subclass of db.Model or similar. Did you perhaps mean to import Site (uppercase) instead of site?

jwodder
  • 54,758
  • 12
  • 108
  • 124
  • I see how that might cause confusion. Alas, no, I added the file structure to each snippet to clarify. – Vevmesteren Oct 28 '18 at 00:12
  • 4
    @ValentinBackofen: That just confirms my answer — `project.models.site` *is* a module! The model is `project.models.site.Site`. – jwodder Oct 28 '18 at 00:14
  • Ha! Off course, thank you for that, temporary code blindness got the better of me yet again. got a new error now `AssertionError: You need to pass a valid SQLAlchemy Model in Site.Meta, received "".` – Vevmesteren Oct 28 '18 at 00:21
1

So fixing packages to classes finally go me in the right direction. It turns out that the issue was deeper then that. And the only way to get to it was by reading the hidden exceptions.

First I ensured that actual models where loaded rather than the modules. Thank you So much for that one @jwodder

In the end this https://github.com/graphql-python/graphene-sqlalchemy/issues/121 was ended up pointing me in the right direction. By checking the actual exception messages I found my way to a solution