# relations-restx
CRUD API from DB Modeling using the Flask-RESTX library
Relations overall is designed to be a simple, straight forward, flexible DIL (data interface layer).
Quite different from other DIL's, it has the singular, microservice based purpose to:
- Create models with very little code, independent of backends
- Create CRUD API with a database backend from those models with very little code
- Create microservices to use those same models but with that CRUD API as the backend
Ya, that last one is kinda new I guess.
Say we create a service, composed of microservices, which in turn is to be consumed by other services made of microservices.
You should only need to define the model once. Your conceptual structure is the same, to the DB, the API, and anything using that API. You shouldn't have say that structure over and over. You shouldn't have to define CRUD endpoints over and over. That's so boring, tedious, and unnecessary.
Furthermore, the conceptual structure is based not the backend of what you've going to use at that moment of time (scaling matters) but on the relations, how the pieces interact. If you know the structure of the data, that's all you need to interact with the data.
So with Relations, Models and Fields are defined independent of any backend, which instead is set at runtime. So the API will use a DB, everything else will use that API.
This creates the CRUD API from Resources pointing to Models.
Don't have great docs yet so I've included some of the unittests to show what's possible.
Btw, going to the root of the API generates a whole OpenAPI GUI. It's pretty!
# Example
## define
```python
import relations
import relations_pymysql
# The source is a string, the backend of which is defined at runtime
class SourceModel(relations.Model):
SOURCE = "RestXResource"
class Simple(SourceModel):
id = int
name = str
CHUNK = 2 # restrieves records 2 at a time
class Plain(SourceModel):
ID = None # This table has no primary id field
simple_id = int
name = str
# This makes Simple a parent of Plain
relations.OneToMany(Simple, Plain)
class Meta(SourceModel):
id = int
name = str
flag = bool
spend = float
people = set # JSON storage
stuff = list # JSON stroage
things = dict, {"extract": "for__0____1"} # Extracts things["for"][0][-1] as a virtual column
push = str, {"inject": "stuff___1__relations.io____1"} # Injects this value into stuff[-1]["relations.io"]["1"]
def subnet_attr(values, value):
values["address"] = str(value)
min_ip = value[0]
max_ip = value[-1]
values["min_address"] = str(min_ip)
values["min_value"] = int(min_ip)
values["max_address"] = str(max_ip)
values["max_value"] = int(max_ip)
class Net(SourceModel):
id = int
ip = ipaddress.IPv4Address, { # The field type is that of a class, with the storage being JSON
"attr": {
"compressed": "address", # Storge compressed attr as address key in JSON
"__int__": "value" # Storge int() as value key in JSON
},
"init": "address", # Initilize with address from JSON
"titles": "address", # Use address from JSON as the how to list this field
"extract": {
"address": str, # Extract address as virtual column
"value": int # Extra value as virtual column
}
}
subnet = ipaddress.IPv4Network, {
"attr": subnet_attr,
"init": "address",
"titles": "address"
}
TITLES = "ip__address" # When listing, use ip["address"] as display value
INDEX = "ip__value" # Create an index on the virtual column ip __value
# Define resources based on the models
class SimpleResource(relations_restx.Resource):
MODEL = Simple
class PlainResource(relations_restx.Resource):
MODEL = Plain
class MetaResource(relations_restx.Resource):
MODEL = Meta
class NetResource(relations_restx.Resource):
MODEL = Net
# With this statement, all the above models now have an in memory store backend
self.source = relations.unittest.MockSource("RestXResource")
# Create standard Flask and RESTX resources
self.app = flask.Flask("resource-api")
self.restx = relations_restx.Api(self.app)
# Add the Relations Resources and endpoints
self.restx.add_resource(SimpleResource, *SimpleResource.thy().endpoints())
self.restx.add_resource(PlainResource, *PlainResource.thy().endpoints())
self.restx.add_resource(MetaResource, *MetaResource.thy().endpoints())
self.restx.add_resource(NetResource, *NetResource.thy().endpoints())
# Use this as the client for all tests
self.api = self.app.test_client()
```
## options
Used with OpenGUI to dynamically build a form. So if you change fields and what not, the forms automatically adapt.
```python
response = self.api.options("/simple")
self.assertStatusFields(response, 200, [
{
"name": "id",
"kind": "int",
"readonly": True
},
{
"name": "name",
"kind": "str",
"required": True
}
], errors=[])
id = self.api.post("/simple", json={"simple": {"name": "ya"}}).json["simple"]["id"]
response = self.api.options(f"/simple/{id}")
self.assertStatusFields(response, 200, [
{
"name": "id",
"kind": "int",
"readonly": True,
"original": id
},
{
"name": "name",
"kind": "str",
"required": True,
"original": "ya"
}
], errors=[])
response = self.api.options(f"/simple/{id}", json={"simple": {"name": "sure"}})
self.assertStatusFields(response, 200, [
{
"name": "id",
"kind": "int",
"readonly": True,
"original": id
},
{
"name": "name",
"kind": "str",
"required": True,
"original": "ya",
"value": "sure"
}
], errors=[])
response = self.api.options(f"/plain", json={"likes": {"simple_id": "y"}})
self.assertStatusFields(response, 200, [
{
"name": "simple_id",
"kind": "int",
"options": [1],
"titles": {
'1': ["ya"]
},
"like": "y",
"format": [None],
"overflow": False,
"required": True
},
{
"name": "name",
"kind": "str",
"required": True
}
], errors=[])
response = self.api.options(f"/plain", json={"likes": {"simple_id": "n"}})
self.assertStatusFields(response, 200, [
{
"name": "simple_id",
"kind": "int",
"options": [],
"titles": {},
"like": "n",
"format": [None],
"overflow": False,
"required": True
},
{
"name": "name",
"kind": "str",
"required": True
}
], errors=[])
id = self.api.post("/net", json={"net": {"ip": "1.2.3.4", "subnet": "1.2.3.0/24"}}).json["net"]["id"]
response = self.api.options(f"/net/{id}")
self.assertStatusFields(response, 200, [
{
"name": "id",
"kind": "int",
"readonly": True,
"original": 1
},
{
"name": "ip",
"kind": "IPv4Address",
"original": {
"address": "1.2.3.4",
"value": 16909060
},
"init": {"address": "address"}
},
{
"name": "subnet",
"kind": "IPv4Network",
"original": {
"address": "1.2.3.0/24",
"min_address": "1.2.3.0",
"min_value": 16909056,
"max_address": "1.2.3.255",
"max_value": 16909311
},
"init": {"address": "address"}
}
], errors=[])
response = self.api.options("/meta")
self.assertStatusFields(response, 200, [
{
"name": "id",
"kind": "int",
"readonly": True
},
{
"name": "name",
"kind": "str",
"required": True
},
{
"name": "flag",
"kind": "bool"
},
{
"name": "spend",
"kind": "float"
},
{
"name": "people",
"kind": "set",
"default": []
},
{
"name": "stuff",
"kind": "list",
"default": []
},
{
"name": "things",
"kind": "dict",
"default": {}
},
{
"name": "push",
"kind": "str",
"inject": "stuff__-1__relations.io___1"
}
], errors=[])
```
## post
Used to create one or many, or perform a complex search with a JSON body.
```python
response = self.api.post("/simple")
self.assertStatusValue(response, 400, "message", "either simple or simples required")
response = self.api.post("/simple", json={"simple": {"name": "ya"}})
self.assertStatusModel(response, 201, "simple", {"name": "ya"})
simple = Simple.one(id=response.json["simple"]["id"])
self.assertEqual(simple.name, "ya")
response = self.api.post("/plain", json={"plains": [{"name": "sure"}]})
self.assertStatusModel(response, 201, "plains", [{"name": "sure"}])
self.assertEqual(Plain.one().name, "sure")
response = self.api.post("/simple", json={"filter": {"name": "ya"}})
self.assertStatusModel(response, 200, "simples", [{"id": simple.id, "name": "ya"}])
response = self.api.post("/simple", json={"filter": {"name": "ya"}, "count": True})
self.assertStatusModel(response, 200, "simples", 1)
```
## get
Used to retrieve one or many or even a count
```python
simple = Simple("ya").create()
simple.plain.add("whatevs").create()
response = self.api.get(f"/simple")
self.assertStatusModel(response, 200, "simples", [{"id": simple.id, "name": "ya"}])
self.assertStatusValue(response, 200, "formats", {})
response = self.api.get(f"/plain")
self.assertStatusModel(response, 200, "plains", [{"simple_id": simple.id, "name": "whatevs"}])
self.assertStatusValue(response, 200, "formats", {
"simple_id": {
"titles": {'1': ["ya"]},
"format": [None]
}
})
response = self.api.get(f"/simple/{simple.id}")
self.assertStatusModel(response, 200, "simple", {"id": simple.id, "name": "ya"})
response = self.api.get("/simple", json={"filter": {"name": "ya"}})
self.assertStatusModel(response, 200, "simples", [{"id": simple.id, "name": "ya"}])
self.assertStatusValue(response, 200, "overflow", False)
response = self.api.get("/simple", json={"filter": {"name": "no"}})
self.assertStatusModel(response, 200, "simples", [])
self.assertStatusValue(response, 200, "overflow", False)
Simple("sure").create()
Simple("fine").create()
response = self.api.get("/simple", json={"filter": {"like": "y"}})
self.assertStatusModels(response, 200, "simples", [{"id": simple.id, "name": "ya"}])
self.assertStatusValue(response, 200, "overflow", False)
response = self.api.get("/simple?limit=1&limit__start=1")
self.assertStatusModels(response, 200, "simples", [{"name": "sure"}])
self.assertStatusValue(response, 200, "overflow", True)
response = self.api.get("/simple?limit__per_page=1&limit__page=3")
self.assertStatusModels(response, 200, "simples", [{"name": "ya"}])
self.assertStatusValue(response, 200, "overflow", True)
self.assertStatusValue(response, 200, "formats", {})
simples = Simple.bulk()
for name in range(3):
simples.add(name)
simples.create()
self.assertEqual(self.api.get("/simple?count=yes").json["simples"], 6)
self.assertEqual(self.api.get("/simple", json={"count": True}).json["simples"], 6)
```
## patch
Used to update one (id) or many (filter).
```python
response = self.api.patch("/simple")
self.assertStatusValue(response, 400, "message", "either simple or simples required")
response = self.api.patch(f"/simple", json={"simple": {"name": "yep"}})
self.assertStatusModel(response, 400, "message", "to confirm all, send a blank filter {}")
simple = Simple("ya").create()
response = self.api.patch(f"/simple/{simple.id}", json={"simple": {"name": "yep"}})
self.assertStatusModel(response, 202, "updated", 1)
response = self.api.patch("/simple", json={"filter": {"name": "yep"}, "simple": {"name": "sure"}})
self.assertStatusModel(response, 202, "updated", 1)
response = self.api.patch("/simple", json={"filter": {"name": "sure"}, "simples": {"name": "whatever"}})
self.assertStatusModel(response, 202, "updated", 1)
response = self.api.patch("/simple", json={"filter": {"name": "no"}, "simples": {}})
self.assertStatusModel(response, 202, "updated", 0)
```
## delete
Use to delete one (id) or many (filter).
```python
response = self.api.delete(f"/simple")
self.assertStatusModel(response, 400, "message", "to confirm all, send a blank filter {}")
simple = Simple("ya").create()
response = self.api.delete(f"/simple/{simple.id}")
self.assertStatusModel(response, 202, "deleted", 1)
simple = Simple("sure").create()
response = self.api.delete("/simple", json={"filter": {"name": "sure"}})
self.assertStatusModel(response, 202, "deleted", 1)
response = self.api.delete("/simple", json={"filter": {"name": "no"}})
self.assertStatusModel(response, 202, "deleted", 0)
```
Raw data
{
"_id": null,
"home_page": "https://github.com/relations-dil/python-relations-restx",
"name": "relations-restx",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Gaffer Fitch",
"author_email": "relations@gaf3.com",
"download_url": "https://files.pythonhosted.org/packages/c1/f1/c9c1300edee82321ac41402f4d8993259a2c989fcc1d3fa02dfb59d9cf13/relations-restx-0.6.2.tar.gz",
"platform": null,
"description": "# relations-restx\n\nCRUD API from DB Modeling using the Flask-RESTX library\n\nRelations overall is designed to be a simple, straight forward, flexible DIL (data interface layer).\n\nQuite different from other DIL's, it has the singular, microservice based purpose to:\n- Create models with very little code, independent of backends\n- Create CRUD API with a database backend from those models with very little code\n- Create microservices to use those same models but with that CRUD API as the backend\n\nYa, that last one is kinda new I guess.\n\nSay we create a service, composed of microservices, which in turn is to be consumed by other services made of microservices.\n\nYou should only need to define the model once. Your conceptual structure is the same, to the DB, the API, and anything using that API. You shouldn't have say that structure over and over. You shouldn't have to define CRUD endpoints over and over. That's so boring, tedious, and unnecessary.\n\nFurthermore, the conceptual structure is based not the backend of what you've going to use at that moment of time (scaling matters) but on the relations, how the pieces interact. If you know the structure of the data, that's all you need to interact with the data.\n\nSo with Relations, Models and Fields are defined independent of any backend, which instead is set at runtime. So the API will use a DB, everything else will use that API.\n\nThis creates the CRUD API from Resources pointing to Models.\n\nDon't have great docs yet so I've included some of the unittests to show what's possible.\n\nBtw, going to the root of the API generates a whole OpenAPI GUI. It's pretty!\n\n# Example\n\n## define\n\n```python\n\nimport relations\nimport relations_pymysql\n\n# The source is a string, the backend of which is defined at runtime\n\nclass SourceModel(relations.Model):\n SOURCE = \"RestXResource\"\n\nclass Simple(SourceModel):\n id = int\n name = str\n CHUNK = 2 # restrieves records 2 at a time\n\nclass Plain(SourceModel):\n ID = None # This table has no primary id field\n simple_id = int\n name = str\n\n# This makes Simple a parent of Plain\n\nrelations.OneToMany(Simple, Plain)\n\nclass Meta(SourceModel):\n id = int\n name = str\n flag = bool\n spend = float\n people = set # JSON storage\n stuff = list # JSON stroage\n things = dict, {\"extract\": \"for__0____1\"} # Extracts things[\"for\"][0][-1] as a virtual column\n push = str, {\"inject\": \"stuff___1__relations.io____1\"} # Injects this value into stuff[-1][\"relations.io\"][\"1\"]\n\ndef subnet_attr(values, value):\n\n values[\"address\"] = str(value)\n min_ip = value[0]\n max_ip = value[-1]\n values[\"min_address\"] = str(min_ip)\n values[\"min_value\"] = int(min_ip)\n values[\"max_address\"] = str(max_ip)\n values[\"max_value\"] = int(max_ip)\n\nclass Net(SourceModel):\n\n id = int\n ip = ipaddress.IPv4Address, { # The field type is that of a class, with the storage being JSON\n \"attr\": {\n \"compressed\": \"address\", # Storge compressed attr as address key in JSON\n \"__int__\": \"value\" # Storge int() as value key in JSON\n },\n \"init\": \"address\", # Initilize with address from JSON\n \"titles\": \"address\", # Use address from JSON as the how to list this field\n \"extract\": {\n \"address\": str, # Extract address as virtual column\n \"value\": int # Extra value as virtual column\n }\n }\n subnet = ipaddress.IPv4Network, {\n \"attr\": subnet_attr,\n \"init\": \"address\",\n \"titles\": \"address\"\n }\n\n TITLES = \"ip__address\" # When listing, use ip[\"address\"] as display value\n INDEX = \"ip__value\" # Create an index on the virtual column ip __value\n\n# Define resources based on the models\n\nclass SimpleResource(relations_restx.Resource):\n MODEL = Simple\n\nclass PlainResource(relations_restx.Resource):\n MODEL = Plain\n\nclass MetaResource(relations_restx.Resource):\n MODEL = Meta\n\nclass NetResource(relations_restx.Resource):\n MODEL = Net\n\n# With this statement, all the above models now have an in memory store backend\n\nself.source = relations.unittest.MockSource(\"RestXResource\")\n\n# Create standard Flask and RESTX resources\n\nself.app = flask.Flask(\"resource-api\")\nself.restx = relations_restx.Api(self.app)\n\n# Add the Relations Resources and endpoints\n\nself.restx.add_resource(SimpleResource, *SimpleResource.thy().endpoints())\nself.restx.add_resource(PlainResource, *PlainResource.thy().endpoints())\nself.restx.add_resource(MetaResource, *MetaResource.thy().endpoints())\nself.restx.add_resource(NetResource, *NetResource.thy().endpoints())\n\n# Use this as the client for all tests\n\nself.api = self.app.test_client()\n```\n\n## options\n\nUsed with OpenGUI to dynamically build a form. So if you change fields and what not, the forms automatically adapt.\n\n```python\nresponse = self.api.options(\"/simple\")\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"id\",\n \"kind\": \"int\",\n \"readonly\": True\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True\n }\n], errors=[])\n\nid = self.api.post(\"/simple\", json={\"simple\": {\"name\": \"ya\"}}).json[\"simple\"][\"id\"]\n\nresponse = self.api.options(f\"/simple/{id}\")\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"id\",\n \"kind\": \"int\",\n \"readonly\": True,\n \"original\": id\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True,\n \"original\": \"ya\"\n }\n], errors=[])\n\nresponse = self.api.options(f\"/simple/{id}\", json={\"simple\": {\"name\": \"sure\"}})\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"id\",\n \"kind\": \"int\",\n \"readonly\": True,\n \"original\": id\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True,\n \"original\": \"ya\",\n \"value\": \"sure\"\n }\n], errors=[])\n\nresponse = self.api.options(f\"/plain\", json={\"likes\": {\"simple_id\": \"y\"}})\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"simple_id\",\n \"kind\": \"int\",\n \"options\": [1],\n \"titles\": {\n '1': [\"ya\"]\n },\n \"like\": \"y\",\n \"format\": [None],\n \"overflow\": False,\n \"required\": True\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True\n }\n], errors=[])\n\nresponse = self.api.options(f\"/plain\", json={\"likes\": {\"simple_id\": \"n\"}})\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"simple_id\",\n \"kind\": \"int\",\n \"options\": [],\n \"titles\": {},\n \"like\": \"n\",\n \"format\": [None],\n \"overflow\": False,\n \"required\": True\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True\n }\n], errors=[])\n\nid = self.api.post(\"/net\", json={\"net\": {\"ip\": \"1.2.3.4\", \"subnet\": \"1.2.3.0/24\"}}).json[\"net\"][\"id\"]\n\nresponse = self.api.options(f\"/net/{id}\")\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"id\",\n \"kind\": \"int\",\n \"readonly\": True,\n \"original\": 1\n },\n {\n \"name\": \"ip\",\n \"kind\": \"IPv4Address\",\n \"original\": {\n \"address\": \"1.2.3.4\",\n \"value\": 16909060\n },\n \"init\": {\"address\": \"address\"}\n },\n {\n \"name\": \"subnet\",\n \"kind\": \"IPv4Network\",\n \"original\": {\n \"address\": \"1.2.3.0/24\",\n \"min_address\": \"1.2.3.0\",\n \"min_value\": 16909056,\n \"max_address\": \"1.2.3.255\",\n \"max_value\": 16909311\n },\n \"init\": {\"address\": \"address\"}\n }\n], errors=[])\n\nresponse = self.api.options(\"/meta\")\nself.assertStatusFields(response, 200, [\n {\n \"name\": \"id\",\n \"kind\": \"int\",\n \"readonly\": True\n },\n {\n \"name\": \"name\",\n \"kind\": \"str\",\n \"required\": True\n },\n {\n \"name\": \"flag\",\n \"kind\": \"bool\"\n },\n {\n \"name\": \"spend\",\n \"kind\": \"float\"\n },\n {\n \"name\": \"people\",\n \"kind\": \"set\",\n \"default\": []\n },\n {\n \"name\": \"stuff\",\n \"kind\": \"list\",\n \"default\": []\n },\n {\n \"name\": \"things\",\n \"kind\": \"dict\",\n \"default\": {}\n },\n {\n \"name\": \"push\",\n \"kind\": \"str\",\n \"inject\": \"stuff__-1__relations.io___1\"\n }\n], errors=[])\n```\n\n## post\n\nUsed to create one or many, or perform a complex search with a JSON body.\n\n```python\nresponse = self.api.post(\"/simple\")\nself.assertStatusValue(response, 400, \"message\", \"either simple or simples required\")\n\nresponse = self.api.post(\"/simple\", json={\"simple\": {\"name\": \"ya\"}})\nself.assertStatusModel(response, 201, \"simple\", {\"name\": \"ya\"})\nsimple = Simple.one(id=response.json[\"simple\"][\"id\"])\nself.assertEqual(simple.name, \"ya\")\n\nresponse = self.api.post(\"/plain\", json={\"plains\": [{\"name\": \"sure\"}]})\nself.assertStatusModel(response, 201, \"plains\", [{\"name\": \"sure\"}])\nself.assertEqual(Plain.one().name, \"sure\")\n\nresponse = self.api.post(\"/simple\", json={\"filter\": {\"name\": \"ya\"}})\nself.assertStatusModel(response, 200, \"simples\", [{\"id\": simple.id, \"name\": \"ya\"}])\n\nresponse = self.api.post(\"/simple\", json={\"filter\": {\"name\": \"ya\"}, \"count\": True})\nself.assertStatusModel(response, 200, \"simples\", 1)\n```\n\n## get\n\nUsed to retrieve one or many or even a count\n\n```python\nsimple = Simple(\"ya\").create()\nsimple.plain.add(\"whatevs\").create()\n\nresponse = self.api.get(f\"/simple\")\nself.assertStatusModel(response, 200, \"simples\", [{\"id\": simple.id, \"name\": \"ya\"}])\nself.assertStatusValue(response, 200, \"formats\", {})\n\nresponse = self.api.get(f\"/plain\")\nself.assertStatusModel(response, 200, \"plains\", [{\"simple_id\": simple.id, \"name\": \"whatevs\"}])\nself.assertStatusValue(response, 200, \"formats\", {\n \"simple_id\": {\n \"titles\": {'1': [\"ya\"]},\n \"format\": [None]\n }\n})\n\nresponse = self.api.get(f\"/simple/{simple.id}\")\nself.assertStatusModel(response, 200, \"simple\", {\"id\": simple.id, \"name\": \"ya\"})\n\nresponse = self.api.get(\"/simple\", json={\"filter\": {\"name\": \"ya\"}})\nself.assertStatusModel(response, 200, \"simples\", [{\"id\": simple.id, \"name\": \"ya\"}])\nself.assertStatusValue(response, 200, \"overflow\", False)\n\nresponse = self.api.get(\"/simple\", json={\"filter\": {\"name\": \"no\"}})\nself.assertStatusModel(response, 200, \"simples\", [])\nself.assertStatusValue(response, 200, \"overflow\", False)\n\nSimple(\"sure\").create()\nSimple(\"fine\").create()\n\nresponse = self.api.get(\"/simple\", json={\"filter\": {\"like\": \"y\"}})\nself.assertStatusModels(response, 200, \"simples\", [{\"id\": simple.id, \"name\": \"ya\"}])\nself.assertStatusValue(response, 200, \"overflow\", False)\n\nresponse = self.api.get(\"/simple?limit=1&limit__start=1\")\nself.assertStatusModels(response, 200, \"simples\", [{\"name\": \"sure\"}])\nself.assertStatusValue(response, 200, \"overflow\", True)\n\nresponse = self.api.get(\"/simple?limit__per_page=1&limit__page=3\")\nself.assertStatusModels(response, 200, \"simples\", [{\"name\": \"ya\"}])\nself.assertStatusValue(response, 200, \"overflow\", True)\nself.assertStatusValue(response, 200, \"formats\", {})\n\nsimples = Simple.bulk()\n\nfor name in range(3):\n simples.add(name)\n\nsimples.create()\n\nself.assertEqual(self.api.get(\"/simple?count=yes\").json[\"simples\"], 6)\nself.assertEqual(self.api.get(\"/simple\", json={\"count\": True}).json[\"simples\"], 6)\n```\n\n## patch\n\nUsed to update one (id) or many (filter).\n\n```python\nresponse = self.api.patch(\"/simple\")\nself.assertStatusValue(response, 400, \"message\", \"either simple or simples required\")\n\nresponse = self.api.patch(f\"/simple\", json={\"simple\": {\"name\": \"yep\"}})\nself.assertStatusModel(response, 400, \"message\", \"to confirm all, send a blank filter {}\")\n\nsimple = Simple(\"ya\").create()\nresponse = self.api.patch(f\"/simple/{simple.id}\", json={\"simple\": {\"name\": \"yep\"}})\nself.assertStatusModel(response, 202, \"updated\", 1)\n\nresponse = self.api.patch(\"/simple\", json={\"filter\": {\"name\": \"yep\"}, \"simple\": {\"name\": \"sure\"}})\nself.assertStatusModel(response, 202, \"updated\", 1)\n\nresponse = self.api.patch(\"/simple\", json={\"filter\": {\"name\": \"sure\"}, \"simples\": {\"name\": \"whatever\"}})\nself.assertStatusModel(response, 202, \"updated\", 1)\n\nresponse = self.api.patch(\"/simple\", json={\"filter\": {\"name\": \"no\"}, \"simples\": {}})\nself.assertStatusModel(response, 202, \"updated\", 0)\n```\n\n## delete\n\nUse to delete one (id) or many (filter).\n\n```python\nresponse = self.api.delete(f\"/simple\")\nself.assertStatusModel(response, 400, \"message\", \"to confirm all, send a blank filter {}\")\n\nsimple = Simple(\"ya\").create()\nresponse = self.api.delete(f\"/simple/{simple.id}\")\nself.assertStatusModel(response, 202, \"deleted\", 1)\n\nsimple = Simple(\"sure\").create()\nresponse = self.api.delete(\"/simple\", json={\"filter\": {\"name\": \"sure\"}})\nself.assertStatusModel(response, 202, \"deleted\", 1)\n\nresponse = self.api.delete(\"/simple\", json={\"filter\": {\"name\": \"no\"}})\nself.assertStatusModel(response, 202, \"deleted\", 0)\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "CRUD API from DB Modeling using the Flask-RESTX library",
"version": "0.6.2",
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"md5": "3185e0ad0ca2a9e920b184b948a18c6f",
"sha256": "34fe597fee82a898cba70c7357bfade4e2c3a57429c4c147a8fae8e9d33a0504"
},
"downloads": -1,
"filename": "relations_restx-0.6.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3185e0ad0ca2a9e920b184b948a18c6f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 13074,
"upload_time": "2022-12-10T21:09:31",
"upload_time_iso_8601": "2022-12-10T21:09:31.096939Z",
"url": "https://files.pythonhosted.org/packages/c5/0a/9bc6f0a4f0d7aa157eeec1146ff87313ef1c98264e4307cb6a0446a9cfdc/relations_restx-0.6.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "7746445e16c6ce93e80432dbc80c39d1",
"sha256": "812b60f36c71d21002a8ef5bfa3d1e994db308a1240d292074fde8b5d8f324f8"
},
"downloads": -1,
"filename": "relations-restx-0.6.2.tar.gz",
"has_sig": false,
"md5_digest": "7746445e16c6ce93e80432dbc80c39d1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 15554,
"upload_time": "2022-12-10T21:09:33",
"upload_time_iso_8601": "2022-12-10T21:09:33.041718Z",
"url": "https://files.pythonhosted.org/packages/c1/f1/c9c1300edee82321ac41402f4d8993259a2c989fcc1d3fa02dfb59d9cf13/relations-restx-0.6.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-12-10 21:09:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "relations-dil",
"github_project": "python-relations-restx",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "opengui",
"specs": [
[
"==",
"0.8.8"
]
]
},
{
"name": "relations-dil",
"specs": [
[
"==",
"0.6.12"
]
]
},
{
"name": "Werkzeug",
"specs": [
[
"==",
"2.1.2"
]
]
},
{
"name": "flask",
"specs": [
[
"==",
"2.1.2"
]
]
},
{
"name": "flask-restx",
"specs": [
[
"==",
"0.5.1"
]
]
},
{
"name": "ptvsd",
"specs": [
[
"==",
"4.3.2"
]
]
},
{
"name": "coverage",
"specs": [
[
"==",
"5.2.1"
]
]
},
{
"name": "pylint",
"specs": [
[
"==",
"2.5.3"
]
]
}
],
"lcname": "relations-restx"
}