From abee8e7e60e5deaf0218578b104384bd258b0ef8 Mon Sep 17 00:00:00 2001 From: "amy.yang" <amy.yang@topibd.com> Date: Fri, 9 Apr 2021 17:07:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8E=E7=AB=AF=E7=AE=80=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3v0.1(=E8=B7=9F=E5=89=8D=E7=AB=AF=E6=97=A0?= =?UTF-8?q?=E5=85=B3=E8=81=94=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-demo/alembic.ini | 85 ++++++++++++++++++ backend-demo/alembic/README | 1 + .../alembic/__pycache__/env.cpython-37.pyc | Bin 0 -> 1738 bytes backend-demo/alembic/env.py | 83 +++++++++++++++++ backend-demo/alembic/script.py.mako | 24 +++++ .../ac95fea8c6b2_message.cpython-37.pyc | Bin 0 -> 1497 bytes .../alembic/versions/ac95fea8c6b2_message.py | 53 +++++++++++ backend-demo/api/__init__.py | 0 .../api/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 146 bytes .../api/__pycache__/crud.cpython-37.pyc | Bin 0 -> 1585 bytes .../api/__pycache__/database.cpython-37.pyc | Bin 0 -> 443 bytes .../api/__pycache__/main.cpython-37.pyc | Bin 0 -> 1754 bytes .../api/__pycache__/models.cpython-37.pyc | Bin 0 -> 1032 bytes .../api/__pycache__/schemas.cpython-37.pyc | Bin 0 -> 1575 bytes backend-demo/api/crud.py | 29 ++++++ backend-demo/api/database.py | 10 +++ backend-demo/api/main.py | 41 +++++++++ backend-demo/api/models.py | 21 +++++ backend-demo/api/schemas.py | 30 +++++++ 19 files changed, 377 insertions(+) create mode 100644 backend-demo/alembic.ini create mode 100644 backend-demo/alembic/README create mode 100644 backend-demo/alembic/__pycache__/env.cpython-37.pyc create mode 100644 backend-demo/alembic/env.py create mode 100644 backend-demo/alembic/script.py.mako create mode 100644 backend-demo/alembic/versions/__pycache__/ac95fea8c6b2_message.cpython-37.pyc create mode 100644 backend-demo/alembic/versions/ac95fea8c6b2_message.py create mode 100644 backend-demo/api/__init__.py create mode 100644 backend-demo/api/__pycache__/__init__.cpython-37.pyc create mode 100644 backend-demo/api/__pycache__/crud.cpython-37.pyc create mode 100644 backend-demo/api/__pycache__/database.cpython-37.pyc create mode 100644 backend-demo/api/__pycache__/main.cpython-37.pyc create mode 100644 backend-demo/api/__pycache__/models.cpython-37.pyc create mode 100644 backend-demo/api/__pycache__/schemas.cpython-37.pyc create mode 100644 backend-demo/api/crud.py create mode 100644 backend-demo/api/database.py create mode 100644 backend-demo/api/main.py create mode 100644 backend-demo/api/models.py create mode 100644 backend-demo/api/schemas.py diff --git a/backend-demo/alembic.ini b/backend-demo/alembic.ini new file mode 100644 index 0000000..4e90f53 --- /dev/null +++ b/backend-demo/alembic.ini @@ -0,0 +1,85 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = postgresql://postgres:1@localhost:5432/antdemo + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks=black +# black.type=console_scripts +# black.entrypoint=black +# black.options=-l 79 + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/backend-demo/alembic/README b/backend-demo/alembic/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/backend-demo/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/backend-demo/alembic/__pycache__/env.cpython-37.pyc b/backend-demo/alembic/__pycache__/env.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfa7eb196dae652248271bdda08a1fffbd8ce49f GIT binary patch literal 1738 zcmZuyPjBor5Ra2=lFe>+w|#AST)^V;-b!f286os&0qIGodX$Gi5mInt@2(fe3AVR? zp4wBnaH!se53uEi#3zclAr5>6PK=%1w){!t@pxuDGnx6>IoR4tJ$U~3Nq+lV;(5Q@ z#pa2Cc?LuO3WRzT39m#MLYDW1Uj|v=_yG7Y3mqSdP8ns9<2xeGVz7-wQg*X$nPw^S zSiI=1`YeUF%eJnOeQ#Tzu^5!YYzQ{dVw8;-Vxz_OHR#xIv6DTb3GM#iWxF(`J(%}c zwA#P*)X!}9+C!d<*q)tf=L>J#{}VFy#;8fBT(HARPWcR0J50{FWcgH8WnOHgVO>=M zv@u8wJ2yvTzlq6-u8Em9G382<l7T)vAet4{v3(GXE{sDM`WX=8tq_Gzx$=y^2rfMn zQlADi<cM}|pg6`~b#A@a1II<T;NUAL&F9{+_chFrbWA=4r^ic)OFmP?@JedTC4N#( zrvlP`g3F4sNt$AKUe3A3?I$c1)7Z?JUE2Kd88>shSZad_{_^-UXHO)>vI2?3pSU8t z3tOt?Y<@4n;E@yss|`63%<Y;p#W2zMj0rKp_}~KT?|5BvIdcJ9Pq<LbW$U(_F-$A@ z#9(&HB$kX($l~LJk6t{-rot!S?v!w0BdovVkO%?!SDW-F?3@)#!=8?@3(rb!T(lXt z9<@;}d}U=WqAnD#4X&1^UYfPjR|EaMAflMF@?x@7;$@T8M3GXP3&EO>?I<0GO#rH9 zXo#9Ilb6g8N(^bX1UF0(k)Lo$b<?Mu2v(T9s*OGx$4%7My&1Y)giEV|ZmABypy}Rq zMfL4^`-B1La-)dUq_B3)KrLl{-{dh;J+S=6Q@b$zHGpX42`|23@^n&PH2eRw&ew2w z2W<5Sh}Tb1h<x|<gA}QKklo?bhlM@j4yPF~#xrQ;8?*>+0k0-pbf|w5TzQw?3Q+m_ zy(?tmMRJKumj*XJpfz5lYuv`G-Ws=Ii(5eOnxi2gxby1A|AVjm4|<<V=pMjL7fcex zD*#vv6$=B4CV<HXsCV!sT2}>kI*SzvErDXTXnz3z4FY-(5CA7Ssui2^^QLQ0dm+FX z2-AB%u31Opz6zj5Y6zt1+5W<jcRkx_+nRI9H!>AktK?`Y#0zlhE)biQ!-3kiek=mi zjwO$PK*ZiUqCEiWO{=gyZ^<5T&ECJe?W*@asI>Lt#Xd@*)hRSObX2_!((xPFKvXjT z+HBG$s%+z%^u7q~hq;vFHNslJ2Kqv0aiu5r!c+FrSFzn2x(hHOb<HGgl03I}X`W{( zsrkfSMM5k1Wvq)eTGz)J+4I#Tn*-HW!J^XT+6=kgfH=2)9+bcp!_^`A08~rCKC~CD eehWz7?;{v~f=1}E-w&fOjiMxZoa`qk@&5(|Cg7X^ literal 0 HcmV?d00001 diff --git a/backend-demo/alembic/env.py b/backend-demo/alembic/env.py new file mode 100644 index 0000000..a7ea42b --- /dev/null +++ b/backend-demo/alembic/env.py @@ -0,0 +1,83 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +import sys +from os.path import abspath, dirname +sys.path.append(dirname(dirname(abspath(__file__)))) # 将项目路径引入 + +from api.models import Base + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = Base.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/backend-demo/alembic/script.py.mako b/backend-demo/alembic/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/backend-demo/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/backend-demo/alembic/versions/__pycache__/ac95fea8c6b2_message.cpython-37.pyc b/backend-demo/alembic/versions/__pycache__/ac95fea8c6b2_message.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26c43e205c21c476001f56e5dbe94f43a4480ac6 GIT binary patch literal 1497 zcmZ`(&2QT_6c;I3l4Uz-6JOS0n}O|OU<sTwD>9=Ph9)Rh49JGH*ugNs(t51JRv#`Y zr%kcruDR}PANMcux?T1!?6gPPi4~-iz$fzeKKP^FdwkOABpyD0|53dBDe}C(?Be>N zIQbrjevAUVkp~25Mshl$#LoT99|aJM8sLvY91)Hf8W8^OjhYZajNb(O=U%`0;n!Sf z&8H$sei0W^%d+S_J013T`t3Kb1V2t6O%7KYp@+TXL<wGr-YJS<?{IK<us1l`8yxoz z9u6NK508%akB<%>4F*Z_4>I%m#L#kfHfq<SrB-wOv~Y5QL;pZLukscINJU@!Kr6Zk zmLB*JT=@=ZAksi2yg{NnNQ_9hu~|ewmt+|djQl#r=uK!YaR+Ej3C2mTf|{n~G!!-d zwFcR=|A$TI&fZ&hkZnZl8P<#!32bBZdsDKsr(1E0Y7FipgEnl{8LV0FIL$3?Yt63H zbT&TVVOG0mCYWoX43+Q{lMom4EaQ_*n1;x?%wCx7bFR+?uo>6-U8%q{rDi;><b^OD z`JP#C=4{bDoEP%#T$toqA;AQ)61izqvcjk>5IR+IR$=v+xO`WjvxE<kjk1r%yXa`` zS>4V?b08YnE#2J3>$jAxaMMm*wXw=kr<$Aaq|D}dVWMY6C8l`5@Oh<VF*VVXvdjc8 zO!sFcbFMCb6qhGup)18@QQbt61&H^CyfWRVr4n*l+%o&qQ=j3!PW=1gbU2>Mis9dR zqh~x7V-R^czL<+WH<|GCjVNHX;F-uLG96zCWjjcZ>jlr&9kxHaG|_xERUE{wt@*D| zcr+wC>$goGkOyS5-XbeReSvnj+9p82wasrh!Qv)Z+!P2F0|oyIFM%5@_z2dhV+(Ay zC8>FYsKpE8R+PAop+{srT&XqB)DCh`Z4_84iOUr$crMg^i{G=tcDeGcXrkx`tMn$I z${BMhQJ*4iR)CAJNyKXQxz#rTOUwPfuW_ljP<XUU?3*~LzC@(oG7)1?ri__rotX88 z`fbLu^jzeZs*9E;R_iOzbZlt0Sxyu$(sPDQBQlM|#0+z-Sy{MTxP3lKF@BtvFwewy Ucx8Lq9zGy#5(fcsuOEN%A0+dN<NyEw literal 0 HcmV?d00001 diff --git a/backend-demo/alembic/versions/ac95fea8c6b2_message.py b/backend-demo/alembic/versions/ac95fea8c6b2_message.py new file mode 100644 index 0000000..4661506 --- /dev/null +++ b/backend-demo/alembic/versions/ac95fea8c6b2_message.py @@ -0,0 +1,53 @@ +"""message + +Revision ID: ac95fea8c6b2 +Revises: +Create Date: 2021-04-08 13:38:44.841600 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ac95fea8c6b2' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('email', sa.String(), nullable=True), + sa.Column('hashed_password', sa.String(), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True) + op.create_index(op.f('ix_user_id'), 'user', ['id'], unique=False) + op.create_table('item', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('owner_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['owner_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_item_description'), 'item', ['description'], unique=False) + op.create_index(op.f('ix_item_id'), 'item', ['id'], unique=False) + op.create_index(op.f('ix_item_title'), 'item', ['title'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_item_title'), table_name='item') + op.drop_index(op.f('ix_item_id'), table_name='item') + op.drop_index(op.f('ix_item_description'), table_name='item') + op.drop_table('item') + op.drop_index(op.f('ix_user_id'), table_name='user') + op.drop_index(op.f('ix_user_email'), table_name='user') + op.drop_table('user') + # ### end Alembic commands ### diff --git a/backend-demo/api/__init__.py b/backend-demo/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend-demo/api/__pycache__/__init__.cpython-37.pyc b/backend-demo/api/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab31f1210930dd43be2cf4e56615f7c6509a0be1 GIT binary patch literal 146 zcmZ?b<>g`kf_%H&1Q7igM8E(ekl_Ht#VkM~g&~+hlhJP_LlH<ALHx3Iv5HC0EQv4A zFUl@1NK8(RNlDGkk0~on)de$>5|gu2^HLz3#DdJ2`1s5`p!#^dg34PQHo5sJr8%i~ KAVWU`F#`bnm?N?P literal 0 HcmV?d00001 diff --git a/backend-demo/api/__pycache__/crud.cpython-37.pyc b/backend-demo/api/__pycache__/crud.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bf5364a7c1c3238ec3ccb30d6ee59d946d7f647 GIT binary patch literal 1585 zcmb_cJ8x4l6!z;rnl?>ZQd%D3A*L*y0U?Cw1Vb0Za)lJq*r7MQw+Z&GP^7T2!pg$X zj{GIBO#KT?e8<Uc(@scW$@cN_IriuC9iNxYW`m)<-kH3Aq8R%{i@HS+UZA^g7&Ozo zU?tBuXIf}kh*D;<RGH$;a1&|uL+D7yUsM)jo#+JXRIgy2>TR-s&FT-S*L3qsl&wIc zMh(3VtCnuVYE|znS#9V|Sgi%CCOmJzv!l0Qx2|u#VclEjz{I-TCvS{%`S|#p(^~kr z9BWfJpSZ!HDf<p8p$~j=;*9O(dLYOTjb=QU?V-DS7-sC0ReU7Q_^G6Mq-OkxR?!*5 zg?zso`{?6|u~SQaUcJSMJ|5;pg<0g<N5kB@sw-@aeVbtT$!rtT@8<5i{v>}luqS$V zGWF>PQ}qZC9pnNcZd;HSzCHr-y!a=qHpO}20=q&I(QMl^tYN4@1_eP3IPE$lzfq&> z9ZY)x2tB2SxdHiHW9Z88POsciKJihJmw7di*q}x;^$^{=5SF7m<A|!7U5)KEygnWe zht5>C17|P$MX|Wg-hd)#=a2*VfP1CJ?dYvF-fhTrSQW+mBB~U8>H*_Z2s1uHl5exm zg80Wu&V&|U#b*ihY9`N+`jC(hVU8CXiR_U3S?hRQSp%Tc!@fH-8kbUZv(|jsoAjOg zG`6~%__UUn_#s=oQ)?d&#wB9u6KjUnxWlfRC)5s|)*1GXOz+x}KG6pupRR{wbpS+_ z340VMN8B^s;BE92-BRZN7uLLbRhiOm;k-FJHzEBUXE_`lIo6y#xODZ3cEe}7fJvlL zZ3@IahETB)AA-J9aRvfsBIn=5Hy&t{7qqDbZP5~KVn0jApN>Oi=*Dw4?&CnObUvu; zZHV>`4V1z)4-ZK}Um~Nh2YA<i&{Eigfg|ohS~9*<hyD?C`^XY1Ty_(~6}jct-N&L| zP!*f*j%{hFPWZ)_rssQ^A6KDlc<Cx@>1SF>ci*7Wv=^uk1ltGDW(^`}p{2W*lI8Lf brO!}5PYUy#P&xWnYrHMmvMoDuGwsMfHV{KP literal 0 HcmV?d00001 diff --git a/backend-demo/api/__pycache__/database.cpython-37.pyc b/backend-demo/api/__pycache__/database.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a6f997028acf84787c1f63d22bea80ee15fa18e GIT binary patch literal 443 zcmYjO%T59@6m4gQXMpI+#P|bjhWOeLV;B^}0!<WMI3d9@y~4zH3hiLTEo(o-U+T`d z@)ulr2SViD^yJ)U?n&F#YMG!Ne5t1yCFDB`HkL!u!e_b&oNy|Lq#>mlcZ4I|&|Ps? zcrq8}kb7YsDCCzkEI^K<LxJZ%+^`7ll7uB*=#zT!2e*+rwbe)iOJNAfI8Fc)I~*dx zG)v=G7>=09auox{#43^O1@yZ=RVE#4Ff-9?G&Vu=uq9N)!~~1Y)05+)21`;7QeD+u zTW0fAMM}yzwWW+di@BLtZxko|re3yX+{HvR0lCl)9v1HZCwzEI{jH<4iw(B6)u6Q0 zUN*JYzwHIRi*D!oad;Wr2koHW89v<gY<?}zR{Copz3fu!wNc(D(N&yX!SAj=VAFWO fS;{i${&ZoBXHxOGfOGs9Vk!s~itcz$k=C3)vq*lN literal 0 HcmV?d00001 diff --git a/backend-demo/api/__pycache__/main.cpython-37.pyc b/backend-demo/api/__pycache__/main.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..106858383b2602a8c8e541fb6e8198e26241cf41 GIT binary patch literal 1754 zcmb_dOK)366rP#;^fON4IM23*Mb*1W{s2PIQbeUHRBCx>RLNZ5nS|@!7c<uqG0ui` zYl#KyDgjIW((Dkc`~_B=Gqwpz5i7=;b7#)$p7VV(*AF|LCV}zu@8wrNd4&9doAvNv z@c~TzfD$5zpc%<2r#a({;+|zr?s7NxxR?9fw>l>a@{otHc7>NU@+NQQE#Au8ylr)U z*2%lPn{V(9N@Q!&n`}<D<c0_q6!zW~;oBk<jn{<t<@RJpG-Z1-5UmB1uIyjYGYb1% z8H)BBCOV?~+Pk8B4?Oq9hD6(7pP)BX*IPw6@&JCJ*nH!NEwODQ4sAsLt=#Ch1DOY6 z*ZLjV8uq~N&VOXx7YEk+t~h*7qN8iXFJi`hn(EqwpH_8R7I79iCiqBJvJlz?AIG}> z@Yxg7`Q*imXOF*4q;-m@37$)>!T%Z{ClKN$YATGMmqKO`r<1Q`9&5<nUO7H3lQ=WJ zEY8zHLIQW379znCaA1}YCMxt0L`|;9C7Ctn<a0270W{9ZFZ5Sfe+g?SpPoicwZYSP zNmgo1$;9|KqBcSIXXp53T%|AbI4zE=3*(>5dL+i^uJJX5`jpWoQ`@kf`6p8?m5wOy zDygfo&~juOL2%Hddf=8Y420ppbYVV%sgFU_WJ2e3P9{vy1-oQ(riQg6m~e!<VBb@) zyJ#2Qf<fi}Db(r#JZYBx0FBRf9^-l#XG+FmsN^~DAr-v5rR%t!>QMry8ehm7+@Nc$ zM)g5No@&5@Z(@5`=xBT~vWe9W`rySdtpw86(%K`(#@P%e5M!&fh%LnyM(u$>T$V_& z9(8G(TJ0=YB6V^tz>cizS7~LuEX~t;2@-;X0|A12x&#SpwIH!MnNtACxpd|ZK*5m2 zL$InN5U{rGG}i6t$i1=J{M@rt-748M5joq8K7d3T-%g-%bqAia-m2>FEJUfe1ZacR zdRg_qQhOg_*VL|w735W@-mTdUxpSn{14`9h@K1k4Lc5;<7sH~ghiB!q5YX2EY-$$- zFkpKO*F9R2K#S3~7`2ZpJjFMhn8x1?-UGvmnJx{H8Pv=Mw|hKEYnkihf8)cZdy5a_ zS^e#DmwZ?gqIko{JFq*A?is(nsM6wGA@B-o<iQzyYT(W)<WAwyvB>bQ{w9kv{G41I zmnv5QSPZcsD*Q`OEf72uaUG9ifF19+>Y&bj2zwLeaBa}ao2!cuXPI&0s<M}#yH%-c z?jmEniSm)XF7~_|2Us#rTGaL+S){r91b|i8$UnNabm8qW;d}7um}c^QI0!@|t3BGM ZZPuqf)?+>kgDyStx9HIA(gVLs{{o1mgkJyv literal 0 HcmV?d00001 diff --git a/backend-demo/api/__pycache__/models.cpython-37.pyc b/backend-demo/api/__pycache__/models.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15ea834c2207e27ecb7319e975ceabe9b7bfc411 GIT binary patch literal 1032 zcmah|%Wl*#6t(kCCNnK>B+3WOX1)NSsz{&;R3Q~46jd_r*mSJgNybhn!*<yAL--|c zS@joKac|NV7L{=1<9lrD`uJSuU^*=bwBl*|`6?jf7m}M6L9h?qeF6|fP)!W2s0pgT zgjHywDl%~uQ(OylV$v#wI24i2OkU-bydfeM$qynDnQz0Y0G^5rcsB5f$dAdqxPt6t z9{cp5X|&|EPhK^;H?=QbH&&{%`mNmf^sw&anY2DR?yRcM=G2!~YTl`)b}Q9hQA|R8 zbikclV#b>mL$D9sy#tV>qJmU`pj9X%8H)hE@G`6tVCldjU>UM4t#TL(n2j%kY9dRK zpniy_qjDd8bRa3}0YA(GKWVKp+-}%8D2`Pv<Tsd2`dY1fX{T^LC`^U?!h7BM=&+N< z$IV48EzHkO`SP5#P20n*q&u3=e8yPKjbzLhjG0FC8sn0&b<g$n%9OE=pK3W$8^R$L zuj~UQY=S{74OiOlthifA!CLOzMPr49auc5`$M~{SU!_fl%?d=hpTzC~8{qfO;)J*A z1kRV*E!vI67lWBy36Rl<&fv>vNr#oY&3_MD|7(5()(+N#<rt&=F%%%)((RoEu)C1f zN2nS6x2WgZ=3)4rVr3R!1WLBg0Or)*hXLHR4{+`w!Xt#o2)FjxCrC&CI@M|ECqlZV zRV}_ai@%1?hSD)ekJj0H2)DM4(Q}+bku&K3_*H^ivtU>`nwP$CYt8j?CCz3i%cuhn x8EQG|nEl<fXsj9Ql?e{zhc|C?+&$bA&$~;A&t8m==q3IvE(6%3Wl#pY*&keP>f8VT literal 0 HcmV?d00001 diff --git a/backend-demo/api/__pycache__/schemas.cpython-37.pyc b/backend-demo/api/__pycache__/schemas.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84b8ba8c79e532c669b82b3d737ef55709407927 GIT binary patch literal 1575 zcmbVMO>fjN5VaF0o6YXFL3|_5NRd!~!3tIF0U^P1fL@|XA*@ZYl#j(usmcK%l|RE@ z@(pp~FL2^b!nWP*RtO^5^0Oy1Z)TpoH<`o?-{<emn~BHR4+6_iV6lr~zhII~@{(0N z<CT|roUm8=mB<8VPnq<k_{yYE;>^zi;6R4Jp$dRQ;DL;QqYe*%hcX6^JNpQDB*(yG z6~TT8Jds<#TOE$&_A8bqKf!{fo)gctZC&(o(dwoy%9Oj|USZXXMyhg7Hp|b)Vi&_c z!lYQnCCj`6rhFwNpMrlDs8IR$8L&?nQG|=0wW=bAE@*XIs+k)}W#>kB@zQ~d^1Lo8 zmFF(b^Qw`@C9TJK{^7VN|D5=?HEui4i@I*wf{5BYHv{l6#OfO}6I#>sE7>_L7W&Z6 z->a&yJBw2jV4I3>X^MHoyPcKXI8JuSWQ=K<o8-vAb1`MGZ&cB$S?Zez7G_8jwfZ7( zzuKa`ZA@flApwSPgjd3ym+~=Amf<c+*_G6rUJ}9?iYo)q37sH1&ePIG%}K3HuH}mF z^Hh>cz9rB6t|9)X5&gfj-_-B)(d$_%))InOQ&At(rqo>6|43;rv%7`$EDhKF__}Tl zmD7;HCTE5ijxcP9i5i1i(cVfv=e4?nldHArvvSdaRi>92+OEr48mtjA6sae4E|yC@ zBkwmbx~yVu2>%C<n0WMJanYi%_M|cLpUK=qaH`sp4B^dWrZ~A;6cykOLO@3>3)MhH z%R7meK*#_uK>$GwWe7nHoFK}Ea(6>*^J3oWkGQQGGO;T`|Eer<biK07O@!E}14{KF z#;T&?^#<Oi|4C6!yltA&&@YCrSSOn6W%d9jcQGv8$zEoOXJ~hpj$GKDE_8j=J0h{6 xZ>O@TTRk`QV04c~cZK^fBn(3h={#)8$3@fr9eY9*vvgMyKK2rk_(_Q2{|2ZO4+j7M literal 0 HcmV?d00001 diff --git a/backend-demo/api/crud.py b/backend-demo/api/crud.py new file mode 100644 index 0000000..33cd363 --- /dev/null +++ b/backend-demo/api/crud.py @@ -0,0 +1,29 @@ +from sqlalchemy.orm import Session +from . import models, schemas + +def get_user(db: Session, user_id: int): + return db.query(models.User).filter(models.User.id == user_id).first() + +def get_user_by_email(db: Session, email: str): + return db.query(models.User).filter(models.User.email == email).first() + +def get_users(db: Session, skip: int = 0, limit: int = 100): + return db.query(models.User).offset(skip).limit(limit).all() + +def create_user(db: Session, user: schemas.UserCreate): + fake_hashed_password = user.password + "notreallyhashed" + db_user = models.User(email=user.email, hashed_password=fake_hashed_password) + db.add(db_user) + db.commit() + db.refresh(db_user) + return db_user + +def get_items(db:Session, skip: int = 0, limit: int = 100): + return db.query(models.Item).offset(skip).limit(limit).all() + +def create_user_items(db: Session, item: schemas.ItemCreate, user_id: int): + db_item = models.Item(**item.dict(), owner_id=user_id) + db.add(db_item) + db.commit() + db.refresh(db_item) + return db_item \ No newline at end of file diff --git a/backend-demo/api/database.py b/backend-demo/api/database.py new file mode 100644 index 0000000..fe16e15 --- /dev/null +++ b/backend-demo/api/database.py @@ -0,0 +1,10 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "postgresql://postgres:1@localhost:5432/antdemo" + +engine = create_engine(SQLALCHEMY_DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() \ No newline at end of file diff --git a/backend-demo/api/main.py b/backend-demo/api/main.py new file mode 100644 index 0000000..02bfd13 --- /dev/null +++ b/backend-demo/api/main.py @@ -0,0 +1,41 @@ +from typing import List, Optional +from fastapi import Depends, FastAPI, HTTPException +from sqlalchemy.orm import Session + +from . import crud, models, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.post("/users", response_model=schemas.User) +def create_user(user: schemas.UserCreate, db:Session = Depends(get_db)): + db_user = crud.get_user_by_email(db, email=user.email) + if db_user: + raise HTTPException(status_code=400, detail="Email alread register") + return crud.create_user(db=db, user=user) + +@app.get("/users/", response_model=List[schemas.User]) +def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + users = crud.get_users(db, skip=skip, limit=limit) + return users + +@app.get("/users/{user_id}", response_model=schemas.User) +def read_user(user_id: int, db: Session = Depends(get_db)): + db_user = crud.get_user(db, user_id=user_id) + if db_user is None: + raise HTTPException(status_code=404, detail="User not found") + return db_user + +@app.post("/users/{user_id}/items", response_model=schemas.Item) +def read_items(skip: int = 0, limit: int = 100, db:Session = Depends(get_db)): + items = crud.get_items(db, skip=skip, limit=limit) + return items diff --git a/backend-demo/api/models.py b/backend-demo/api/models.py new file mode 100644 index 0000000..696fda6 --- /dev/null +++ b/backend-demo/api/models.py @@ -0,0 +1,21 @@ +from sqlalchemy import Boolean, Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship + +from .database import Base + +class User(Base): + __tablename__ = "user" + id = Column(Integer, primary_key=True, index=True) + email = Column(String, unique=True, index=True) + hashed_password = Column(String) + is_active = Column(Boolean, default=True) + items = relationship("Item", back_populates="owner") + +class Item(Base): + __tablename__ = "item" + id = Column(Integer, primary_key=True, index=True) + title = Column(String, index=True) + description = Column(String, index=True) + owner_id = Column(Integer, ForeignKey("user.id")) + + owner = relationship("User", back_populates="items") \ No newline at end of file diff --git a/backend-demo/api/schemas.py b/backend-demo/api/schemas.py new file mode 100644 index 0000000..f07db4e --- /dev/null +++ b/backend-demo/api/schemas.py @@ -0,0 +1,30 @@ +from typing import List, Optional +from pydantic import BaseModel + +class ItemBase(BaseModel): + title: str + description: Optional[str] = None + +class ItemCreate(ItemBase): + pass + +class Item(ItemBase): + id: int + owner_id: int + class Config: + orm_mode = True + +class UserBase(BaseModel): + email: str + +class UserCreate(UserBase): + password: str + +class User(UserBase): + id: int + is_active: bool + items: List[Item] = [] + + class Config: + orm_mode = True + -- 2.21.0