{"id":22183,"date":"2018-07-19T12:15:53","date_gmt":"2018-07-19T09:15:53","guid":{"rendered":"https:\/\/www.webcodegeeks.com\/?p=22183"},"modified":"2018-07-23T12:21:15","modified_gmt":"2018-07-23T09:21:15","slug":"part-1-sqlalchemy-models-to-json","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/","title":{"rendered":"Part 1: SQLAlchemy Models to JSON"},"content":{"rendered":"<p><em>This is the first of three posts about building a JSON API with Flask. <a href=\"https:\/\/www.webcodegeeks.com\/python\/part-2-building-a-flask-restful-api\/\" target=\"_blank\" rel=\"nofollow noopener\">Part 2<\/a> and <a href=\"https:\/\/www.webcodegeeks.com\/python\/part-3-flask-api-decorators-helpers\/\" target=\"_blank\" rel=\"nofollow noopener\">part 3<\/a> arrive tomorrow and the day after.<\/em><\/p>\n<p>I&#8217;ve <a href=\"https:\/\/stackoverflow.com\/questions\/5022066\/how-to-serialize-sqlalchemy-result-to-json\" target=\"_blank\" rel=\"nofollow noopener\">seen<\/a> <a href=\"https:\/\/stackoverflow.com\/questions\/7102754\/jsonify-a-sqlalchemy-result-set-in-flask\" target=\"_blank\" rel=\"nofollow noopener\">a<\/a> <a href=\"https:\/\/stackoverflow.com\/questions\/13539082\/restful-interface-in-flask-and-issues-serializing\" target=\"_blank\" rel=\"nofollow noopener\">lot<\/a> <a href=\"https:\/\/stackoverflow.com\/questions\/25737050\/jsonify-flask-sqlalchemy-many-to-one-relationship-in-flask\" target=\"_blank\" rel=\"nofollow noopener\">of<\/a> <a href=\"https:\/\/stackoverflow.com\/questions\/37783919\/flask-restful-vs-flask-restless-which-should-be-used-and-when\" target=\"_blank\" rel=\"nofollow noopener\">questions<\/a> on StackOverflow about how to turn SQLAlchemy models into JSON. When building a JSON API with Flask and <a href=\"https:\/\/www.sqlalchemy.org\/\" target=\"_blank\" rel=\"nofollow noopener\">SQLAlchemy<\/a>, you end up writing a lot of boilerplate api code just to serialize your models into JSON. Since I encountered this problem early on at WakaTime, I decided to share my solution here. You have some libraries available to help such as <a href=\"https:\/\/flask-restful.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"nofollow noopener\">Flask-RESTful<\/a>, <a href=\"https:\/\/flask-restless.readthedocs.io\/en\/stable\/\" target=\"_blank\" rel=\"nofollow noopener\">Flask-Restless<\/a>, or <a href=\"https:\/\/github.com\/closeio\/flask-restutils\" target=\"_blank\" rel=\"nofollow noopener\">flask-restutils<\/a>. However, back in 2013 when I started WakaTime these either weren\u2019t available or weren\u2019t stable. Thankfully it was trivial to loop through the columns of an SQLAlchemy model and produce a <code>dict<\/code>. That <code>dict<\/code> object could then be jsonified with <code>json.dumps<\/code> and returned from an API.<\/p>\n<h2>SQLAlchemy Model to Dictionary<\/h2>\n<p>To add a serialization method have all your SQLAlchemy models inherit from an abstract base class. This base class defines the <code>to_dict<\/code> method that loops through the model\u2019s columns and returns a dictionary.<\/p>\n<pre class=\"brush:sql; wrap-lines:false\">from flask import json\r\nfrom flask_sqlalchemy import SQLAlchemy\r\nfrom sqlalchemy.orm.attributes import QueryableAttribute\r\nfrom wakatime_website import app\r\n\r\ndb = SQLAlchemy(app)\r\n\r\nclass BaseModel(db.Model):\r\n    __abstract__ = True\r\n\r\n    def to_dict(self, show=None, _hide=[], _path=None):\r\n        \"\"\"Return a dictionary representation of this model.\"\"\"\r\n\r\n        show = show or []\r\n\r\n        hidden = self._hidden_fields if hasattr(self, \"_hidden_fields\") else []\r\n        default = self._default_fields if hasattr(self, \"_default_fields\") else []\r\n        default.extend(['id', 'modified_at', 'created_at'])\r\n\r\n        if not _path:\r\n            _path = self.__tablename__.lower()\r\n\r\n            def prepend_path(item):\r\n                item = item.lower()\r\n                if item.split(\".\", 1)[0] == _path:\r\n                    return item\r\n                if len(item) == 0:\r\n                    return item\r\n                if item[0] != \".\":\r\n                    item = \".%s\" % item\r\n                item = \"%s%s\" % (_path, item)\r\n                return item\r\n\r\n            _hide[:] = [prepend_path(x) for x in _hide]\r\n            show[:] = [prepend_path(x) for x in show]\r\n\r\n        columns = self.__table__.columns.keys()\r\n        relationships = self.__mapper__.relationships.keys()\r\n        properties = dir(self)\r\n\r\n        ret_data = {}\r\n\r\n        for key in columns:\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            check = \"%s.%s\" % (_path, key)\r\n            if check in _hide or key in hidden:\r\n                continue\r\n            if check in show or key in default:\r\n                ret_data[key] = getattr(self, key)\r\n\r\n        for key in relationships:\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            check = \"%s.%s\" % (_path, key)\r\n            if check in _hide or key in hidden:\r\n                continue\r\n            if check in show or key in default:\r\n                _hide.append(check)\r\n                is_list = self.__mapper__.relationships[key].uselist\r\n                if is_list:\r\n                    items = getattr(self, key)\r\n                    if self.__mapper__.relationships[key].query_class is not None:\r\n                        if hasattr(items, \"all\"):\r\n                            items = items.all()\r\n                    ret_data[key] = []\r\n                    for item in items:\r\n                        ret_data[key].append(\r\n                            item.to_dict(\r\n                                show=list(show),\r\n                                _hide=list(_hide),\r\n                                _path=(\"%s.%s\" % (_path, key.lower())),\r\n                            )\r\n                        )\r\n                else:\r\n                    if (\r\n                        self.__mapper__.relationships[key].query_class is not None\r\n                        or self.__mapper__.relationships[key].instrument_class\r\n                        is not None\r\n                    ):\r\n                        item = getattr(self, key)\r\n                        if item is not None:\r\n                            ret_data[key] = item.to_dict(\r\n                                show=list(show),\r\n                                _hide=list(_hide),\r\n                                _path=(\"%s.%s\" % (_path, key.lower())),\r\n                            )\r\n                        else:\r\n                            ret_data[key] = None\r\n                    else:\r\n                        ret_data[key] = getattr(self, key)\r\n\r\n        for key in list(set(properties) - set(columns) - set(relationships)):\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            if not hasattr(self.__class__, key):\r\n                continue\r\n            attr = getattr(self.__class__, key)\r\n            if not (isinstance(attr, property) or isinstance(attr, QueryableAttribute)):\r\n                continue\r\n            check = \"%s.%s\" % (_path, key)\r\n            if check in _hide or key in hidden:\r\n                continue\r\n            if check in show or key in default:\r\n                val = getattr(self, key)\r\n                if hasattr(val, \"to_dict\"):\r\n                    ret_data[key] = val.to_dict(\r\n                        show=list(show),\r\n                        _hide=list(_hide), _path=(\"%s.%s\" % (_path, key.lower()))\r\n                        _path=('%s.%s' % (path, key.lower())),\r\n                    )\r\n                else:\r\n                    try:\r\n                        ret_data[key] = json.loads(json.dumps(val))\r\n                    except:\r\n                        pass\r\n\r\n        return ret_data\r\n<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>Now we use this base class to print a <code>User<\/code> as a dictionary.<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">class User(BaseModel):\r\n    id = db.Column(UUID(), primary_key=True, default=uuid.uuid4)\r\n    username = db.Column(db.String(), nullabe=False, unique=True)\r\n    password = db.Column(db.String())\r\n    email_confirmed = db.Column(db.Boolean())\r\n    modified_at = db.Column(db.DateTime())\r\n    created_at = db.Column(db.DateTime(), nullable=False, default=datetime.utcnow)\r\n\r\n    _default_fields = [\r\n        \"username\",\r\n        \"joined_recently\",\r\n    ]\r\n    _hidden_fields = [\r\n        \"password\",\r\n    ]\r\n    _readonly_fields = [\r\n        \"email_confirmed\",\r\n    ]\r\n\r\n    @property\r\n    def joined_recently(self):\r\n        return self.created_at &gt; datetime.utcnow() - timedelta(days=3)\r\n\r\nuser = User(username=\"zzzeek\")\r\ndb.session.add(user)\r\ndb.session.commit()\r\n\r\nprint(user.to_dict())<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>Which prints:<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">{\r\n    'id': UUID('488345de-88a1-4c87-9304-46a1a31c9414'),\r\n    'username': 'zzzeek',\r\n    'joined_recently': True,\r\n    'modified_at': None,\r\n    'created_at': datetime.datetime(2018, 7, 11, 6, 28, 56, 905379),\r\n}<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>And is easily jsonified with:<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">json.dumps(user.to_dict())<\/pre>\n<h2>Defaults and hidden fields<\/h2>\n<p>You might have noticed the attributes on <code>User<\/code> listing default and hidden fields. These allow you to customize which columns from <code>User<\/code> are included in the returned dictionary. For example, if you want to include <code>email_confirmed<\/code> in your serialized user you would do:<\/p>\n<pre class=\"brush:sql; wrap-lines:false\">print(user.to_dict(show=['email_confirmed', 'password']))<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>Which prints:<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">{\r\n    'id': UUID('488345de-88a1-4c87-9304-46a1a31c9414'),\r\n    'username': 'zzzeek',\r\n    'email_confirmed': None,\r\n    'joined_recently': True,\r\n    'modified_at': None,\r\n    'created_at': datetime.datetime(2018, 7, 11, 6, 28, 56, 905379),\r\n}<\/pre>\n<p>Also notice that <code>password<\/code> was not included, since it\u2019s listed as hidden on <code>User<\/code>.<\/p>\n<h2>Updating an SQLAlchemy Model from a Dictionary<\/h2>\n<p>We have a <code>to_dict<\/code> method, but to support POST, PUT, and PATCH methods we need a <code>from_dict<\/code> method that takes a dictionary and updates the model\u2019s columns with the provided data. Let\u2019s add the <code>from_dict<\/code> method like this:<\/p>\n<pre class=\"brush:sql; wrap-lines:false\">from sqlalchemy.sql.expression import not_\r\n\r\nclass BaseModel(db.Model):\r\n    __abstract__ = True\r\n\r\n    def __init__(self, **kwargs):\r\n        kwargs[\"_force\"] = True\r\n        self.from_dict(**kwargs)\r\n\r\n    def to_dict(self, show=None, _hide=[], _path=None):\r\n        ...\r\n\r\n    def from_dict(self, **kwargs):\r\n        \"\"\"Update this model with a dictionary.\"\"\"\r\n\r\n        _force = kwargs.pop(\"_force\", False)\r\n\r\n        readonly = self._readonly_fields if hasattr(self, \"_readonly_fields\") else []\r\n        if hasattr(self, \"_hidden_fields\"):\r\n            readonly += self._hidden_fields\r\n\r\n        readonly += [\"id\", \"created_at\", \"modified_at\"]\r\n\r\n        columns = self.__table__.columns.keys()\r\n        relationships = self.__mapper__.relationships.keys()\r\n        properties = dir(self)\r\n\r\n        changes = {}\r\n\r\n        for key in columns:\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            allowed = True if _force or key not in readonly else False\r\n            exists = True if key in kwargs else False\r\n            if allowed and exists:\r\n                val = getattr(self, key)\r\n                if val != kwargs[key]:\r\n                    changes[key] = {\"old\": val, \"new\": kwargs[key]}\r\n                    setattr(self, key, kwargs[key])\r\n\r\n        for rel in relationships:\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            allowed = True if _force or rel not in readonly else False\r\n            exists = True if rel in kwargs else False\r\n            if allowed and exists:\r\n                is_list = self.__mapper__.relationships[rel].uselist\r\n                if is_list:\r\n                    valid_ids = []\r\n                    query = getattr(self, rel)\r\n                    cls = self.__mapper__.relationships[rel].argument()\r\n                    for item in kwargs[rel]:\r\n                        if (\r\n                            \"id\" in item\r\n                            and query.filter_by(id=item[\"id\"]).limit(1).count() == 1\r\n                        ):\r\n                            obj = cls.query.filter_by(id=item[\"id\"]).first()\r\n                            col_changes = obj.from_dict(**item)\r\n                            if col_changes:\r\n                                col_changes[\"id\"] = str(item[\"id\"])\r\n                                if rel in changes:\r\n                                    changes[rel].append(col_changes)\r\n                                else:\r\n                                    changes.update({rel: [col_changes]})\r\n                            valid_ids.append(str(item[\"id\"]))\r\n                        else:\r\n                            col = cls()\r\n                            col_changes = col.from_dict(**item)\r\n                            query.append(col)\r\n                            db.session.flush()\r\n                            if col_changes:\r\n                                col_changes[\"id\"] = str(col.id)\r\n                                if rel in changes:\r\n                                    changes[rel].append(col_changes)\r\n                                else:\r\n                                    changes.update({rel: [col_changes]})\r\n                            valid_ids.append(str(col.id))\r\n\r\n                    # delete rows from relationship that were not in kwargs[rel]\r\n                    for item in query.filter(not_(cls.id.in_(valid_ids))).all():\r\n                        col_changes = {\"id\": str(item.id), \"deleted\": True}\r\n                        if rel in changes:\r\n                            changes[rel].append(col_changes)\r\n                        else:\r\n                            changes.update({rel: [col_changes]})\r\n                        db.session.delete(item)\r\n\r\n                else:\r\n                    val = getattr(self, rel)\r\n                    if self.__mapper__.relationships[rel].query_class is not None:\r\n                        if val is not None:\r\n                            col_changes = val.from_dict(**kwargs[rel])\r\n                            if col_changes:\r\n                                changes.update({rel: col_changes})\r\n                    else:\r\n                        if val != kwargs[rel]:\r\n                            setattr(self, rel, kwargs[rel])\r\n                            changes[rel] = {\"old\": val, \"new\": kwargs[rel]}\r\n\r\n        for key in list(set(properties) - set(columns) - set(relationships)):\r\n            if key.startswith(\"_\"):\r\n                continue\r\n            allowed = True if _force or key not in readonly else False\r\n            exists = True if key in kwargs else False\r\n            if allowed and exists and getattr(self.__class__, key).fset is not None:\r\n                val = getattr(self, key)\r\n                if hasattr(val, \"to_dict\"):\r\n                    val = val.to_dict()\r\n                changes[key] = {\"old\": val, \"new\": kwargs[key]}\r\n                setattr(self, key, kwargs[key])\r\n\r\n        return changes<\/pre>\n<p>Using the new <code>from_dict<\/code> method we update our user with a dictionary:<\/p>\n<pre class=\"brush:sql; wrap-lines:false\">updates = {\r\n    \"username\": \"zoe\",\r\n    \"email_confirmed\": True,\r\n}\r\nuser.from_dict(**updates)\r\ndb.session.commit()\r\n\r\nprint(user.to_dict(show=['email_confirmed']))<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>Which prints:<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">{\r\n    'id': UUID('488345de-88a1-4c87-9304-46a1a31c9414'),\r\n    'username': 'zoe',\r\n    'email_confirmed': None,\r\n    'joined_recently': True,\r\n    'modified_at': datetime.datetime(2018, 7, 11, 6, 36, 47, 939084),\r\n    'created_at': datetime.datetime(2018, 7, 11, 6, 28, 56, 905379),\r\n}<\/pre>\n<p>Notice that <code>email_confirmed<\/code> is still <code>None<\/code> because it\u2019s marked as read only.<\/p>\n<h2>Relationships<\/h2>\n<p>Our <code>to_dict<\/code> and <code>from_dict<\/code> methods also work for relationships. For example, when our <code>User<\/code> model has many <code>Goal<\/code> models we can serialize <code>Goal<\/code> by default or with <code>show<\/code>:<\/p>\n<pre class=\"brush:sql; wrap-lines:false\">class User(BaseModel):\r\n    ...\r\n    goals = db.relationship('Goal', backref='user', lazy='dynamic')\r\n\r\nclass Goal(BaseModel):\r\n    id = db.Column(UUID(), primary_key=True, default=uuid.uuid4)\r\n    title = db.Column(db.String(), nullabe=False)\r\n    accomplished = db.Column(db.Boolean())\r\n    created_at = db.Column(db.DateTime(), nullable=False, default=datetime.utcnow)\r\n\r\n    _default_fields = [\r\n        \"title\",\r\n    ]\r\n\r\ngoal = Goal(title=\"Mountain\", accomplished=True)\r\nuser.goals.append(goal)\r\ndb.session.commit()\r\n\r\nprint(user.to_dict(show=['goals', 'goals.accomplished']))<\/pre>\n<p><span style=\"text-decoration: underline;\"><em>Which prints:<\/em><\/span><\/p>\n<pre class=\"brush:sql; wrap-lines:false\">{\r\n    'id': UUID('488345de-88a1-4c87-9304-46a1a31c9414'),\r\n    'username': 'zoe',\r\n    'goals': [\r\n        {\r\n            'id': UUID('c72cfef0-0988-45e4-9f4b-8a4a7d4f8d8f'),\r\n            'title': 'Mountain',\r\n            'accomplished': True,\r\n            'created_at': datetime.datetime(2018, 7, 11, 6, 45, 18, 299924),\r\n        },\r\n    ],\r\n    'joined_recently': True,\r\n    'modified_at': datetime.datetime(2018, 7, 11, 6, 36, 47, 939084),\r\n    'created_at': datetime.datetime(2018, 7, 11, 6, 28, 56, 905379),\r\n}<\/pre>\n<p>It even allows customizing columns of relationships, for ex: <code>goals.accomplished<\/code>.<\/p>\n<p>To see how this all fits into a RESTful API continue with <a href=\"https:\/\/www.webcodegeeks.com\/python\/part-2-building-a-flask-restful-api\/\" target=\"_blank\" rel=\"nofollow noopener\">Part 2: Building a Flask RESTful API<\/a>.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>Published on Web Code Geeks with permission by Alan Hamlett, partner at our <a href=\"\/\/www.webcodegeeks.com\/join-us\/wcg\/\" target=\"_blank\" rel=\"noopener\">WCG program<\/a>. See the original article here: <a href=\"https:\/\/wakatime.com\/blog\/32-part-1-sqlalchemy-models-to-json\" target=\"_blank\" rel=\"noopener\">Part 1: SQLAlchemy Models to JSON<\/a><\/p>\n<p>Opinions expressed by Web Code Geeks contributors are their own.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This is the first of three posts about building a JSON API with Flask. Part 2 and part 3 arrive tomorrow and the day after. I&#8217;ve seen a lot of questions on StackOverflow about how to turn SQLAlchemy models into JSON. When building a JSON API with Flask and SQLAlchemy, you end up writing a &hellip;<\/p>\n","protected":false},"author":7205,"featured_media":1651,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[465,40],"class_list":["post-22183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","tag-flask","tag-json"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-07-19T09:15:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-07-23T09:21:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Alan Hamlett\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@alanhamlett\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alan Hamlett\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\"},\"author\":{\"name\":\"Alan Hamlett\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/44e870ec5ce29036f262cee9e1d86d16\"},\"headline\":\"Part 1: SQLAlchemy Models to JSON\",\"datePublished\":\"2018-07-19T09:15:53+00:00\",\"dateModified\":\"2018-07-23T09:21:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\"},\"wordCount\":414,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"keywords\":[\"Flask\",\"JSON\"],\"articleSection\":[\"Python\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\",\"name\":\"Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"datePublished\":\"2018-07-19T09:15:53+00:00\",\"dateModified\":\"2018-07-23T09:21:15+00:00\",\"description\":\"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/python\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Part 1: SQLAlchemy Models to JSON\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/44e870ec5ce29036f262cee9e1d86d16\",\"name\":\"Alan Hamlett\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/19c4b485cf5773d8c3f6981415dbf2cead5ec7b021e5b13e95a6085cfe8e1c04?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/19c4b485cf5773d8c3f6981415dbf2cead5ec7b021e5b13e95a6085cfe8e1c04?s=96&d=mm&r=g\",\"caption\":\"Alan Hamlett\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/alanhamlett\/\",\"https:\/\/x.com\/alanhamlett\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/alan-hamlett\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026","description":"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/","og_locale":"en_US","og_type":"article","og_title":"Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026","og_description":"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!","og_url":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2018-07-19T09:15:53+00:00","article_modified_time":"2018-07-23T09:21:15+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","type":"image\/jpeg"}],"author":"Alan Hamlett","twitter_card":"summary_large_image","twitter_creator":"@alanhamlett","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Alan Hamlett","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/"},"author":{"name":"Alan Hamlett","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/44e870ec5ce29036f262cee9e1d86d16"},"headline":"Part 1: SQLAlchemy Models to JSON","datePublished":"2018-07-19T09:15:53+00:00","dateModified":"2018-07-23T09:21:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/"},"wordCount":414,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","keywords":["Flask","JSON"],"articleSection":["Python"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/","url":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/","name":"Part 1: SQLAlchemy Models to JSON - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","datePublished":"2018-07-19T09:15:53+00:00","dateModified":"2018-07-23T09:21:15+00:00","description":"Interested to learn more about sqlalchemy models? Then check out our article on how to build a JSON API with Flask Part 1 of 3!","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/python\/part-1-sqlalchemy-models-to-json\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Python","item":"https:\/\/www.webcodegeeks.com\/category\/python\/"},{"@type":"ListItem","position":3,"name":"Part 1: SQLAlchemy Models to JSON"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/44e870ec5ce29036f262cee9e1d86d16","name":"Alan Hamlett","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/19c4b485cf5773d8c3f6981415dbf2cead5ec7b021e5b13e95a6085cfe8e1c04?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/19c4b485cf5773d8c3f6981415dbf2cead5ec7b021e5b13e95a6085cfe8e1c04?s=96&d=mm&r=g","caption":"Alan Hamlett"},"sameAs":["https:\/\/www.linkedin.com\/in\/alanhamlett\/","https:\/\/x.com\/alanhamlett"],"url":"https:\/\/www.webcodegeeks.com\/author\/alan-hamlett\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/22183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/7205"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=22183"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/22183\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/1651"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=22183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=22183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=22183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}