11# jsweb/admin.py
22import os
33import logging
4+ from jinja2 import Environment , FileSystemLoader
5+ from jsweb import __VERSION__
46from jsweb .blueprints import Blueprint
57from jsweb .database import db_session
68from jsweb .forms import Form , StringField
7- from jsweb .response import redirect , url_for , render , HTMLResponse
9+ from jsweb .response import redirect , url_for , HTMLResponse
810from jsweb .auth import admin_required , login_user
911from sqlalchemy .inspection import inspect
1012
@@ -16,7 +18,10 @@ class Admin:
1618 """
1719 def __init__ (self , app = None ):
1820 self .models = {}
19- # Define the path to the admin's own static files
21+
22+ admin_template_dir = os .path .join (os .path .dirname (__file__ ), "admin_templates" )
23+ self .jinja_env = Environment (loader = FileSystemLoader (admin_template_dir ))
24+
2025 admin_static_folder = os .path .join (os .path .dirname (__file__ ), 'admin_static' )
2126
2227 self .blueprint = Blueprint (
@@ -29,26 +34,41 @@ def __init__(self, app=None):
2934 if app :
3035 self .init_app (app )
3136
37+ def render (self , request , template_name , context = None ):
38+ """Renders a template using the admin's isolated Jinja2 environment."""
39+ if context is None :
40+ context = {}
41+
42+ context ['request' ] = request
43+ context ['app' ] = self .app
44+ context ['admin_models' ] = self .models .keys ()
45+ context ['url_for' ] = lambda endpoint , ** kwargs : url_for (request , endpoint , ** kwargs )
46+ context ['library_version' ] = __VERSION__
47+
48+ if hasattr (request , 'csrf_token' ):
49+ context ['csrf_token' ] = request .csrf_token
50+
51+ template = self .jinja_env .get_template (template_name )
52+ body = template .render (** context )
53+ return HTMLResponse (body )
54+
3255 def init_app (self , app ):
3356 self .app = app
3457 self ._register_dashboard_and_login ()
3558 self .app .register_blueprint (self .blueprint )
3659
3760 def _register_dashboard_and_login (self ):
3861 """Registers the main admin dashboard and handles login."""
39- def index (request ):
62+ async def index (request ):
4063 error = None
4164 if request .user and getattr (request .user , 'is_admin' , False ):
42- context = {
43- "admin_models" : self .models .keys (),
44- "request" : request
45- }
46- return render (request , "dashboard.html" , context = context )
65+ return self .render (request , "dashboard.html" )
4766
4867 if request .method == "POST" :
4968 from models import User
50- username = request .form .get ("username" )
51- password = request .form .get ("password" )
69+ form_data = await request .form ()
70+ username = form_data .get ("username" )
71+ password = form_data .get ("password" )
5272
5373 user = User .query .filter_by (username = username ).first ()
5474
@@ -59,7 +79,7 @@ def index(request):
5979 else :
6080 error = "Invalid credentials or not an admin."
6181
62- return render (request , "login.html" , context = {"error" : error , "request" : request })
82+ return self . render (request , "login.html" , context = {"error" : error })
6383
6484 self .blueprint .add_route ("/" , index , endpoint = "index" , methods = ["GET" , "POST" ])
6585
@@ -80,75 +100,71 @@ def register(self, model):
80100 pk_name = inspect (model ).primary_key [0 ].name
81101
82102 @admin_required
83- def list_view (request ):
103+ async def list_view (request ):
84104 records = db_session .query (model ).all ()
85105 columns = [c .name for c in model .__table__ .columns ]
86- records_data = [r .to_dict () for r in records ]
106+ records_data = [{c .name : getattr (r , c .name ) for c in model .__table__ .columns } for r in records ]
107+
108+ AddForm = self ._create_form_for_model (model )
109+ add_form = AddForm ()
110+
87111 context = {
88112 "model_name" : model_name ,
89113 "columns" : columns ,
90114 "records" : records_data ,
91115 "pk_name" : pk_name ,
92- "admin_models" : self .models .keys (),
93- "request" : request
116+ "add_form" : add_form
94117 }
95- return render (request , "list.html" , context = context )
118+ return self . render (request , "list.html" , context = context )
96119
97120 @admin_required
98- def add_view (request ):
121+ async def add_view (request ):
99122 ModelForm = self ._create_form_for_model (model )
100- form = ModelForm (formdata = request .form )
101- if request .method == "POST" and form .validate ():
123+ form_data = await request .form ()
124+ form = ModelForm (formdata = form_data )
125+
126+ if form .validate ():
102127 new_record = model ()
103128 for field_name , field in form ._fields .items ():
104129 setattr (new_record , field_name , field .data )
105130 new_record .save ()
106131 return redirect (url_for (request , f"admin.{ model_name .lower ()} _list" ))
107132
133+ records = db_session .query (model ).all ()
134+ columns = [c .name for c in model .__table__ .columns ]
135+ records_data = [{c .name : getattr (r , c .name ) for c in model .__table__ .columns } for r in records ]
108136 context = {
109137 "model_name" : model_name ,
110- "form" : form ,
111- "record" : None ,
112- "admin_models" : self .models .keys (),
113- "request" : request ,
114- "pk_name" : pk_name
138+ "columns" : columns ,
139+ "records" : records_data ,
140+ "pk_name" : pk_name ,
141+ "add_form" : form
115142 }
116-
117- # If it's an AJAX request, render only the partial
118- if request .headers .get ("X-Requested-With" ) == "XMLHttpRequest" :
119- return render (request , "form_partial.html" , context = context )
120-
121- # Otherwise, render the full page
122- return render (request , "form.html" , context = context )
143+ return self .render (request , "list.html" , context = context )
123144
124145 @admin_required
125- def edit_view (request , ** kwargs ):
146+ async def edit_view (request , ** kwargs ):
126147 record_id = kwargs .get (pk_name )
127148 record = db_session .query (model ).get (record_id )
149+
128150 ModelForm = self ._create_form_for_model (model , instance = record )
129- form = ModelForm (formdata = request .form )
130- if request .method == "POST" and form .validate ():
131- for field_name , field in form ._fields .items ():
132- setattr (record , field_name , field .data )
133- record .save ()
134- return redirect (url_for (request , f"admin.{ model_name .lower ()} _list" ))
135151
136- context = {
137- "model_name" : model_name ,
138- "form" : form ,
139- "record" : record ,
140- "admin_models" : self .models .keys (),
141- "request" : request ,
142- "pk_name" : pk_name
143- }
144-
145- if request .headers .get ("X-Requested-With" ) == "XMLHttpRequest" :
146- return render (request , "form_partial.html" , context = context )
152+ if request .method == "POST" :
153+ form_data = await request .form ()
154+ form = ModelForm (formdata = form_data )
155+ if form .validate ():
156+ for field_name , field in form ._fields .items ():
157+ setattr (record , field_name , field .data )
158+ record .save ()
159+ return redirect (url_for (request , f"admin.{ model_name .lower ()} _list" ))
160+ else :
161+ form = ModelForm ()
147162
148- return render (request , "form.html" , context = context )
163+ context = {"model_name" : model_name , "form" : form , "record" : record , "pk_name" : pk_name }
164+ return self .render (request , "form.html" , context = context )
149165
150166 @admin_required
151- def delete_view (request , ** kwargs ):
167+ async def delete_view (request , ** kwargs ):
152168 if request .method == "POST" :
153169 record_id = kwargs .get (pk_name )
154170 record = db_session .query (model ).get (record_id )
@@ -157,6 +173,6 @@ def delete_view(request, **kwargs):
157173 return redirect (url_for (request , f"admin.{ model_name .lower ()} _list" ))
158174
159175 self .blueprint .add_route (f"/{ model_name .lower ()} " , list_view , endpoint = f"{ model_name .lower ()} _list" )
160- self .blueprint .add_route (f"/{ model_name .lower ()} /add" , add_view , endpoint = f"{ model_name .lower ()} _add" , methods = ["GET" , " POST" ])
176+ self .blueprint .add_route (f"/{ model_name .lower ()} /add" , add_view , endpoint = f"{ model_name .lower ()} _add" , methods = ["POST" ])
161177 self .blueprint .add_route (f"/{ model_name .lower ()} /edit/<int:{ pk_name } >" , edit_view , endpoint = f"{ model_name .lower ()} _edit" , methods = ["GET" , "POST" ])
162178 self .blueprint .add_route (f"/{ model_name .lower ()} /delete/<int:{ pk_name } >" , delete_view , endpoint = f"{ model_name .lower ()} _delete" , methods = ["POST" ])
0 commit comments