├── .env ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── Pipfile ├── Pipfile.lock ├── README.md ├── alembic.ini ├── alembic ├── README ├── env.py ├── script.py.mako └── versions │ └── 7972a23eaea8_first_migration.py ├── docker-compose.yml ├── main.py ├── models.py └── schema.py /.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL = postgresql+psycopg2://postgres:postgres@db:5432 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Compiled python modules. 3 | *.pyc 4 | 5 | # Setuptools distribution folder. 6 | /dist/ 7 | 8 | # Python egg metadata, regenerated from source files by setuptools. 9 | /*.egg-info 10 | /*.egg 11 | .vscode 12 | .coverage 13 | .pytest_cache 14 | .pypirc -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/home/ahmed/.local/share/virtualenvs/fastapi_sqlalchemy_alembic-RRSReEYP/bin/python", 3 | "python.formatting.provider": "black", 4 | "python.linting.flake8Path": "/home/ahmed/.local/share/virtualenvs/fastapi_sqlalchemy_alembic-RRSReEYP/bin/flake8" 5 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Pull base image 2 | FROM python:3.7 3 | 4 | # Set environment varibles 5 | ENV PYTHONDONTWRITEBYTECODE 1 6 | ENV PYTHONUNBUFFERED 1 7 | 8 | WORKDIR /code/ 9 | 10 | # Install dependencies 11 | RUN pip install pipenv 12 | COPY Pipfile Pipfile.lock /code/ 13 | RUN pipenv install --system --dev 14 | 15 | COPY . /code/ 16 | 17 | EXPOSE 8000 -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | flake8 = "*" 8 | ipython = "*" 9 | black = "*" 10 | 11 | [packages] 12 | fastapi = "*" 13 | fastapi-sqlalchemy = "*" 14 | pydantic = "*" 15 | alembic = "*" 16 | psycopg2 = "*" 17 | uvicorn = "*" 18 | python-dotenv = "*" 19 | 20 | [requires] 21 | python_version = "3.7" 22 | 23 | [pipenv] 24 | allow_prereleases = true 25 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "d0ab9af4ffbfd001deb6ca90ad9bb30869d1da327e5a6241e77f426b968bd25a" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "alembic": { 20 | "hashes": [ 21 | "sha256:2df2519a5b002f881517693b95626905a39c5faf4b5a1f94de4f1441095d1d26" 22 | ], 23 | "index": "pypi", 24 | "version": "==1.4.0" 25 | }, 26 | "click": { 27 | "hashes": [ 28 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 29 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 30 | ], 31 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 32 | "version": "==7.1.2" 33 | }, 34 | "fastapi": { 35 | "hashes": [ 36 | "sha256:68395725aac4342896b4f9aa335c7e7fb773b565df7f96e964e24bffb84dc5a3", 37 | "sha256:e3b479c61d8a02ec6c80ebbc2ee2d621a32855ffffedd55fd5f2993c6dbdcc1e" 38 | ], 39 | "index": "pypi", 40 | "version": "==0.49.2" 41 | }, 42 | "fastapi-sqlalchemy": { 43 | "hashes": [ 44 | "sha256:00f2bab2349e491262aaef6bb098105f00cc2218e8190c34139f7730686209c8", 45 | "sha256:e8ddf9fb9d53b321eee841183d2b3b7e5b4e27fe1ce85696e5a814aa01d509a1" 46 | ], 47 | "index": "pypi", 48 | "version": "==0.1.1" 49 | }, 50 | "greenlet": { 51 | "hashes": [ 52 | "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711", 53 | "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd", 54 | "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073", 55 | "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708", 56 | "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67", 57 | "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23", 58 | "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1", 59 | "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08", 60 | "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd", 61 | "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa", 62 | "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8", 63 | "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40", 64 | "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab", 65 | "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6", 66 | "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc", 67 | "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b", 68 | "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e", 69 | "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963", 70 | "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3", 71 | "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d", 72 | "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d", 73 | "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28", 74 | "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3", 75 | "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e", 76 | "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c", 77 | "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d", 78 | "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0", 79 | "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497", 80 | "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee", 81 | "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713", 82 | "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58", 83 | "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a", 84 | "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06", 85 | "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88", 86 | "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4", 87 | "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5", 88 | "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c", 89 | "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a", 90 | "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1", 91 | "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43", 92 | "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627", 93 | "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b", 94 | "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168", 95 | "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d", 96 | "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5", 97 | "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478", 98 | "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf", 99 | "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce", 100 | "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c", 101 | "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b" 102 | ], 103 | "markers": "python_version >= '3' and platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", 104 | "version": "==1.1.2" 105 | }, 106 | "h11": { 107 | "hashes": [ 108 | "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1", 109 | "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1" 110 | ], 111 | "version": "==0.9.0" 112 | }, 113 | "httptools": { 114 | "hashes": [ 115 | "sha256:07659649fe6b3948b6490825f89abe5eb1cec79ebfaaa0b4bf30f3f33f3c2ba8", 116 | "sha256:08b79e09114e6ab5c3dbf560bba2cb2257ea38cdaeaf99b7cb80d8f92622fcd9", 117 | "sha256:1e35aa179b67086cc600a984924a88589b90793c9c1b260152ca4908786e09df", 118 | "sha256:31629e1f1b89959f8c0927bad12184dc07977dcf71e24f4772934aa490aa199b", 119 | "sha256:851026bd63ec0af7e7592890d97d15c92b62d9e17094353f19a52c8e2b33710a", 120 | "sha256:8fcca4b7efe353b13a24017211334c57d055a6e132c7adffed13a10d28efca57", 121 | "sha256:9abd788465aa46a0f288bd3a99e53edd184177d6379e2098fd6097bb359ad9d6", 122 | "sha256:aebdf0bd7bf7c90ae6b3be458692bf6e9e5b610b501f9f74c7979015a51db4c4", 123 | "sha256:bda99a5723e7eab355ce57435c70853fc137a65aebf2f1cd4d15d96e2956da7b", 124 | "sha256:c1c63d860749841024951b0a78e4dec6f543d23751ef061d6ab60064c7b8b524", 125 | "sha256:c4111a0a8a00eff1e495d43ea5230aaf64968a48ddba8ea2d5f982efae827404", 126 | "sha256:dce59ee45dd6ee6c434346a5ac527c44014326f560866b4b2f414a692ee1aca8", 127 | "sha256:f759717ca1b2ef498c67ba4169c2b33eecf943a89f5329abcff8b89d153eb500", 128 | "sha256:fb7199b8fb0c50a22e77260bb59017e0c075fa80cb03bb2c8692de76e7bb7fe7", 129 | "sha256:fbf7ecd31c39728f251b1c095fd27c84e4d21f60a1d079a0333472ff3ae59d34" 130 | ], 131 | "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'", 132 | "version": "==0.1.2" 133 | }, 134 | "importlib-metadata": { 135 | "hashes": [ 136 | "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", 137 | "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" 138 | ], 139 | "markers": "python_version < '3.8'", 140 | "version": "==4.8.2" 141 | }, 142 | "mako": { 143 | "hashes": [ 144 | "sha256:4e9e345a41924a954251b95b4b28e14a301145b544901332e658907a7464b6b2", 145 | "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57" 146 | ], 147 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 148 | "version": "==1.1.6" 149 | }, 150 | "markupsafe": { 151 | "hashes": [ 152 | "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", 153 | "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", 154 | "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", 155 | "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", 156 | "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", 157 | "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", 158 | "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", 159 | "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", 160 | "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", 161 | "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", 162 | "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", 163 | "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", 164 | "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", 165 | "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", 166 | "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", 167 | "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", 168 | "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", 169 | "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", 170 | "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", 171 | "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", 172 | "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", 173 | "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", 174 | "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", 175 | "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", 176 | "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", 177 | "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", 178 | "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", 179 | "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", 180 | "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", 181 | "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", 182 | "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", 183 | "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", 184 | "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", 185 | "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", 186 | "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", 187 | "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", 188 | "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", 189 | "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", 190 | "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", 191 | "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", 192 | "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", 193 | "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", 194 | "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", 195 | "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", 196 | "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", 197 | "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", 198 | "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", 199 | "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", 200 | "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", 201 | "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", 202 | "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", 203 | "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", 204 | "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", 205 | "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", 206 | "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", 207 | "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", 208 | "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", 209 | "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", 210 | "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", 211 | "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", 212 | "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", 213 | "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", 214 | "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", 215 | "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", 216 | "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", 217 | "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", 218 | "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", 219 | "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", 220 | "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" 221 | ], 222 | "markers": "python_version >= '3.6'", 223 | "version": "==2.0.1" 224 | }, 225 | "psycopg2": { 226 | "hashes": [ 227 | "sha256:4212ca404c4445dc5746c0d68db27d2cbfb87b523fe233dc84ecd24062e35677", 228 | "sha256:47fc642bf6f427805daf52d6e52619fe0637648fe27017062d898f3bf891419d", 229 | "sha256:72772181d9bad1fa349792a1e7384dde56742c14af2b9986013eb94a240f005b", 230 | "sha256:8396be6e5ff844282d4d49b81631772f80dabae5658d432202faf101f5283b7c", 231 | "sha256:893c11064b347b24ecdd277a094413e1954f8a4e8cdaf7ffbe7ca3db87c103f0", 232 | "sha256:92a07dfd4d7c325dd177548c4134052d4842222833576c8391aab6f74038fc3f", 233 | "sha256:965c4c93e33e6984d8031f74e51227bd755376a9df6993774fd5b6fb3288b1f4", 234 | "sha256:9ab75e0b2820880ae24b7136c4d230383e07db014456a476d096591172569c38", 235 | "sha256:b0845e3bdd4aa18dc2f9b6fb78fbd3d9d371ad167fd6d1b7ad01c0a6cdad4fc6", 236 | "sha256:dca2d7203f0dfce8ea4b3efd668f8ea65cd2b35112638e488a4c12594015f67b", 237 | "sha256:ed686e5926929887e2c7ae0a700e32c6129abb798b4ad2b846e933de21508151", 238 | "sha256:ef6df7e14698e79c59c7ee7cf94cd62e5b869db369ed4b1b8f7b729ea825712a", 239 | "sha256:f898e5cc0a662a9e12bde6f931263a1bbd350cfb18e1d5336a12927851825bb6" 240 | ], 241 | "index": "pypi", 242 | "version": "==2.8.4" 243 | }, 244 | "pydantic": { 245 | "hashes": [ 246 | "sha256:14e598055b65d2e6cedf10dc3de6ad1bb04ca3eec348e4af1cf5e5e496deab55", 247 | "sha256:1d42c7408cde8a224c2bb969bfb9dca21f3b1eec37a92044be8bcd7d35ea5826", 248 | "sha256:433dda6200104d7aa38c27a6ea52485e69931042556065402281cc73a57fd680", 249 | "sha256:51dec047b44f0de4dbfa301b73df605918088348b951b8b4616127249febfe30", 250 | "sha256:548c284237b0c61e0e785ad03167c75723f22000f82e8104d8981fdf50ce14e8", 251 | "sha256:60b8956b57045224294691b78a6a4be0f321271a9f1c2a7fef25248e4c4f20df", 252 | "sha256:6eea211e8b427841a16f43fa739ac06059db6af0d167476b928dbb237d870b77", 253 | "sha256:76b241172d6e22403e116e1d3b7305b6a9479323f8168f2fcb300ffe698443b9", 254 | "sha256:90310c1c5945b4fe2ff7bd69e306e54d192e55d22480657ddd6d2519cf2f12ba", 255 | "sha256:93f7f510fc366b99dace4a3d1f036aafcfe908092c5f2572ad4a96be24da199c", 256 | "sha256:ae48129396bd5acfaef1cdaaa959ac8ab5d02c026b1fdffb421dc6fa81d7861d", 257 | "sha256:be4e0263ef515ae14f06e9fb372843f00bdb218ec4f2f04beb3480ac1538a9a9", 258 | "sha256:bf9e5dd5e0e7e64541508f657c63bf6ab869109cb39f017f935acfeb64ea9be8", 259 | "sha256:cd777c102ba31bc9992093c2e9f778c21b3965566d1fa5ac9f9b7cea2e67fe2a", 260 | "sha256:d09adff1c70351a8750941dd39fda25447eab2e3cdb5b2aade340f69f6f53e84", 261 | "sha256:e77e5f640f1093bf417b841d9b4148bd4212bb0dbb2cbb9024aa07f2b3b260eb", 262 | "sha256:f6a1a465dd72aff0462486588a2bf905f9169e575deec1e6f6d00240fe1b4e00" 263 | ], 264 | "index": "pypi", 265 | "version": "==1.6.2" 266 | }, 267 | "python-dateutil": { 268 | "hashes": [ 269 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", 270 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" 271 | ], 272 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 273 | "version": "==2.8.2" 274 | }, 275 | "python-dotenv": { 276 | "hashes": [ 277 | "sha256:81822227f771e0cab235a2939f0f265954ac4763cafd806d845801c863bf372f", 278 | "sha256:92b3123fb2d58a284f76cc92bfe4ee6c502c32ded73e8b051c4f6afc8b6751ed" 279 | ], 280 | "index": "pypi", 281 | "version": "==0.12.0" 282 | }, 283 | "python-editor": { 284 | "hashes": [ 285 | "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", 286 | "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", 287 | "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8", 288 | "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77", 289 | "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522" 290 | ], 291 | "version": "==1.0.4" 292 | }, 293 | "six": { 294 | "hashes": [ 295 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 296 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 297 | ], 298 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 299 | "version": "==1.16.0" 300 | }, 301 | "sqlalchemy": { 302 | "hashes": [ 303 | "sha256:08e39d65b38d4c3f77c4c9bf090b0ba4ec5721a6e0a74b63d2a9781cdcacf142", 304 | "sha256:2019b332cf4f9a513133fdf056dc4cecec7fbae7016ebc574d0f310103eed7ee", 305 | "sha256:261fcb3ff8c59e17ec44f9e61713a44ceaa97ae816da978d5cd1dc2c36f32478", 306 | "sha256:29d10796e5604ab7bc067eda7231a2d2411a51eda43082673641245a49d1c4bb", 307 | "sha256:387365c157e96eceacdd6c5468815ad05a523ba778680de4c8139a029e1fe044", 308 | "sha256:38df997ffa9007e953ad574f2263f61b9b683fd63ae397480ea4960be9bda0fd", 309 | "sha256:3b64f5d1c1d0e5f2ed4aa66f2b65ff6bdcdf4c5cc83b71c4bbf69695b09e9e19", 310 | "sha256:41a02030f8934b0de843341e7014192a0c16ee2726a06da154c81153fbe56b33", 311 | "sha256:4490b10f83cd56ca2cdcd94b140d89911ac331e42a727b79157963b1b04fdd0c", 312 | "sha256:4999b03daa6c9afb9a0bf9e3b8769128ef1880557dacfca86fa7562920c49f6b", 313 | "sha256:525e962af8f25fc24ce019e6f237d49f8720d757a8a56c9b4caa2d91e2c66111", 314 | "sha256:555d56b71f61b4c9fa55fe203fe6e1e561c9385fa97c5849783ae050a89113af", 315 | "sha256:5639800f1cfe751569af2242041b30a08a6c0b9e5d95ed674ec8082d381eff13", 316 | "sha256:5d91dce14ac3347bce301062ca825e7fb7e15c133f3909f15989e94878b1082f", 317 | "sha256:61965abc63c8b54038574698888e91a126753a4bdc0ec001397acb14501834e0", 318 | "sha256:6dd6fa51cf08d9433d28802228d2204e175324f1a284c4492e4af2dd36a2d485", 319 | "sha256:7fdb7b775fb0739d3e71461509f978beb788935bc0aa9e47df14837cb33e5226", 320 | "sha256:83ee7f6fa5faed23996c67044376d46815f65183ad6d744d94d68b18cdef060b", 321 | "sha256:853de08e881dae0305647dd61b4429758f11d1bf02a9faf02793cad44bb2e0d5", 322 | "sha256:b5541355b8d4970753d4f7292f73a320704b20406e06cd29b469d156f0a484d8", 323 | "sha256:b72744fed32ecf2bf786d2e2f6756c04126c323ba939f47177b9722775626889", 324 | "sha256:bb2d8530b7cc94b7fd9341843c3e49b6db48ea22313a8db9df21c41615b5e7b1", 325 | "sha256:bf2c1d64c4ee0f30e08e1844ff0acf3c1b6c4277c0e89ec3e8bf1722d245b108", 326 | "sha256:c3497cd63c5f90112b8882ea4dd694052166f779ce9055cd5c4305e0b76d72d9", 327 | "sha256:c85ead1d17acc5e8b282c578394dba253728bcbcbeb66e4ef0e25f4bab53935a", 328 | "sha256:c90b21360cf14d33c8a004f991aa336c7906a8db825d4ec38722c5ff1c47dada", 329 | "sha256:ca500f30619daf863ab1c66d57d53a0987361a8f3266454290198aabd18f2599", 330 | "sha256:ce4f2b34378561bc2e42635888fe86efe13d104ba1d95b5ca67b4d60d8e53e67", 331 | "sha256:cf3a3c2f32d53a4166b2eb8de35f93bcb640e51c32033024af500017d8e8a8c9", 332 | "sha256:daddcd6ba1706cc5fcc9cfaa913aa4bf331172dc7efd385fe3ee1feae3b513bc", 333 | "sha256:dd041324328cece3ccdf70cfbd71b5ab968e564a22318ffd88b054f5eadeb9be", 334 | "sha256:dfa093bd8ecfceafff62078910178567323005e44fbe4d7933e6cbce4512cea2", 335 | "sha256:e659f256b7d402338563913bdeba53bf1eadd4c09e6f6dc93cc47938f7962a8f", 336 | "sha256:f25c02991e22ddce134ef1093ef5a9d5de448fc87b91432e4f879826e93cd1c7", 337 | "sha256:f667a947378bcb12a371ab38bed1b708f3a682d1ba30176422652082919285a2" 338 | ], 339 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 340 | "version": "==1.4.28" 341 | }, 342 | "starlette": { 343 | "hashes": [ 344 | "sha256:c2ac9a42e0e0328ad20fe444115ac5e3760c1ee2ac1ff8cdb5ec915c4a453411" 345 | ], 346 | "markers": "python_version >= '3.6'", 347 | "version": "==0.12.9" 348 | }, 349 | "typing-extensions": { 350 | "hashes": [ 351 | "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", 352 | "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" 353 | ], 354 | "markers": "python_version < '3.8'", 355 | "version": "==4.0.1" 356 | }, 357 | "uvicorn": { 358 | "hashes": [ 359 | "sha256:1d46a22cc55a52f5567e0c66f000ae56f26263e44cef59b7c885bf10f487ce6e", 360 | "sha256:b50f7f4c0c499c9b8d0280924cfbd24b90ba02456e3dc80934b9a786a291f09f" 361 | ], 362 | "index": "pypi", 363 | "version": "==0.11.7" 364 | }, 365 | "uvloop": { 366 | "hashes": [ 367 | "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450", 368 | "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897", 369 | "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861", 370 | "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c", 371 | "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805", 372 | "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d", 373 | "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464", 374 | "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f", 375 | "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9", 376 | "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab", 377 | "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f", 378 | "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638", 379 | "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64", 380 | "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee", 381 | "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382", 382 | "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228" 383 | ], 384 | "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'", 385 | "version": "==0.16.0" 386 | }, 387 | "websockets": { 388 | "hashes": [ 389 | "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5", 390 | "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5", 391 | "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308", 392 | "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb", 393 | "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a", 394 | "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c", 395 | "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170", 396 | "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422", 397 | "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8", 398 | "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485", 399 | "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f", 400 | "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8", 401 | "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc", 402 | "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779", 403 | "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989", 404 | "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1", 405 | "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092", 406 | "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824", 407 | "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d", 408 | "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55", 409 | "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36", 410 | "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b" 411 | ], 412 | "markers": "python_full_version >= '3.6.1'", 413 | "version": "==8.1" 414 | }, 415 | "zipp": { 416 | "hashes": [ 417 | "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", 418 | "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" 419 | ], 420 | "markers": "python_version >= '3.6'", 421 | "version": "==3.6.0" 422 | } 423 | }, 424 | "develop": { 425 | "appdirs": { 426 | "hashes": [ 427 | "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", 428 | "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" 429 | ], 430 | "version": "==1.4.4" 431 | }, 432 | "attrs": { 433 | "hashes": [ 434 | "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", 435 | "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" 436 | ], 437 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 438 | "version": "==21.2.0" 439 | }, 440 | "backcall": { 441 | "hashes": [ 442 | "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", 443 | "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" 444 | ], 445 | "version": "==0.2.0" 446 | }, 447 | "black": { 448 | "hashes": [ 449 | "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", 450 | "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" 451 | ], 452 | "index": "pypi", 453 | "version": "==19.10b0" 454 | }, 455 | "click": { 456 | "hashes": [ 457 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 458 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 459 | ], 460 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 461 | "version": "==7.1.2" 462 | }, 463 | "decorator": { 464 | "hashes": [ 465 | "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374", 466 | "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7" 467 | ], 468 | "markers": "python_version >= '3.5'", 469 | "version": "==5.1.0" 470 | }, 471 | "entrypoints": { 472 | "hashes": [ 473 | "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", 474 | "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" 475 | ], 476 | "markers": "python_version >= '2.7'", 477 | "version": "==0.3" 478 | }, 479 | "flake8": { 480 | "hashes": [ 481 | "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb", 482 | "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca" 483 | ], 484 | "index": "pypi", 485 | "version": "==3.7.9" 486 | }, 487 | "importlib-metadata": { 488 | "hashes": [ 489 | "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", 490 | "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" 491 | ], 492 | "markers": "python_version < '3.8'", 493 | "version": "==4.8.2" 494 | }, 495 | "ipython": { 496 | "hashes": [ 497 | "sha256:ca478e52ae1f88da0102360e57e528b92f3ae4316aabac80a2cd7f7ab2efb48a", 498 | "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333" 499 | ], 500 | "index": "pypi", 501 | "version": "==7.13.0" 502 | }, 503 | "jedi": { 504 | "hashes": [ 505 | "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d", 506 | "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab" 507 | ], 508 | "markers": "python_version >= '3.6'", 509 | "version": "==0.18.1" 510 | }, 511 | "mccabe": { 512 | "hashes": [ 513 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", 514 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" 515 | ], 516 | "version": "==0.6.1" 517 | }, 518 | "parso": { 519 | "hashes": [ 520 | "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", 521 | "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" 522 | ], 523 | "markers": "python_version >= '3.6'", 524 | "version": "==0.8.3" 525 | }, 526 | "pathspec": { 527 | "hashes": [ 528 | "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", 529 | "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" 530 | ], 531 | "version": "==0.9.0" 532 | }, 533 | "pexpect": { 534 | "hashes": [ 535 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 536 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 537 | ], 538 | "markers": "sys_platform != 'win32'", 539 | "version": "==4.8.0" 540 | }, 541 | "pickleshare": { 542 | "hashes": [ 543 | "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", 544 | "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" 545 | ], 546 | "version": "==0.7.5" 547 | }, 548 | "prompt-toolkit": { 549 | "hashes": [ 550 | "sha256:1bb05628c7d87b645974a1bad3f17612be0c29fa39af9f7688030163f680bad6", 551 | "sha256:e56f2ff799bacecd3e88165b1e2f5ebf9bcd59e80e06d395fa0cc4b8bd7bb506" 552 | ], 553 | "markers": "python_full_version >= '3.6.2'", 554 | "version": "==3.0.24" 555 | }, 556 | "ptyprocess": { 557 | "hashes": [ 558 | "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", 559 | "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" 560 | ], 561 | "version": "==0.7.0" 562 | }, 563 | "pycodestyle": { 564 | "hashes": [ 565 | "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", 566 | "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" 567 | ], 568 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 569 | "version": "==2.5.0" 570 | }, 571 | "pyflakes": { 572 | "hashes": [ 573 | "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", 574 | "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2" 575 | ], 576 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 577 | "version": "==2.1.1" 578 | }, 579 | "pygments": { 580 | "hashes": [ 581 | "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", 582 | "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" 583 | ], 584 | "markers": "python_version >= '3.5'", 585 | "version": "==2.10.0" 586 | }, 587 | "regex": { 588 | "hashes": [ 589 | "sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05", 590 | "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f", 591 | "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc", 592 | "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4", 593 | "sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737", 594 | "sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a", 595 | "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4", 596 | "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8", 597 | "sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d", 598 | "sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03", 599 | "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f", 600 | "sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264", 601 | "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a", 602 | "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef", 603 | "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f", 604 | "sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da", 605 | "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc", 606 | "sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063", 607 | "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50", 608 | "sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a", 609 | "sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49", 610 | "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d", 611 | "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d", 612 | "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733", 613 | "sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00", 614 | "sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b", 615 | "sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a", 616 | "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36", 617 | "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345", 618 | "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0", 619 | "sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732", 620 | "sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286", 621 | "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12", 622 | "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646", 623 | "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667", 624 | "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244", 625 | "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29", 626 | "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec", 627 | "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf", 628 | "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4", 629 | "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449", 630 | "sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0", 631 | "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a", 632 | "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d", 633 | "sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129", 634 | "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb", 635 | "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e", 636 | "sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b", 637 | "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83", 638 | "sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf", 639 | "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e", 640 | "sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b", 641 | "sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942", 642 | "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a", 643 | "sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e", 644 | "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94", 645 | "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc", 646 | "sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a", 647 | "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e", 648 | "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965", 649 | "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0", 650 | "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36", 651 | "sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296", 652 | "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec", 653 | "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23", 654 | "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7", 655 | "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe", 656 | "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6", 657 | "sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8", 658 | "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b", 659 | "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb", 660 | "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b", 661 | "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30", 662 | "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e" 663 | ], 664 | "version": "==2021.11.10" 665 | }, 666 | "setuptools": { 667 | "hashes": [ 668 | "sha256:6d10741ff20b89cd8c6a536ee9dc90d3002dec0226c78fb98605bfb9ef8a7adf", 669 | "sha256:d144f85102f999444d06f9c0e8c737fd0194f10f2f7e5fdb77573f6e2fa4fad0" 670 | ], 671 | "markers": "python_version >= '3.6'", 672 | "version": "==59.5.0" 673 | }, 674 | "toml": { 675 | "hashes": [ 676 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 677 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 678 | ], 679 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 680 | "version": "==0.10.2" 681 | }, 682 | "traitlets": { 683 | "hashes": [ 684 | "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7", 685 | "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033" 686 | ], 687 | "markers": "python_version >= '3.7'", 688 | "version": "==5.1.1" 689 | }, 690 | "typed-ast": { 691 | "hashes": [ 692 | "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb", 693 | "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695", 694 | "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32", 695 | "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5", 696 | "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471", 697 | "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d", 698 | "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4", 699 | "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212", 700 | "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f", 701 | "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30", 702 | "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb", 703 | "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d", 704 | "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08", 705 | "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a", 706 | "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631", 707 | "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775", 708 | "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af", 709 | "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb", 710 | "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e" 711 | ], 712 | "markers": "python_version >= '3.6'", 713 | "version": "==1.5.1" 714 | }, 715 | "typing-extensions": { 716 | "hashes": [ 717 | "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", 718 | "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" 719 | ], 720 | "markers": "python_version < '3.8'", 721 | "version": "==4.0.1" 722 | }, 723 | "wcwidth": { 724 | "hashes": [ 725 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", 726 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" 727 | ], 728 | "version": "==0.2.5" 729 | }, 730 | "zipp": { 731 | "hashes": [ 732 | "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", 733 | "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" 734 | ], 735 | "markers": "python_version >= '3.6'", 736 | "version": "==3.6.0" 737 | } 738 | } 739 | } 740 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastapi_sqlalchemy_alembic 2 | 3 | This repo is used as a part of a tutorial to show how to use Fastapi and pydantic with Sqlalchemy, postgresql, Alembic(for migrations). 4 | 5 | The full article is published on medium [here](https://medium.com/@ahmed.nafies/fastapi-with-sqlalchemy-postgresql-and-alembic-and-of-course-docker-f2b7411ee396) 6 | 7 | ## How to build 8 | 9 | docker-compose build 10 | 11 | ## How to run 12 | 13 | docker-compose up 14 | 15 | and go to: 16 | 17 | http://localhost:8000 18 | 19 | ## Documentation 20 | 21 | swagger - http://localhost:8000/docs 22 | redoc - http://localhost:8000/redoc 23 | 24 | ## Pgadmin4 25 | 26 | http://localhost:5050 -------------------------------------------------------------------------------- /alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # timezone to use when rendering the date 11 | # within the migration file as well as the filename. 12 | # string value is passed to dateutil.tz.gettz() 13 | # leave blank for localtime 14 | # timezone = 15 | 16 | # max length of characters to apply to the 17 | # "slug" field 18 | # truncate_slug_length = 40 19 | 20 | # set to 'true' to run the environment during 21 | # the 'revision' command, regardless of autogenerate 22 | # revision_environment = false 23 | 24 | # set to 'true' to allow .pyc and .pyo files without 25 | # a source .py file to be detected as revisions in the 26 | # versions/ directory 27 | # sourceless = false 28 | 29 | # version location specification; this defaults 30 | # to alembic/versions. When using multiple version 31 | # directories, initial revisions must be specified with --version-path 32 | # version_locations = %(here)s/bar %(here)s/bat alembic/versions 33 | 34 | # the output encoding used when revision files 35 | # are written from script.py.mako 36 | # output_encoding = utf-8 37 | 38 | sqlalchemy.url = 39 | 40 | 41 | [post_write_hooks] 42 | # post_write_hooks defines scripts or Python functions that are run 43 | # on newly generated revision scripts. See the documentation for further 44 | # detail and examples 45 | 46 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 47 | # hooks=black 48 | # black.type=console_scripts 49 | # black.entrypoint=black 50 | # black.options=-l 79 51 | 52 | # Logging configuration 53 | [loggers] 54 | keys = root,sqlalchemy,alembic 55 | 56 | [handlers] 57 | keys = console 58 | 59 | [formatters] 60 | keys = generic 61 | 62 | [logger_root] 63 | level = WARN 64 | handlers = console 65 | qualname = 66 | 67 | [logger_sqlalchemy] 68 | level = WARN 69 | handlers = 70 | qualname = sqlalchemy.engine 71 | 72 | [logger_alembic] 73 | level = INFO 74 | handlers = 75 | qualname = alembic 76 | 77 | [handler_console] 78 | class = StreamHandler 79 | args = (sys.stderr,) 80 | level = NOTSET 81 | formatter = generic 82 | 83 | [formatter_generic] 84 | format = %(levelname)-5.5s [%(name)s] %(message)s 85 | datefmt = %H:%M:%S 86 | -------------------------------------------------------------------------------- /alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /alembic/env.py: -------------------------------------------------------------------------------- 1 | from logging.config import fileConfig 2 | 3 | from sqlalchemy import engine_from_config 4 | from sqlalchemy import pool 5 | 6 | from alembic import context 7 | import os, sys 8 | from dotenv import load_dotenv 9 | 10 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 11 | load_dotenv(os.path.join(BASE_DIR, ".env")) 12 | sys.path.append(BASE_DIR) 13 | 14 | # this is the Alembic Config object, which provides 15 | # access to the values within the .ini file in use. 16 | config = context.config 17 | 18 | # this will overwrite the ini-file sqlalchemy.url path 19 | # with the path given in the config of the main code 20 | config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"]) 21 | # Interpret the config file for Python logging. 22 | # This line sets up loggers basically. 23 | fileConfig(config.config_file_name) 24 | 25 | # add your model's MetaData object here 26 | # for 'autogenerate' support 27 | # from myapp import mymodel 28 | # target_metadata = mymodel.Base.metadata 29 | import models 30 | 31 | target_metadata = models.Base.metadata 32 | # other values from the config, defined by the needs of env.py, 33 | # can be acquired: 34 | # my_important_option = config.get_main_option("my_important_option") 35 | # ... etc. 36 | 37 | 38 | def run_migrations_offline(): 39 | """Run migrations in 'offline' mode. 40 | 41 | This configures the context with just a URL 42 | and not an Engine, though an Engine is acceptable 43 | here as well. By skipping the Engine creation 44 | we don't even need a DBAPI to be available. 45 | 46 | Calls to context.execute() here emit the given string to the 47 | script output. 48 | 49 | """ 50 | url = config.get_main_option("sqlalchemy.url") 51 | context.configure( 52 | url=url, 53 | target_metadata=target_metadata, 54 | literal_binds=True, 55 | dialect_opts={"paramstyle": "named"}, 56 | ) 57 | 58 | with context.begin_transaction(): 59 | context.run_migrations() 60 | 61 | 62 | def run_migrations_online(): 63 | """Run migrations in 'online' mode. 64 | 65 | In this scenario we need to create an Engine 66 | and associate a connection with the context. 67 | 68 | """ 69 | connectable = engine_from_config( 70 | config.get_section(config.config_ini_section), 71 | prefix="sqlalchemy.", 72 | poolclass=pool.NullPool, 73 | ) 74 | 75 | with connectable.connect() as connection: 76 | context.configure(connection=connection, target_metadata=target_metadata) 77 | 78 | with context.begin_transaction(): 79 | context.run_migrations() 80 | 81 | 82 | if context.is_offline_mode(): 83 | run_migrations_offline() 84 | else: 85 | run_migrations_online() 86 | -------------------------------------------------------------------------------- /alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /alembic/versions/7972a23eaea8_first_migration.py: -------------------------------------------------------------------------------- 1 | """First migration 2 | 3 | Revision ID: 7972a23eaea8 4 | Revises: 5 | Create Date: 2020-02-29 19:23:03.285963 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '7972a23eaea8' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('users', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('first_name', sa.String(), nullable=True), 24 | sa.Column('last_name', sa.String(), nullable=True), 25 | sa.Column('age', sa.Integer(), nullable=True), 26 | sa.PrimaryKeyConstraint('id') 27 | ) 28 | op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False) 29 | # ### end Alembic commands ### 30 | 31 | 32 | def downgrade(): 33 | # ### commands auto generated by Alembic - please adjust! ### 34 | op.drop_index(op.f('ix_users_id'), table_name='users') 35 | op.drop_table('users') 36 | # ### end Alembic commands ### 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres:11 6 | ports: 7 | - "5432:5432" 8 | environment: 9 | - POSTGRES_USER=postgres 10 | - POSTGRES_PASSWORD=postgres 11 | - POSTGRES_DB=test_db 12 | web: 13 | build: . 14 | command: bash -c "alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port 8000 --reload" 15 | volumes: 16 | - .:/code 17 | ports: 18 | - "8000:8000" 19 | depends_on: 20 | - db 21 | 22 | pgadmin: 23 | container_name: pgadmin 24 | image: dpage/pgadmin4 25 | environment: 26 | - PGADMIN_DEFAULT_EMAIL=pgadmin4@pgadmin.org 27 | - PGADMIN_DEFAULT_PASSWORD=admin 28 | ports: 29 | - "5050:80" 30 | depends_on: 31 | - db 32 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | import os 4 | from fastapi_sqlalchemy import DBSessionMiddleware 5 | from fastapi_sqlalchemy import db 6 | from models import User as ModelUser 7 | from schema import User as SchemaUser 8 | from dotenv import load_dotenv 9 | 10 | 11 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 12 | load_dotenv(os.path.join(BASE_DIR, ".env")) 13 | 14 | app = FastAPI() 15 | 16 | app.add_middleware(DBSessionMiddleware, db_url=os.environ["DATABASE_URL"]) 17 | 18 | 19 | @app.post("/user/", response_model=SchemaUser) 20 | def create_user(user: SchemaUser): 21 | db_user = ModelUser( 22 | first_name=user.first_name, last_name=user.last_name, age=user.age 23 | ) 24 | db.session.add(db_user) 25 | db.session.commit() 26 | return db_user 27 | 28 | 29 | if __name__ == "__main__": 30 | uvicorn.run(app, host="0.0.0.0", port=8000) 31 | -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.declarative import declarative_base 2 | from sqlalchemy import Column, Integer, String 3 | 4 | 5 | Base = declarative_base() 6 | 7 | 8 | class User(Base): 9 | __tablename__ = "users" 10 | 11 | id = Column(Integer, primary_key=True, index=True) 12 | first_name = Column(String) 13 | last_name = Column(String) 14 | age = Column(Integer) 15 | -------------------------------------------------------------------------------- /schema.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class User(BaseModel): 5 | first_name: str 6 | last_name: str 7 | age: int 8 | 9 | class Config: 10 | orm_mode = True 11 | 12 | --------------------------------------------------------------------------------