{ "info": { "author": "Exley McCormick", "author_email": "exleym@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# Flask-Filter\nFiltering Extension for Flask / SQLAlchemy\n\nCheck out our\n[GitHub Pages site](https://exleym.github.io/Flask-Filter/) for the\nfull documentation.\n\n[![Build Status](https://travis-ci.org/exleym/Flask-Filter.svg?branch=master)](https://travis-ci.org/exleym/Flask-Filter)\n[![Coverage Status](https://coveralls.io/repos/github/exleym/Flask-Filter/badge.svg?branch=master)](https://coveralls.io/github/exleym/Flask-Filter?branch=master)\n[![PyPi][pypi-badge]][pypi]\n\nFlask-Filter is a simple [Flask](http://flask.pocoo.org/) extension for\nstandardizing behavior of REST API resource search endpoints. It is\ndesigned to integrate with the [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org/2.3/)\nextension and [Marshmallow](https://marshmallow.readthedocs.io/en/3.0/),\na popular serialization library.\n\nOut-of-the-box, Flask-Filter provides search functionality on top-level\nobject fields via an array of filter objects provided in the JSON body\nof a POST request. For configuring filtering on derived or nested fields\nsee the \"Filtering on Nested Fields\" section of the documentation.\n\n# Installation\nFlask-Filter is available on [PyPi][pypi]. To use this library, we recommend you \ninstall it via pip:\n\n```bash\n(venv)$ pip install flask-filter\n```\n\n# Default Filters\nFlask-Filter supports searching resources based on an array of filters,\nJSON objects with the following structure:\n\n```json\n{\"field\": \"\", \"op\": \"\", \"value\": \"\"}\n```\n\nThe built-in filters support the following operators:\n\n| symbol | operator | python filter class |\n|----------|------------------------------|-----------------------|\n| < | less-than | `LTFilter` |\n| <= | less-than or equal to | `LTEFilter` |\n| = | equal to | `EqualsFilter` |\n| > | greater-than | `GTFilter` |\n| >= | greater-than or equal to | `GTEFilter` |\n| in | in | `InFilter` |\n| != | not equal to | `NotEqualsFilter` |\n| like | like | `LikeFilter` |\n| contains | many-to-many associated | `ContainsFilter` |\n\nNote: Be careful with typing around comparator operators. This version\ndoes not provide rigorous type-checking, which could cause problems for\na user who submits a search like \"find Pets with name greater than\n'Fido'\"\n\nMany-to-many associations can be searched using the `contains` operator.\nFor a Dog object with a many-to-many relationship with \"favorite toys\" \ndefined as Dog.toys = [Toy(), Toy()], you can set the field to \"toys.name\",\nthe operator to \"contains\" and the value to \"Tennis Ball\". This will perform \na SQL \"any\" search on that field / value and return any Dog objects who like \ntennis balls.\n\n# Examples\nThis section demonstrates simplified use-cases for Flask-Filter. For\na complete example app (a Pet Store API), see the `/example` folder.\n\nNote: examples in this readme define simple `/search` endpoints that\nassume a working Flask app has already been initialized, and other\nrequired classes have been defined in a `pet_store` directory. To see\na full implementation, go to `/examples/pet_store`\n\n### Example 1: Manually implementing filters in a flask view\nUsing the `FilterSchema` class directly, you can deserialize an\narray of JSON filters into a list of `flask_filter.Filter` objects\nand directly apply the filters using `Filter.apply` to craft a\nSQLAlchemy query with a complex set of filters.\n\n```python\nfilter_schema = FilterSchema()\npet_schema = PetSchema()\n\n@app.route('/api/v1/pets/search', methods=['POST'])\ndef pet_search():\n filters = filter_schema.load(request.json.get(\"filters\"), many=True)\n query = Pet.query\n for f in filters:\n query = f.apply(query, Pet, PetSchema)\n return jsonify(pet_schema.dump(query.all())), 200\n```\n\n### Example 2: Automatically filtering using the `query_with_filters` function\n\n```python\nfrom flask_filter import query_with_filters\npet_schema = PetSchema()\n\n@app.route('/api/v1/pets/search', methods=['POST']\ndef pet_search():\n pets = query_with_filters(Pet, request.json.get(\"filters\"), PetSchema)\n return jsonify(pet_schema.dump(pets)), 200\n```\n\n\n### Example 3: Initializing and using the Flask extension object\n\n```python\nfrom flask import Flask\n\nfrom pet_store import Pet, PetSchema # Model defined as subclass of `db.Model`\nfrom pet_store.extensions import db, filtr # SQLAlchemy and FlaskFilter objects\n\napp = Flask(__name__)\ndb.init_app(app)\nfiltr.init_app(app)\n\n\n@app.route('/api/v1/pets/search', methods=['POST'])\ndef pet_search():\n pets = filtr.search(Pet, request.json.get(\"filters\"), PetSchema)\n return jsonify(pet_schema.dump(pets)), 200\n```\n\nor alternatively, if you pre-register the Model and Schema with the\n`FlaskFilter` object you do not need to pass the `Schema` directly to\nthe `search` method:\n\n```python\nfiltr.register_model(Dog, DogSchema) # Register in the app factory\n```\n\nfollowed by the search execution (without an explicitly-defined schema):\n\n```python\npets = filtr.search(Pet, request.json.get(\"filters\"))\n```\n\n### Example 4: Ordering Search Responses\nBy default, searches return objects ordered on `id`, ascending. This behavior \ncan be customized with the optional `order_by` argument.\n\nIf you don't have an `id` parameter for your database objects or you wish to \nsort by other fields, you should populate the `order_by` argument to the search \nfunction when you call it. \n\nThis approach does not allow API consumers to set the order_by argument, but \nallows the developer to override the default id ordering.\n```python\n@app.route('/api/v1/pets/search', methods=['POST'])\ndef pet_search():\n pets = filtr.search(Pet, request.json.get(\"filters\"), PetSchema,\n order_by=Pet.name)\n return jsonify(pet_schema.dump(pets)), 200\n```\n\nAlternatively, if you wish to allow users to customize the order of the \nobjects in the response, use a string for the `order_by` argument.\n\n```python\n@app.route('/api/v1/pets/search', methods=['POST'])\ndef pet_search():\n order_by = json.get(\"orderBy\") or \"name\"\n pets = filtr.search(Pet, request.json.get(\"filters\"), PetSchema,\n order_by=order_by)\n return jsonify(pet_schema.dump(pets)), 200\n```\n\n\n[pypi-badge]: https://badge.fury.io/py/Flask-Filter.svg\n[pypi]: https://pypi.org/project/Flask-Filter/\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/exleym/Flask-Filter", "keywords": "", "license": "Creative Commons Attribution-Noncommercial-Share Alike license", "maintainer": "", "maintainer_email": "", "name": "Flask-Filter", "package_url": "https://pypi.org/project/Flask-Filter/", "platform": "", "project_url": "https://pypi.org/project/Flask-Filter/", "project_urls": { "Homepage": "https://github.com/exleym/Flask-Filter" }, "release_url": "https://pypi.org/project/Flask-Filter/0.1.0.dev5/", "requires_dist": null, "requires_python": "", "summary": "A Flask extension for creating standard resource searches", "version": "0.1.0.dev5", "yanked": false, "yanked_reason": null }, "last_serial": 8146088, "releases": { "0.1.0.dev1": [ { "comment_text": "", "digests": { "md5": "96d27bfc82ca2a2b9e3207d00656c9bd", "sha256": "ddffca3eb542dcdafd9c7fa1122168cb5ad7d1e5ce10c06e9d32d33e8230c2a7" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev1-py3-none-any.whl", "has_sig": false, "md5_digest": "96d27bfc82ca2a2b9e3207d00656c9bd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7394, "upload_time": "2019-10-24T22:22:08", "upload_time_iso_8601": "2019-10-24T22:22:08.589785Z", "url": "https://files.pythonhosted.org/packages/8c/d9/74df8573c7b3182d63f3332499a687aee35c8dde49d94396d31295dd7945/Flask_Filter-0.1.0.dev1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "82fcca12c3dda29162d4471bb03f0e10", "sha256": "d468e4aaead10569db4c031a639c825d0e09e545ad3ed70ee32ce7c9a2727bb2" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev1.tar.gz", "has_sig": false, "md5_digest": "82fcca12c3dda29162d4471bb03f0e10", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5207, "upload_time": "2019-10-24T22:22:10", "upload_time_iso_8601": "2019-10-24T22:22:10.639659Z", "url": "https://files.pythonhosted.org/packages/18/f3/948791ddb1875972539a3e0d2a553cae7750ea849737432929047c8e532c/Flask-Filter-0.1.0.dev1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.0.dev2": [ { "comment_text": "", "digests": { "md5": "fcb73e37b44f2aa84d6257bab24421f1", "sha256": "4217fb443353e9152edd6ebea05bd85935909cffc362bd6c585d93076f30ae33" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev2-py3-none-any.whl", "has_sig": false, "md5_digest": "fcb73e37b44f2aa84d6257bab24421f1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7407, "upload_time": "2019-10-24T23:38:06", "upload_time_iso_8601": "2019-10-24T23:38:06.013253Z", "url": "https://files.pythonhosted.org/packages/03/64/2f10b293f72841850372ffd4d544d47e387081aa31b568193ce34c48f8be/Flask_Filter-0.1.0.dev2-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "0f477f1f73072a9fb85b095ff356356a", "sha256": "af13d7f09e0b6005eef134a000bf0afae75c103c0f3efc536d56d15024c9ad44" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev2.tar.gz", "has_sig": false, "md5_digest": "0f477f1f73072a9fb85b095ff356356a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5262, "upload_time": "2019-10-24T23:38:07", "upload_time_iso_8601": "2019-10-24T23:38:07.187982Z", "url": "https://files.pythonhosted.org/packages/56/53/c2d03ca31a96c01b175c22333222319a6b948c191a0e72a1ec1af18ef22d/Flask-Filter-0.1.0.dev2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.0.dev3": [ { "comment_text": "", "digests": { "md5": "75911eee6cf7f880b445aad13235af0a", "sha256": "df040e1a6bb6c840ac8230c0d3c6e937208445832b8ce00bfa41d2650b005e99" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev3-py3-none-any.whl", "has_sig": false, "md5_digest": "75911eee6cf7f880b445aad13235af0a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7951, "upload_time": "2020-04-23T22:41:52", "upload_time_iso_8601": "2020-04-23T22:41:52.602723Z", "url": "https://files.pythonhosted.org/packages/ff/18/ce306fa3e6d2942464ec1acbda5c99ef4b87267e186ec68edfc92c1490bd/Flask_Filter-0.1.0.dev3-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "7f6fbd175f3d81ac19b308ca1c27f9e7", "sha256": "00e35b380ee3784795bc7c9e7d1c8d97cd22bafca29515cb0c6c89fea7fa2a4d" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev3.tar.gz", "has_sig": false, "md5_digest": "7f6fbd175f3d81ac19b308ca1c27f9e7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5908, "upload_time": "2020-04-23T22:41:54", "upload_time_iso_8601": "2020-04-23T22:41:54.401951Z", "url": "https://files.pythonhosted.org/packages/04/15/b1d905032d845cb9f6ceca809c4f62c46cb15a7e4802d54761cc5111e5d9/Flask-Filter-0.1.0.dev3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.0.dev4": [ { "comment_text": "", "digests": { "md5": "d7a3f757928710bb0a0af024eb0f58b4", "sha256": "89450d366419a20c1bb2d37ffc860654b62776ba91f5c03fb69290b7b20409b0" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev4-py3-none-any.whl", "has_sig": false, "md5_digest": "d7a3f757928710bb0a0af024eb0f58b4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8310, "upload_time": "2020-09-02T17:55:40", "upload_time_iso_8601": "2020-09-02T17:55:40.040729Z", "url": "https://files.pythonhosted.org/packages/29/5f/4b24404aaf0e7c5192f90b9002a22b08ed23e6628b21438fbfde7584b7cf/Flask_Filter-0.1.0.dev4-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "f1da5274af3f51a8ee0922fd88733036", "sha256": "722574d80ed0af06afa810548957847d825798ff8f1e7d9f7022b9ceddae9649" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev4.tar.gz", "has_sig": false, "md5_digest": "f1da5274af3f51a8ee0922fd88733036", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6387, "upload_time": "2020-09-02T17:55:41", "upload_time_iso_8601": "2020-09-02T17:55:41.614722Z", "url": "https://files.pythonhosted.org/packages/99/fb/db653b9d12a0938c6db94807345bab79c06aae7e4a674ee74dc82483a086/Flask-Filter-0.1.0.dev4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.0.dev5": [ { "comment_text": "", "digests": { "md5": "120c0fcc3f9d4f0e92522f917f854fec", "sha256": "c4067d771c48182ba0e31fc44afa685fde70dce84e3f940008b549e0a24fa0d2" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev5-py3-none-any.whl", "has_sig": false, "md5_digest": "120c0fcc3f9d4f0e92522f917f854fec", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8562, "upload_time": "2020-09-09T14:53:06", "upload_time_iso_8601": "2020-09-09T14:53:06.173302Z", "url": "https://files.pythonhosted.org/packages/f7/58/14b7bb62bdaf87b75899f6aaeb65af688617b9ed2c14b4e7ae914525d34c/Flask_Filter-0.1.0.dev5-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "6889bda6346497b98d765b3f79211ba7", "sha256": "182c346ae3b95533243d0850d4ca85f370f17f96c190ec475603bdc77f9442e6" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev5.tar.gz", "has_sig": false, "md5_digest": "6889bda6346497b98d765b3f79211ba7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6478, "upload_time": "2020-09-09T14:53:07", "upload_time_iso_8601": "2020-09-09T14:53:07.534456Z", "url": "https://files.pythonhosted.org/packages/22/f2/1093ae85b3d27c1dae184d5224af74de47db932ed99f52e713d1c4142887/Flask-Filter-0.1.0.dev5.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "120c0fcc3f9d4f0e92522f917f854fec", "sha256": "c4067d771c48182ba0e31fc44afa685fde70dce84e3f940008b549e0a24fa0d2" }, "downloads": -1, "filename": "Flask_Filter-0.1.0.dev5-py3-none-any.whl", "has_sig": false, "md5_digest": "120c0fcc3f9d4f0e92522f917f854fec", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8562, "upload_time": "2020-09-09T14:53:06", "upload_time_iso_8601": "2020-09-09T14:53:06.173302Z", "url": "https://files.pythonhosted.org/packages/f7/58/14b7bb62bdaf87b75899f6aaeb65af688617b9ed2c14b4e7ae914525d34c/Flask_Filter-0.1.0.dev5-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "6889bda6346497b98d765b3f79211ba7", "sha256": "182c346ae3b95533243d0850d4ca85f370f17f96c190ec475603bdc77f9442e6" }, "downloads": -1, "filename": "Flask-Filter-0.1.0.dev5.tar.gz", "has_sig": false, "md5_digest": "6889bda6346497b98d765b3f79211ba7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6478, "upload_time": "2020-09-09T14:53:07", "upload_time_iso_8601": "2020-09-09T14:53:07.534456Z", "url": "https://files.pythonhosted.org/packages/22/f2/1093ae85b3d27c1dae184d5224af74de47db932ed99f52e713d1c4142887/Flask-Filter-0.1.0.dev5.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }