From e6dc52ca4d87002df47ee18fa47f9bd3777f5fc3 Mon Sep 17 00:00:00 2001 From: cesar98 Date: Tue, 30 Sep 2025 23:09:47 +0300 Subject: [PATCH] Part 1: Booking API with Swagger and custom endpoints --- booking_system/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 195 bytes .../__pycache__/settings.cpython-311.pyc | Bin 0 -> 3630 bytes .../__pycache__/urls.cpython-311.pyc | Bin 0 -> 2104 bytes .../__pycache__/wsgi.cpython-311.pyc | Bin 0 -> 731 bytes booking_system/asgi.py | 16 ++ booking_system/settings.py | 180 ++++++++++++++++++ booking_system/urls.py | 41 ++++ booking_system/wsgi.py | 16 ++ bookings/__init__.py | 0 bookings/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 189 bytes bookings/__pycache__/admin.cpython-311.pyc | Bin 0 -> 1107 bytes bookings/__pycache__/apps.cpython-311.pyc | Bin 0 -> 564 bytes .../__pycache__/middleware.cpython-311.pyc | Bin 0 -> 2426 bytes bookings/__pycache__/models.cpython-311.pyc | Bin 0 -> 2342 bytes .../__pycache__/serializers.cpython-311.pyc | Bin 0 -> 1669 bytes bookings/__pycache__/urls.cpython-311.pyc | Bin 0 -> 630 bytes bookings/__pycache__/views.cpython-311.pyc | Bin 0 -> 7092 bytes bookings/admin.py | 11 ++ bookings/apps.py | 6 + bookings/middleware.py | 41 ++++ bookings/migrations/0001_initial.py | 37 ++++ bookings/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 2196 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 200 bytes bookings/models.py | 32 ++++ bookings/serializers.py | 15 ++ bookings/tests.py | 3 + bookings/urls.py | 9 + bookings/views.py | 111 +++++++++++ db.sqlite3 | Bin 0 -> 143360 bytes logs/api.log | 33 ++++ manage.py | 22 +++ 33 files changed, 573 insertions(+) create mode 100644 booking_system/__init__.py create mode 100644 booking_system/__pycache__/__init__.cpython-311.pyc create mode 100644 booking_system/__pycache__/settings.cpython-311.pyc create mode 100644 booking_system/__pycache__/urls.cpython-311.pyc create mode 100644 booking_system/__pycache__/wsgi.cpython-311.pyc create mode 100644 booking_system/asgi.py create mode 100644 booking_system/settings.py create mode 100644 booking_system/urls.py create mode 100644 booking_system/wsgi.py create mode 100644 bookings/__init__.py create mode 100644 bookings/__pycache__/__init__.cpython-311.pyc create mode 100644 bookings/__pycache__/admin.cpython-311.pyc create mode 100644 bookings/__pycache__/apps.cpython-311.pyc create mode 100644 bookings/__pycache__/middleware.cpython-311.pyc create mode 100644 bookings/__pycache__/models.cpython-311.pyc create mode 100644 bookings/__pycache__/serializers.cpython-311.pyc create mode 100644 bookings/__pycache__/urls.cpython-311.pyc create mode 100644 bookings/__pycache__/views.cpython-311.pyc create mode 100644 bookings/admin.py create mode 100644 bookings/apps.py create mode 100644 bookings/middleware.py create mode 100644 bookings/migrations/0001_initial.py create mode 100644 bookings/migrations/__init__.py create mode 100644 bookings/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 bookings/migrations/__pycache__/__init__.cpython-311.pyc create mode 100644 bookings/models.py create mode 100644 bookings/serializers.py create mode 100644 bookings/tests.py create mode 100644 bookings/urls.py create mode 100644 bookings/views.py create mode 100644 db.sqlite3 create mode 100644 logs/api.log create mode 100644 manage.py diff --git a/booking_system/__init__.py b/booking_system/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/booking_system/__pycache__/__init__.cpython-311.pyc b/booking_system/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8053daf4ba468525e5c55f281970d2b5267271b3 GIT binary patch literal 195 zcmZ3^%ge<81QXBQ$^g-iK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCUt!KxF`>n& zMa41Bsl|y!F)pda*(Lb}F^&b9=^2TYxrrIb%%uGM?99CM_~OdqlGNN7G;Vx+W?p7V qe7s&k=rfFki(rG z+SZ(iT#^8L@GU;*VC-QR!R8n84^m(tL?Z_QIr%og-u9GgJ|vnp5QmSNuC8}=RrUN3 zi3AaR-p&7e{~vLL{=<>sCoow2^sNJ-zaoqzgdNzaIT}vM=|E0IoW%7#(0+t}|MSK@ zT#Y`z2js`Ijc156foEH4fp*nEr z$X$0x5geAHID(_ZizloQLO6EhR2|X;p2TtBn#5B*INgIYs-y0fVt7`X#22JE*qeg? zG)_n}cutzd^LPO-9yz58pzR{pCM8JX&D_x6(IX93-z%zB^#Mj_|9p9)sLCTF+k6Z&x0F4|=1O4WaM_RyZ6_mQA z+=i3~bI+7!T~AVCnrgF7lY6?6+|~61KxBGIP0~oV4E-6YnL;qQNt(n^OoEfUhsmqB zC%UTOhT2S0Q!&f|=hbAJf_!qI`;Kr+xC_!7pt_+OB&jyRN<%SKy_tlcxvzpy{(x0*7_g|YLk*$+aRmzmu++T+Rf(6uUD*l zrgATJr>z~X+oeov&hAaUdAGLz<=&cXR8s+Ky01p4=}ps6cZFV3 zt*Pui45dL{ z=*9u_V`EP~RA`;~2Q@-dert80p`l`|kr#?VgkCOG^H8Ypq`+e9jAnf?ZgAkDFd|>+ z?~O>MJ~RT=(9oMgw)glStkl>OvH%{d4W8;!i+2Vck-IU>_Ne+Y`3CCPEa>$*$c}JNz2Cn= z+t8?$9+-xPZfVfM!YVQmHyjNE*O&OZ629f9nO}VX=aWx-u37G7* z>(;eT;57OnSl0)8JW_w%i zt$d~JYQ9vgSeM80_JY<`L20$%gnGx%e3gw4S^`T($>X+TF7KW$3&yTx>|=;)HhV3;grK#et#|r1{5+eh(U#4S4ze500YLQF~*i+ zKvMf`+r2fMQ6eX9WOfQwxeVnYmc_E1Eo3ScvBGADl6S_P_0qZaB!)j2eDazdW z;zr4u0u#Kig$8za%*`d44|<2{U}BMzE^?BK`S<%~sgZyU7Jxy}QtB`}m`5y^OJ$Ho zR&;PygH}#?nD04c7zP+iV3jJn8j*Whf>>nk5D;1L%t>lo;<|kUN-?#_e6kEzzbrFf z3ockq-8EdC#V^a;RlX00s%y^)^TKh$bY}kbOhx3)%z_m$TNbPGBk_04lM~l>Hd!Q7 zD3qRvIr(9!QmwFPzF4Wk7Hq%-sIcHxK9?(qPcmhZh0CQd{-YCNu z0W*)7uTa|Th3sh@VAWtQY8t&w7&n`LLq9>v(9e&v_n-19LZ4;{Rg9-OLJ#1@>1n2= z*7udehO$4pe1H5s9Ycq2T0-maXa85wmu-zaFmhmq*FL@MM96kI91hzVbhvHAK>|7E zj!|OtXM0gN_UA8N`Tz3Z+Xw#&E&VgJbP~GqmjAB34Xt(jb`(X+j!qC51CfsBG#2kf z>|iABw9ycBqV}ag6gGwcxMxvpxf8biXj*i1WAW~E;xwGJk>^Tu1h{UE$?5gc?#ek6mm#4=#j{+0NG0Ap0LD=6zwnvfQ zj3VVeG80*JLj3mUXfn}>oQ5Ymfz!}L$A1dJdF?QYUI6EVXcjz(+kWSg*Y-Lud+mUa z2MhpWO`y=!tH&q7g^sU_e1D4kG4jgnL{8A+TeNtL7EdQ)-Q@DAKi&;bAJ68&>`c&h zxu?7k(ClJ&=2|zg@Y?ly^No74m_A9|e4Du0ox5TOJd;644FF(U*D3V?|)&l?A+r4U2`pyT6TV;u_R EzsswpwEzGB literal 0 HcmV?d00001 diff --git a/booking_system/__pycache__/urls.cpython-311.pyc b/booking_system/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..162be0353cf79ba2ea632763379d4e67d1621ab9 GIT binary patch literal 2104 zcmb7F&2Jk;6yJ5$UdK*ir>&c~Ep$qu$yTXXtyEE2KpPSY5e1>ra4-?u&Cb|fcfT~V zPKYI>9zg0bhf4IwDS*fyz>zzbb!Dm6ibD}6Zm!x>PrTU=u&W}$WM=Z-+c)q1-p7o; zpPelTFn&GxTl@E{ApF6ZbVOf(dActO!nXnz8Uhw^#uDvJBO`Kp%9^sJhGb_O*@%~{ zoGmxxh|XGhd%7_l(K)MN7aK)U$OvQ_R9o|<5)KPx2$kjJOH0R!HUP>%z*?v zta#vAB6sFet|=bQ9ZbP@Sn+6-z>9=SB-1IUvd(-;9b`ZkRy-ojGVEDAKk4-)dPhj< zyCdnz@&EWJ77ve2p1_sEXjTc|E(2^R*aP?C`IiY_8Arv-m z-av-yG|g6*>b~hZsOeI)?YehNr=_ty<`Wxv)a?+%uN4Zn+63M1Qp?kQpHPS0MwZEZ zMBT1W7y@Gq`7YWq$u6s*>tM-tDM6+KM(xaR*9otu3b`n*E0>Ka%C0VGqv#Em%0tMSiNw)>lhL8$ZcfwVhycgjC2Q?w&zm6 zj!=`jHnR6L-SZM*3^UTdl<4yacmQJ&!chpey}Y!vlEl?^ZL)$K-6n4@ae7H9tXVo^ z7q%fVJZAOZP`G}ZP!6OPAx`0Z0Ji=Q8m?c{nZ}JQD=#40a15)9p@xuz$R7`l7dp+) zMwA!?P@p_qmnndq)WN%_xcw=K7&LIP7yOI#4yT~d_7pS*z; zG0f`NHXS7sN<8DCoM^+BqDQE0G6wz0fGxF%uQ8)dY(0t|M6&AEBRujCcFo{@LRc>sMXL5BK&W#7su}7kHS;1EIhxtR^QrWP=u{D!gRW|PS_oICAL;Qv(?u3Y`r~BPCjT`FRU7(_(A}F=gv$D z|BTB(8=t^~7I?%nIB5|*o7{-ZmPr6ff3_1oFU*qXXRqKboEiXUdQ63Y0cf6T=WMnF ztwqmhLV5A{m-V(;t?+%`YKr3fL`alW1xTlP zjB~cnkupgcjf8i|@e#)XaynpXcpZvagdXj5Sd#Ft%Ty@hPDj^!slg(VA`N4W8(jye zh;{K$(q72%A(e<$pj09^9LEz~X?uMZ`(nnaDz&HptL@_lH!s1KsFc1FSuSQp z*VRm1H#3CH?oRpGU40BYub!G3FDqg^2vZSfmQM7r#}2v5mga!J!DUYD>dn?hdrx92 z+gm7E+OD8HP$Fq>CZQj&VZ?%Y^CqeGe{K$MC&Q~-&!^AuA}whM{m($Y(`sT8LMBF$ z6ef_XdqAv{+j$$qlhMsS2IGVE6IOn}%4pRdJ+7TY{Q~MEsES8Bc4l6Bd~s!QNosBklv^AVAD@|* sSrQ+wS5Wzj!zMRBr8Fniu80+A0muo({6OLZGb1D82L>2X#0(Sz0C(;(H2?qr literal 0 HcmV?d00001 diff --git a/bookings/__pycache__/admin.cpython-311.pyc b/bookings/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46137f7ac637a9d2e1bec59bc47b4344910425d5 GIT binary patch literal 1107 zcma)4&1(}u6rY*hO*S#zYfmq{`S3nZ+`RMZ{|m}S|%{w-TSloof7gF zozW-^jlpj)b_pk(h9sgcrGztXge)>#BQjl+5=I2wvPKJqu?JlH@aBV&w}hKJgjnMx zgz{zWjZoWZ(yT2vgT|)cj{MDw=0@I%r`jqNQElj|TGsbcvn_4l%)kUg%>s1B^LX}I zXBDT!rn9V@HJOL-RZU!z8=#A+D?>SRWeTzc$=dpsNnNeCRGLIWW@6~FN`0AnX@Ihc znCDgj{-!PEFnJftz|GbjOIFdDK$t|B0?@ZI#l8e#Dx{po-&y6@mYf>_wyYKaE_V94 zvwAf1xbq%oz6kTzosyp5TYlU~mg-5I%3wp{Wz_{ZG7&0?w_W08*0vN4I4&V|c@1M( zyScpC&X=n>w_oOm{z@*wYP?jlpc}AgUinmd3bQsb4({Yb36CD)*+qm(fK~3 z^m(6LhwfZ&`oSp%&Ja!w!fucA3xrK&EX6~*(4z}|#^{qixenc@z1c^n7&t>fmOIz; HGxh!fzB>il literal 0 HcmV?d00001 diff --git a/bookings/__pycache__/apps.cpython-311.pyc b/bookings/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a72b07b8cfea6be14c1647b66d342e96c56b1f6d GIT binary patch literal 564 zcmZutJx{|h5IrX;D*X~dqEZJ2#w?i;LP%{944^I*15qT)#cmp!FXD74QwM$kTP1z~ z2=QmiR%K;kD=Jeb>?B1XINRrUzUOD(JyokE5Y~N71`lF?lfl{wIanG3Oo0MLE_ld9 z2oyL4s@wrp8G2L!Uc}1GRH)Vkz3?tW9VMI1Fl+~Y-?6W9M!KOqSk?uY0s|9K5O?jd3k4YEJsvb zb33}4l=Hf!P$XNONmV3Di8X;%#lx)3qi9QnvcvpLxP^)kn#11g_gri!sJ?)|?*8&a Lo__w5N+0_ITmqA) literal 0 HcmV?d00001 diff --git a/bookings/__pycache__/middleware.cpython-311.pyc b/bookings/__pycache__/middleware.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41d862de75c1e121f19c870616c0ae412fc63610 GIT binary patch literal 2426 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 b|K)CQC@!*k-!9h{ZyC>d?BzQ$c#;1D)Q~Vq literal 0 HcmV?d00001 diff --git a/bookings/__pycache__/serializers.cpython-311.pyc b/bookings/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c4ef309ed9fdc5ff77bf974a0c85aa778dc48ee GIT binary patch literal 1669 zcmaJ>&2JPp6u0MVC(CX=_y}p!L(2hWRVfmJLxd2hP(Y9nRgK!iXeDciO)|;MZm?&8 z?TG`29FaKCBjON1;ScD6KVqp?>dNY&Qcv7A+MIIgd!FofRPXq=&wlo^-+RC3cg13! zK)ZkC@68()A^+l_+uUQJQvu;M;e^weBs8FuaEsfqmDquuIDtcnMeY*rydc~abgR3M z?Ae6uL(f{^nN=RF%Kgu(9QW5qY2piRDp7q(2^ocP^qY|C3&lB0yT6J`P3YXsYIQrR zY^-PYGjxszodpnH6F~yXNnn|yDI9I>ft&l#vliIghT|MPWo)kX4jVFx=VI&30`!dv zJ8(D+TyB90`{?Y5iNyyZ4RwyOFpe2pEqU5!tP&=IF`Z{Dsq$Kka)GhOwJ^>!5~HVG zP>NW4k0KFs^?`Ko^rN*~SIfUZJXHCXP@ydUDAaaZ-6{XD6K!mU^(5RJ6dz{MVXCfD zk(7^zsyq9(iu7^K)8kF)Zz-q~n1soI+CcD#e z1|_rV3`%|%&?$8dpl`ZuS?+wBjKcxW9iE`b45Q7VcN0$n-!RAm2H7JFn&1wk-_zjr53yt~94Sz2C1{s$hy@?IB^z2VE zNEZzC_y<7>kWHHuZUGG5hkE31~72N!s707v#|Jw z`>FWX(!D>I?tNZbZZ0i13M-!rE6u{n^V@C5cCWO_I2_>I;R%Y&Ej)1*GB_!PO4%a` zFT>NS+?K{K&%6N2_#rXodg=kb34L~D)n)EJTy{tPwd`%VE=#ZxIjmj*v~5c1KjdO# v_-m01jgvlbi$Z~p!^`dF>?QDxLY4NkzDFSj055S`VXR(Dn;fia{A7?CPU5%-ocD0UfA*u=$gL|oXhzV38l_fAHxL>jwr zkuEM>IfMk`pCW?_v7`{BQWtRNDzlLJy(!dzr|R%ClNgB&31W_q|J{kNFI89Kh1-%YxIsN1S`zaoD@Ms?sU49+M zy-vTC<$P#P71cQ(0)_n`LPAT8dRtr3Wr-?j9!femie*n4*E&C>c1oJ}OKynLE*=JH znC$(zTl1v{?MQ5O6uHrMDnq4IfISK zV{`7VpFW+s>o;z7>Q={m2K=P*vGU11-@1M=uG~O<3iS!pGroBK{<>@U#uOS8Xw1uN NXT5RJ47p0z{|2d9r?3D3 literal 0 HcmV?d00001 diff --git a/bookings/__pycache__/views.cpython-311.pyc b/bookings/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8853b1dd642503089d9055bc073a457e6161f49c GIT binary patch literal 7092 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 Rzi%W)9%09mF1^%4{{^K#=tTek literal 0 HcmV?d00001 diff --git a/bookings/admin.py b/bookings/admin.py new file mode 100644 index 0000000..bf7bda3 --- /dev/null +++ b/bookings/admin.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from .models import Venue, Booking + +@admin.register(Venue) +class VenueAdmin(admin.ModelAdmin): + list_display = ("id", "name", "capacity", "address") + +@admin.register(Booking) +class BookingAdmin(admin.ModelAdmin): + list_display = ("id", "venue", "customer_name", "start_time", "end_time", "status") + list_filter = ("status", "venue") diff --git a/bookings/apps.py b/bookings/apps.py new file mode 100644 index 0000000..2b3d34c --- /dev/null +++ b/bookings/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BookingsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'bookings' diff --git a/bookings/middleware.py b/bookings/middleware.py new file mode 100644 index 0000000..eba757c --- /dev/null +++ b/bookings/middleware.py @@ -0,0 +1,41 @@ +# bookings/middleware.py +import logging +import time +import json + +logger = logging.getLogger(__name__) + +class RequestLoggingMiddleware: + """ + Logs request start, method, path, body (if small), response status and duration. + Place this middleware after common Django middleware as configured in settings.py. + """ + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + start = time.time() + try: + # basic request info + method = request.method + path = request.get_full_path() + # try to capture small JSON bodies safely + body = None + try: + if method in ("POST", "PUT", "PATCH") and request.body: + raw = request.body.decode("utf-8")[:2000] + body = raw + except Exception: + body = "" + + logger.info(f"Request start: {method} {path} body={body}") + + response = self.get_response(request) + + duration = time.time() - start + logger.info(f"Request finished: {method} {path} status={response.status_code} time={duration:.3f}s") + return response + except Exception as ex: + # log exception details + logger.exception(f"Unhandled exception during request: {ex}") + raise diff --git a/bookings/migrations/0001_initial.py b/bookings/migrations/0001_initial.py new file mode 100644 index 0000000..2f8d9d4 --- /dev/null +++ b/bookings/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 5.2.6 on 2025-09-30 18:07 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Venue', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('address', models.CharField(blank=True, max_length=300)), + ('capacity', models.PositiveIntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='Booking', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('customer_name', models.CharField(max_length=200)), + ('customer_email', models.EmailField(max_length=254)), + ('start_time', models.DateTimeField()), + ('end_time', models.DateTimeField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('status', models.CharField(choices=[('CONFIRMED', 'Confirmed'), ('CANCELLED', 'Cancelled')], default='CONFIRMED', max_length=20)), + ('venue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bookings', to='bookings.venue')), + ], + ), + ] diff --git a/bookings/migrations/__init__.py b/bookings/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bookings/migrations/__pycache__/0001_initial.cpython-311.pyc b/bookings/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3db58d42aa63568759bcb15fe7f4dc886c759710 GIT binary patch literal 2196 zcmb7FO>7fK6rNrGJC3nKz&NpSND!(Cihu+QD6N{#|H8v^d~oZ&DT}l6+rm~VT1)0l>~T;s#x=sJT-60DKu=&Z*zXarfW6q)^zVBC2Rv?D7jeMx4E1_&uo>DHzz3eb zPxzRRfCrk9eL(UYp1#+hiA4mZ!`939K?K#JpMnB4;@2w67tiI&p;O> z!ow$IcgFFF^nCU~dEPS+Fm(1`#uJ~8W1)HOc-}ba_F0#}=;ORo{bT{YS_NljMN!@qb?*tBHBk}L&a1&M}TE!@pV zk}X)sO;OVyO8}4gA;M~yfG(6@SuQR;xHn$_RoB)PqeigPKf9ctzkAo|m$eE}Rf3HS zEO$7}p?g@MvY{&#VjA3b)AMaR%m&w7@aB_fPn&W^AS$G566|_n0iOm@IpJ<*qNOiq zPqU!pn3BZ8k^~1tLnWX`BV~{ilQ%wAyTnQ6j%krvxyNJq!}(dhdiClxsY}IFeaGPEq9gd`F<(RV z?e?!X(V^Xij#n7=@80bMQ7H3s*bbg=$IrcqpP`A%Pq*#F<(J-97imeNnn4q0D`DCR zlg6xeJVBG$y|Z>Q`(l+QZ?%%Q?Bp#PyWNhD(A1T^qMf?(V&))EQ;V(CqMcf#v88r= zl%{X)J+jj`58^bPZ>95gI!|MTPRKVL?f8PB@LL4ph>On92RI}D0nQj5zy9o!J%0UV zg^tg)#^>zuIU38i;}__}%(I+5F>~Od6NT19!Ja74*nB&lrkUxzZ96mF%G|IsH)t&9 z0KCQlUTdYN?esK_&3xo{FibPWR;FlYiZr&+jwk8p07^qjnH_EX;}U zS`qK_SL%WI){#e!gr4}S2>jBK$-PVV$mEOl-xWJov~w$V?t8jk2ZwE;$RkG=cqB-O z1j!>8#ZElLiHdNdKpb(=Ig=Rj?|#iM<4*5eXZnF`Hu{X7ba(vc1%C(q TQ#=jZv5Rl{z|je#4u-!0Ha$-I literal 0 HcmV?d00001 diff --git a/bookings/migrations/__pycache__/__init__.cpython-311.pyc b/bookings/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13356ff54b96c947a0a2fb7e5123100d875e6eb0 GIT binary patch literal 200 zcmZ3^%ge<81i=??Wq|0%AOZ#$p^VRLK*n^26oz01O-8?!3`I;p{%4TnuV`nhn9$S8Bc4l6Bd~s!QNosBklv^B=o0(pe zSdy8aR~!=`pP83g5+AQuQ2C3)CO1E&G$+-rh!toT$Th|MK;i>4BO~Jn1{hJq3={(Z DG-)>3 literal 0 HcmV?d00001 diff --git a/bookings/models.py b/bookings/models.py new file mode 100644 index 0000000..6fb3359 --- /dev/null +++ b/bookings/models.py @@ -0,0 +1,32 @@ +from django.db import models + +# Create your models here.# bookings/models.py + +class Venue(models.Model): + name = models.CharField(max_length=100) + city = models.CharField(max_length=50) + capacity = models.IntegerField() + description = models.TextField(blank=True, null=True) + image = models.ImageField(upload_to="venues/", blank=True, null=True) + + def __str__(self): + return f"{self.name} ({self.city})" + + +class Booking(models.Model): + venue = models.ForeignKey(Venue, related_name="bookings", on_delete=models.CASCADE) + customer_name = models.CharField(max_length=200) + customer_email = models.EmailField() + start_time = models.DateTimeField() + end_time = models.DateTimeField() + created_at = models.DateTimeField(auto_now_add=True) + + STATUS_CHOICES = [ + ("CONFIRMED", "Confirmed"), + ("CANCELLED", "Cancelled"), + ] + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="CONFIRMED") + + def __str__(self): + return f"Booking {self.id} at {self.venue.name} for {self.customer_name}" + diff --git a/bookings/serializers.py b/bookings/serializers.py new file mode 100644 index 0000000..715fb0c --- /dev/null +++ b/bookings/serializers.py @@ -0,0 +1,15 @@ +# bookings/serializers.py +from rest_framework import serializers +from .models import Venue, Booking + +class VenueSerializer(serializers.ModelSerializer): + class Meta: + model = Venue + fields = "__all__" +class BookingSerializer(serializers.ModelSerializer): + venue = serializers.PrimaryKeyRelatedField(queryset=Venue.objects.all()) + + class Meta: + model = Booking + fields = ["id", "venue", "customer_name", "customer_email", "start_time", "end_time", "status", "created_at"] + read_only_fields = ["created_at", "status"] diff --git a/bookings/tests.py b/bookings/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/bookings/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/bookings/urls.py b/bookings/urls.py new file mode 100644 index 0000000..a16e193 --- /dev/null +++ b/bookings/urls.py @@ -0,0 +1,9 @@ +# bookings/urls.py +from rest_framework import routers +from .views import VenueViewSet, BookingViewSet + +router = routers.DefaultRouter() +router.register(r"venues", VenueViewSet, basename="venues") +router.register(r"bookings", BookingViewSet, basename="bookings") + +urlpatterns = router.urls diff --git a/bookings/views.py b/bookings/views.py new file mode 100644 index 0000000..b48f9f4 --- /dev/null +++ b/bookings/views.py @@ -0,0 +1,111 @@ +from django.shortcuts import render + +# Create your views here. +# bookings/views.py +from rest_framework import viewsets, filters, status +from rest_framework.decorators import action +from rest_framework.response import Response +from .models import Venue, Booking +from .serializers import VenueSerializer, BookingSerializer +from django.shortcuts import get_object_or_404 +from django.utils import timezone + +from rest_framework.decorators import action +from rest_framework import viewsets, status +from rest_framework.response import Response +from .models import Venue, Booking +from .serializers import VenueSerializer, BookingSerializer + +class VenueViewSet(viewsets.ModelViewSet): + queryset = Venue.objects.all() + serializer_class = VenueSerializer + + # Custom endpoint: /venues/findByCity?city=Paris + @action(detail=False, methods=["get"]) + def findByCity(self, request): + city = request.query_params.get("city") + venues = Venue.objects.filter(city__iexact=city) if city else Venue.objects.all() + serializer = self.get_serializer(venues, many=True) + return Response(serializer.data) + + # Custom endpoint: /venues/{id}/availability + @action(detail=True, methods=["get"]) + def availability(self, request, pk=None): + venue = self.get_object() + bookings = Booking.objects.filter(venue=venue, status="active") + return Response({ + "venue": venue.name, + "city": venue.city, + "capacity": venue.capacity, + "active_bookings": bookings.count(), + "available": venue.capacity - bookings.count() + }) + + # Custom endpoint: /venues/{id}/uploadImage + @action(detail=True, methods=["post"]) + def uploadImage(self, request, pk=None): + venue = self.get_object() + file = request.FILES.get("file") + if not file: + return Response({"error": "No file uploaded"}, status=400) + venue.image = file + venue.save() + return Response({"status": "Image uploaded", "venue": venue.name}) + + # Custom endpoint: /venues/{id}/bookings + @action(detail=True, methods=["get"]) + def bookings(self, request, pk=None): + venue = self.get_object() + bookings = Booking.objects.filter(venue=venue) + serializer = BookingSerializer(bookings, many=True) + return Response(serializer.data) + + + +class BookingViewSet(viewsets.ModelViewSet): + queryset = Booking.objects.all().order_by("-created_at") + serializer_class = BookingSerializer + filter_backends = [filters.SearchFilter] + search_fields = ["customer_name", "customer_email"] + + def get_queryset(self): + qs = super().get_queryset() + venue_id = self.request.query_params.get("venue") + if venue_id: + qs = qs.filter(venue_id=venue_id) + return qs + + # Example custom action: cancel booking (POST /api/bookings/{id}/cancel/) + @action(detail=True, methods=["post"]) + def cancel(self, request, pk=None): + booking = self.get_object() + booking.status = "cancelled" + booking.save() + return Response( + {"status": "Booking cancelled", "id": booking.id}, + status=status.HTTP_200_OK + ) + # Custom endpoint: /bookings/findByStatus?status=active + @action(detail=False, methods=["get"]) + def findByStatus(self, request): + status_param = request.query_params.get("status", None) + if status_param: + bookings = Booking.objects.filter(status=status_param) + else: + bookings = Booking.objects.all() + serializer = self.get_serializer(bookings, many=True) + return Response(serializer.data) + + # Custom endpoint: /bookings/{id}/uploadDocument + @action(detail=True, methods=["post"]) + def uploadDocument(self, request, pk=None): + booking = self.get_object() + file = request.FILES.get("file") + if not file: + return Response({"error": "No file uploaded"}, status=400) + + # In a real app, save file to booking record or storage + return Response( + {"status": "File uploaded", "filename": file.name, "booking_id": booking.id}, + status=200 + ) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..92543c7e4097ac4d561f31a2af993346789de6e0 GIT binary patch literal 143360 zcmeI5eQX=&eaCqsMT(Zl(~IRxV#_*FR$^9G#8**Fnk9UxL!R<(%=(8zO zCMnrQfo+tXG;OwF>#zbFwsjaVV8iyux((=tu0YXY>(*gwF|@g6T9p~-92+Pd11lb%73Ab4Jq zWsk=*Y5b>O{O1MQ`i#%)mtgz6)5l5Avs-WXGGp-v%tjJ_5E|?Me*e?`e;NE*;CsQ} z^M9eYy@H*N8M~(S2pWfO)1r?n;Z4k zXT8|kRp>)Dl}yJ9v4XN$(Qi4;M^0bKEv)3^Ys-t5ujS;$R_^vFh2pu{|{PbWzdY!~y*iC%P6Y0*!6R|>mE$gm(XkWU!ob4sK zoq^Qe5c{O2H!EyU?n`b*VU<{+m`tSeF{|Zt5gOdN{dCz{O>&ph?7M8#q&nPCVNZmq zYNk7?#%5BeRvKERp)~GpXsk&k)>4@{EtTh0W7&x=bz-F|J9)9`wyatEabzHwS3?2m z?zFHiT2*3Y={iB7TGT4)x~9b9YCf4st5$7TxxzbFgJrZ&*ZVFB)j(TZB)a|DKtNhp z5bi(UQ1j(hKjpojZ!8gYYix0*gp5M0EWEswvyUfELxzJ=_& zad~lNabam`)i{_t)71#OHFbHnSnTf{(d}4&K$@8m?vFUo@*ZXb+S(u331chyv4Ync zBlcG-+;*SH?tLH_kjBS_HzzxhnT_wz4v-#*&W2jA->%lEMQ*9J!gaNFGM<=^n$40L zNm;EolybGCS0ZvzZDb-hs^3;yvU*pmV{{!2y3~A^ z(E~MumY0X#n2EYoD0Tz&D8`uPpg$l@ObE@J4xpSlFIiwGa1R8lvklI7x94aw;Fr!$ z?Ak0^#9Qrxf9|8ZX!hT;eWEuYO-~E=e%>mNMUfZE+V#7X%u0O-#Y@|YN7d=PCD^?} zi#OCtsoHVzHYDwRaWb#Z*2omIX^A$^`2tckDKtOAJDba?6m?@mDXV#{tgO?WNLk6u z<%`K;GS6>ATr%_;Fgs@yE{3~%Zrz2rWMgGFHL-~WmqoW#C2v4VCWY-yUgIt~T@Lv= zYu?4;A=G}{j+_Kr>fLL_ER%b3^iq$XHSJYiPGh{RYqvJFN)( zZLSIdX?9lFR_*N8^-@i3u*sOg#X8W_;WyHi{y@}-i*?;eq&qJ>o#TZwm9m!guB!`; z1EWVnv>oX`>Jh&veo`!o6XAae|6=&%(2qi&4c!i<2EIA)seum<4E2Ax|Be1jWQHFQ z009sH0T2KI5C8!XIH&}YBfXxnsfD`MT5^fSVsS;U=nY*hCt`{8Oe{N-jLGr&=VF=X z67gp<>2xfUP7d=-6yv$6S4#CgGo@mQ%-p%5UeD;O3vAv^CrK!3xj`#dJS1xct(0~3 zj#AbtrN(vF(7m&l|~i{#-#+e6II z(h4Q8S;ihR<}%sDeClkNoLn=U#Ip7R@mSw}9Hld)=9LgRy4rR$Z+FxV`|TwtnItaf z2guLsZ9f^q&z4%&iBGjg!MS2l(Q377OYq8N#qTj(cei*09fN{wchdQEG` zAlM2@U7?y!xKU1Lsm3!eA0ij$+b+`fa#_JprLtLeZEETHH2HWbNIu$i9ZT7Lm~5&W z4cCIC(^S`~(|zQjUDvUs-2;zv?twO)WKPZn$Vt2L#@db73J~##>t3E>RG`#3f3Iii z?1B;h;TRc3;=5kmGV!)ns8|bf!<(Y^mzi7a?e$2cskp9J$VHL`muYdUc9+*P3&d6{ z%34`1DTV7*o#Fznu2}Kr7JTH2C>yR4mMcRR_1Y?P>*^vACl@g^h1hX+3&= zezu30QVu>K>^|%yGx6knHX{(aDJQz!&y=Jy&4t82@c6|okN7R|tKw(HE%9yfH^n;# zbx23KKmY_l00ck)1V8`;KmY_l00cnb$4Ows=baWDkJ-qfpm(B=ALP-tfkWQ$Am3%t z98x#ZN;D%YlGmFQT%O738|m@R^ce{}Zoy&}qk?y~ZEZcNFmi|-_lX6M_}}6`h+h{! zClZ0dCiR+Q|6rKjxd76zoq#*gp4$e50d0jKCrUzOZjp;(I)N;2rUePVikbU{L89 z@=0Ss9ujCj5W$}Rm;29n#QzZgRD4U!i_eJz;r|T(dH9pzT6j79Y;QIq#9r)vc`vX5a@bbX%{{QR$djDVa|4RRLa)2KY009sH0T2KI5C8!X_z58p zk$XMD)J)%&uH9CQ8~oF1MP~c#uRX9g0iGTwn`pd`-VxX64>;JYT1QN~<1IV-I~kQy zhh6JP+fE)MyUFQ3_T0M78SS<$jvph7iD-bU;xi0W6W@y*rSz$pfT75=F!Z!+o@&_` zYD^nL3*SHXB-xBV6JSbA1E!?u($!R}RWHVx#jNR$OWHFQJ<*IBmDpQ$pOlA+E&(eD!Lj3t&L!QIjkl2xd z-T`4544sY)hE{uqD82t7Os9L9V23pmZ8tqeFL)4bA6L$%eWql#Bh$+pRC1powViHg z(WTt|BK2EPuP@D4dv-4@Dd3wGVp*JI_O?i#; zn-+$EmJPl7z-$Z!ri~$i?;oRA8>p0Crol8|BKXcpdTl|NPWEsW*6h}lVjVgaAj{cI zkD)8m*(ulnJ$toS+v7g3rXc*!Ha3 zlu8F={$j#OdPg8Qoi>Ep?F^ZgCA}L!mWD{Xr6JL@jL=H~!Kqm$&~C=$nKo?wUk-iD zBYu}w|Nn+!0KYB1A+C$Bif6@?I3W&-LioGkZ-oCb{F(6Ygx?5P!aox}8%~7B!(!-% zp>Ku$HT1WkPltYs9N-58KmY_l00ck)1V8`;KmY_lV1ERLeZrK`5kis=`-G_Ah!~Bx z4jQvRBl2^6$R|t+_E^x^pih_(Y_XqX+OFFFfBOaB|}`j z6&e}j0_?#Mv3107$RZlyuum8h%wR`|bF;-a1~`F^fJT4okl}jl=Gj7Z zz3XoirZdlGVu|?tJX`-4#CJUOFYsQAi2NV`0w4eaAOHd&00JNY0w4eaAOHf76@fml z6yz}iw*K!Ke5|xV3*A~8W$`>Yzz+z300@8p2!H?xfB*=900@8p2pn_*yZ;$is z7~2Mp@$FH*eTr|NWLy6ed@J$o5xyN|+up-`JHofad^^OpzCpef`8LeAA-44n@NGZe z9^%^|+xGPFZGdn6eB0~u1_dA6c-f}M>kS66{(sOLC&~u`AOHd&00JNY0w4eaAOHd& z00JHl|D%8S{y#JY5C8!X009sH0T2KI5C8!X009s<&;&65KhV{S!hrw?fB*=900@8p z2!H?xfB*=904IR?KN0+|0F{5nPnK>!3m00ck) z1V8`;KmY_l00ck)^MAAf5C8!X009sH0T2KI5C8!X009s<_yj_M?|DSwiyrYr_@9Gc z^M4_9d*I{#!@aNie!c&l;ER2^{ttTpPWWQaMd1^kuXtW?@MsQ>1f+{ILNl&cirO7@ zvvFP7tZOx;RI6@o)LWnRqB5t(6IyXT?=(1k`butLB_}T~pUJ%@N1VxB`6KehsRYjr1*B3|XsT8TTB#daZC$U|^=hTASf5!T=I{O7(SS5FBYbqWq2|k4@rGI{ zRTZ_ku2+Ox4c3nsOE2Ig$AjK$PMjIgJ-Y~*R+jVMBY+sh3jhVWFi)enqJ9B zEi|Z9%34`1MdbRrS}xP6<;_Z6FIBXnX(^vRmpgr)#C6#J)C+PfN>0dgrKBnATD`88 zw6+REI!muoaVia^ad$)GGR@+#qFu?olDm>yKApR2@~~$xkVNG(%2A5VIonHeJ3}P8 z9qZ>q-~ACj^jQs=o7A2A1BM=B=yN6;{jt0E?l$!CCha<4zPCPa7P4DTmt$_bztJSx z|Fq|lG(Il8IoXNKgmGvGNITGJ-X86fn!yEOd)8_(9E!8Eo0s&C9Rf&SQ18Eeb|S_PDG^>Av@fG%+DGZ`y%2=Z^%W0$p=g9hJXhJ5;l2O)bW4 zH^NTSCwFQOPD8V8w|zPrhBJe`Ax9s_JNFwR4I}q;ekFqL}U4&wVVlt7= z$E*>gE9>CSqeqwRzD{E!-sPa9Lw2>%==N&^0cl}Dxc|J>pm>EjYt0%joGBrfp6cr2 zfqEz+4Y{ofJOz%B@Y00@8p2!H?xfB*=900@8p2pm8HA@5nwknoo0&An1T75`p#CLl$l!kaTZDpS#J zD~cH{>)Z=;#$!4YA1D~Jq1NlSt2GL#w3oEwiTRF*Oj)fr*wVXRv4>q~rI~_(dR?h+ zQecY(*&=ejS}n`X%~@WWdsDnLbnK>HDb+(zb8)^{tkIgf zRn(-zprCH31-)_C3g_*-a&Ou4W&3FSS-+GU7d$-VYee9v7OQ;Us!t_uR&8H%Xga`y z@#`EFPvG%a>yy}7;a0*!z!Oi~o?VbzOHonpFMEbBPqSk96Mo)LlBfLA*@;~X)(RT8 zO2$8rANr;zu^$@uQbyaKy!Qe6wA)giqwSj*ABe<5Z}#mcOQ=(@&d}Kq-AI!m?^(N8 zl8Lsi>Se3JCeo>nzRCJuLtR@l`kqY$rLYGrwkVj&yQM9O#ZHwQ)G%EGsdUmcy+&Pr z7h%!ni3lyMPj@V=Tk&nh{=5lW(@3nPGILt0wOVA^g^k8-e`?A~-O-C}wZgJyt-x_w zTGYHc5s>aq3)`Z#5MyQOIzgdY)L5yNSX|8~GilXYgRye?4bd)3x0ca9UGKXjR4Hw7 z^qjzy9AFCr_XTU%uujeUg|*x3GJsgA57c*@n0H^NG}aXCnT)gUu~um>vvqNDjM$xx zG+|#%h&IoS)00F=q4^PB`z}HhT2D~QYF;ZV>s0q;B{P>VCX2~DuXvXXKG({3G2GpA ztKMC*F*2qmwo1=sQA1ul9*~krVLQvK+$E>Wp|Q@Ycd>Y&>bLamSSu~n?#Z-bJ7#~@ z(vW37;b$%f7t(VnEw9cw4UQSbGDZz&a##Ki*yd?i(c4Rd(dNlx0ZE~UA1>QlifP;3 zn^XCMHm~KK=RUfJGUkb4jDZ4UfSAXM@1WktR>pcMV);v!SA5ApRsp#!@5(! zgliYKIc|%&snJbs`wl;4zwfg>4o2fm+n!3Tc0YJ(m+7(u`+U+bU5xH@r`V}niFfWt znj>-h14!m%!1&ObKd?@diYN1lq?UAA$ep#}Ozw8jstl(cs}4R_p>su|_nwLIXY$@` zU2C1j&i($*`fw&c(0E(etT(Fb^enpLTIaYDnr3_4GSdBGjUF9#fBKeMfL1B)l3J)~ zboW?P)P{XBXg!)t-W!{?8CJs9)X2FBR?h1*p`>T4jjSC{Et}Z5xdCmDyM-v${~xcY z2GoE62!H?xfB*=900@8p2!H?xfWV_5fcgKUpbDQL00JNY0w4eaAOHd&00JNY0wC~s z5y1Ta@v0A~0Ra#I0T2KI5C8!X009sH0T2LzM?nDd|3^U;K0yEkKmY_l00ck)1V8`; zKmY_l;PE1W`TyfpA5a4VAOHd&00JNY0w4eaAOHd&00NJKK!}|7iFuFs9r549FNuF8 zeoFkfc$*I32LwO>1V8`;KmY_l00ck)1V8`;K;T^v80qtQ#*ViCIKT0GC_o3L_Cfv! z`$zoD&iE#Yy7BvHug^0zX?&eYv?sAW{#|0jJ+wQ) zcCGI%8WMaSX^ekC3w<-4R%z7kviZMf@Ld!KrXT#rK_f2nGQV009sH0T2KI5C8!X009sH0T9?10o(k4U-mEp0T2KI5C8!X009sH z0T2KI5C8!Xc>fW=^Z)O^I)h>m009sH0T2KI5C8!X009sH0T6h%1hD@9Zi&Gj1V8`; zKmY_l00ck)1V8`;KmY{Ze*`f9fB)4P6oUW=fB*=900@8p2!H?xfB*=9z`G^z|GIx| AQ2+n{ literal 0 HcmV?d00001 diff --git a/logs/api.log b/logs/api.log new file mode 100644 index 0000000..41f9397 --- /dev/null +++ b/logs/api.log @@ -0,0 +1,33 @@ +[2025-09-30 21:08:56,616] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 21:09:36,669] INFO bookings.middleware: Request start: GET /api/ body=None +[2025-09-30 21:09:36,693] INFO bookings.middleware: Request finished: GET /api/ status=200 time=0.024s +[2025-09-30 21:10:00,790] INFO bookings.middleware: Request start: GET /swagger/ body=None +[2025-09-30 21:10:00,883] INFO bookings.middleware: Request finished: GET /swagger/ status=200 time=0.093s +[2025-09-30 21:10:02,120] INFO bookings.middleware: Request start: GET /swagger/?format=openapi body=None +[2025-09-30 21:10:02,144] INFO bookings.middleware: Request finished: GET /swagger/?format=openapi status=200 time=0.024s +[2025-09-30 21:11:08,908] INFO bookings.middleware: Request start: GET /swagger.json body=None +[2025-09-30 21:11:08,936] INFO bookings.middleware: Request finished: GET /swagger.json status=200 time=0.027s +[2025-09-30 22:20:11,279] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\views.py changed, reloading. +[2025-09-30 22:20:12,596] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 22:20:16,338] INFO bookings.middleware: Request start: GET /swagger/ body=None +[2025-09-30 22:20:16,365] INFO bookings.middleware: Request finished: GET /swagger/ status=200 time=0.028s +[2025-09-30 22:20:17,138] INFO bookings.middleware: Request start: GET /swagger/?format=openapi body=None +[2025-09-30 22:20:17,230] INFO bookings.middleware: Request finished: GET /swagger/?format=openapi status=200 time=0.092s +[2025-09-30 22:21:44,602] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\views.py changed, reloading. +[2025-09-30 22:21:45,825] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 22:21:46,318] INFO bookings.middleware: Request start: GET /swagger/ body=None +[2025-09-30 22:21:46,345] INFO bookings.middleware: Request finished: GET /swagger/ status=200 time=0.027s +[2025-09-30 22:21:47,206] INFO bookings.middleware: Request start: GET /swagger/?format=openapi body=None +[2025-09-30 22:21:47,299] INFO bookings.middleware: Request finished: GET /swagger/?format=openapi status=200 time=0.093s +[2025-09-30 22:22:30,864] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\views.py changed, reloading. +[2025-09-30 22:22:31,796] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 22:22:34,154] INFO bookings.middleware: Request start: GET /swagger/ body=None +[2025-09-30 22:22:34,183] INFO bookings.middleware: Request finished: GET /swagger/ status=200 time=0.029s +[2025-09-30 22:22:34,674] INFO bookings.middleware: Request start: GET /swagger/?format=openapi body=None +[2025-09-30 22:22:34,710] INFO bookings.middleware: Request finished: GET /swagger/?format=openapi status=200 time=0.036s +[2025-09-30 22:48:48,940] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\models.py changed, reloading. +[2025-09-30 22:48:50,022] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 22:49:30,550] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\serializers.py changed, reloading. +[2025-09-30 22:49:31,697] INFO django.utils.autoreload: Watching for file changes with StatReloader +[2025-09-30 22:50:34,260] INFO django.utils.autoreload: C:\Users\Cesar\Desktop\Apighaymah\Apighaymah\booking_system\bookings\views.py changed, reloading. +[2025-09-30 22:50:35,299] INFO django.utils.autoreload: Watching for file changes with StatReloader diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..a330967 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'booking_system.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()