aminalaee / sqladmin Goto Github PK
View Code? Open in Web Editor NEWSQLAlchemy Admin for FastAPI and Starlette
Home Page: https://aminalaee.dev/sqladmin/
License: BSD 3-Clause "New" or "Revised" License
SQLAlchemy Admin for FastAPI and Starlette
Home Page: https://aminalaee.dev/sqladmin/
License: BSD 3-Clause "New" or "Revised" License
No response
Hello !
First, thanks for this amazing package, this community really needs this.
I tried to use sqladmin
with Ormar https://github.com/collerek/ormar/ which is basically another ORM built on top of SQLalchemy. And it seems that sqladmin
has troubles with fields, even though under the hood it's SQLachemy, I think you have the same problem while implemtenting SQLModel.
So I figured out maybe if we implement for SQLmodel, we shouldn't be that far from being to implement another ORM.
Traceback (most recent call last):
File "/.cache/pypoetry/virtualenvs/api-5UH-8tMH-py3.10/lib/python3.10/site-packages/sqladmin/models.py", line 57, in __new__
mapper = inspect(model)
File "ache/pypoetry/virtualenvs/-5UH-8tMH-py3.10/lib/python3.10/site-packages/sqlalchemy/inspection.py", line 71, in inspect
raise exc.NoInspectionAvailable(
sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'ormar.models.metaclass.ModelMetaclass'>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/pegazor_api/__main__.py", line 95, in <module>
class UserAdmin(ModelAdmin, model=User):
File "/pypoetry/virtualenvs/i-5UH-8tMH-py3.10/lib/python3.10/site-packages/sqladmin/models.py", line 59, in __new__
raise InvalidModelError(
sqladmin.exceptions.InvalidModelError: Class User is not a SQLAlchemy model.
Thank you :)
No response
No response
Error while query the Model :
sqlalchemy.exc.CompileError: MSSQL requires an order_by when using an OFFSET or a non-simple LIMIT clause
Why?
MSSQL requires an order_by when using an offset.
Setup:
Original code:
Line 261 in 2205de1
My change:
https://github.com/bigg01/sqladmin/blob/main/sqladmin/models.py#L262
# sqlalchemy.exc.CompileError: MSSQL requires an order_by when using an OFFSET or a non-simple LIMIT clause
query = select(cls.model).order_by("id").limit(page_size).offset((page - 1) * page_size)
I think in general it would make sense to add an option for ordering ?
What do you think ?
Regards
master
.This is not intended:
Deploy the docs.
The docstring should be from the file sqladmin/models.py
:
No response
No response
Github Actions
No response
master
.https://python-sqladmin.herokuapp.com/admin/ shows generic Server error heroku page.
No response
No response
No response
No response
No response
master
.get_converter()
in ModelConverterBase
selects QuerySelectMultipleField
instead of QuerySelectField
for a column with ONETOMANY
direction even if its uselist
is False
(i.e. the column is defined as one-to-one relationship).
If a scalar is desired where normally a list would be present, such as a bi-directional one-to-one relationship, set
relationship.uselist
to False.
Because of that, the following code tries to iterate over the non-iterable column data and fails with Internal Server Error in edit pages:
from sqlalchemy import Column, ForeignKey, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine(...)
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
address: "Address" = relationship(
"Address",
back_populates="user",
uselist=False, # indicates it is one-to-one relationship
)
class Address(Base):
__tablename__ = "address"
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("user.id"), unique=True, nullable=False)
user: User = relationship("User", back_populates="address")
Base.metadata.create_all(engine)
from fastapi import FastAPI
from sqladmin import Admin, ModelAdmin
app = FastAPI()
admin = Admin(app, engine)
class UserAdmin(ModelAdmin, model=User):
column_list = [User.id, User.address]
admin.register_model(UserAdmin)
No response
No response
Traceback (most recent call last):
...
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/templates/edit.html", line 18, in block 'content'
{{ field() }}
File "/home/myproject/.venv/lib/python3.9/site-packages/wtforms/fields/core.py", line 172, in __call__
return self.meta.render_field(self, kwargs)
File "/home/myproject/.venv/lib/python3.9/site-packages/wtforms/meta.py", line 64, in render_field
return field.widget(field, **render_kw)
File "/home/myproject/.venv/lib/python3.9/site-packages/wtforms/widgets/core.py", line 351, in __call__
for val, label, selected in field.iter_choices():
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/fields.py", line 411, in iter_choices
primary_keys = [str(inspect(m).identity[0]) for m in self.data]
TypeError: 'Address' object is not iterable
Here is a workaround for this issue:
class UserAdmin(ModelAdmin, model=User):
...
form_overrides = {
"address": QuerySelectField, # workaround for aminalaee/sqladmin#180
}
get_model_form()
receives only
parameter in Sequence
but ignores its order to build form fields.
attributes
should align to the order of only
if specified like:
attributes = []
names = only or mapper.attrs.keys()
for name in names:
if exclude and name in exclude:
continue
attributes.append((name, mapper.attrs[name]))
No response
No response
master
.The call self.pk_column.type.python_type
fails when the pk is a Postgres UUID field with a NotImplementedError
. Maybe this call can be replaced with something along the lines of
from sqlalchemy.dialects.postgresql import UUID
...
def coerce_to_pk_value(self, value):
if isinstance(self.pk_column.type, UUID):
return str(value)
return self.pk_column.type.python_type(value)
...
stmt = select(self.model).where(self.pk_column == self.coerce_to_pk_value(value))
Alternatively, if it's not desirable importing specific dialects such as Postgres, maybe we could pass a custom value coercion function to each admin model?
No response
No response
No response
No response
Python 3.10
No response
Originally posted by JonasKs February 16, 2022
Hi! This looks awesome, Iโm definitely going to test it out!
Since this support SQLAlchemy, will it also support SQLModel? ๐
As suggested by @JonasKs, I did test SQLAdmin with SQLModel but it needs a few tweaks to make it work.
I'll get to it after we have the minimum functionality like #24 done.
There is a UUID converter for sqlalchemy.dialects.postgresql.base.UUID
but sqlalchemy_utils.types.uuid.UUIDType
is missing.
Add sqlalchemy_utils.types.uuid.UUIDType
to the @converts
annotation for conv_PgUuid
.
No response
No response
I want to be able to show JSON column in detail page.
Could not find field converter for column questions (<class 'sqlalchemy.dialects.postgresql.json.JSON'>).
No response
No response
No response
Need to check SQLAlchemy V2 migration steps. As far as I can see we're using SQLAlchemy 1.4 features, It should be ready, but needs checking and fixing.
No response
eg how FastAPI-Admin can specify tabler icons https://tablericons.com/
No response
No response
master
.Thank you for this awesome repo. It saved me a lot of time.
I have faced a weird bug.
Here goes my model.
class UserAdmin(ModelAdmin, model=UserModel.User):
column_list = [UserModel.User.id, UserModel.User.last_name, UserModel.User.first_name, UserModel.User.email]
column_sortable_list = [UserModel.User.last_name,UserModel.User.first_name,UserModel.User.email]
column_labels = dict(id='ID',last_name='Last Name', first_name='First Name',email='Email Address')
It worked perfectly until I added custom_labels. Now when ever I click on the table header, it returns with an error saying "Model User has no attribute 'Email address' "
This should sort using original field name, not with the label.
No response
No response
No response
No response
No response
master
.I'm getting a 500 error when accessing details.
Load the view template.
500 error.
Exception.
INFO: 127.0.0.1:63769 - "GET /file/details/c09f63a4-7093-45f6-8498-17bbcd7e40e6 HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 372, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in call
return await self.app(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/fastapi/applications.py", line 269, in call
await super().call(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/applications.py", line 124, in call
await self.middleware_stack(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in call
raise exc
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in call
await self.app(scope, receive, _send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 93, in call
raise exc
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in call
await self.app(scope, receive, sender)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in call
raise e
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in call
await self.app(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/routing.py", line 670, in call
await route.handle(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/routing.py", line 418, in handle
await self.app(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/applications.py", line 124, in call
await self.middleware_stack(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in call
raise exc
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in call
await self.app(scope, receive, _send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 93, in call
raise exc
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in call
await self.app(scope, receive, sender)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/routing.py", line 670, in call
await route.handle(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/routing.py", line 266, in handle
await self.app(scope, receive, send)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/routing.py", line 65, in app
response = await func(request)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/application.py", line 286, in details
return self.templates.TemplateResponse(model_admin.details_template, context)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/templating.py", line 98, in TemplateResponse
return _TemplateResponse(
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/starlette/templating.py", line 37, in init
content = template.render(context)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/templates/details.html", line 1, in top-level template code
{% extends "layout.html" %}
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/templates/layout.html", line 1, in top-level template code
{% extends "base.html" %}
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/templates/base.html", line 15, in top-level template code
{% block body %}
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/templates/layout.html", line 49, in block 'body'
{% block content %} {% endblock %}
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/templates/details.html", line 29, in block 'content'
{{ model_admin.get_detail_value(model, attr) }}
File "/Users/theber/code/college-toolkit/.venv/lib/python3.9/site-packages/sqladmin/models.py", line 592, in _url_for_details_with_attr
pk = getattr(target, attr.mapper.primary_key[0].name)
AttributeError: 'NoneType' object has no attribute 'id'
MacOSX, Python3.9, 0.1.9
This is my models file:
# https://gist.github.com/gmolveau/7caeeefe637679005a7bb9ae1b5e421e
class GUID(TypeDecorator):
"""Platform-independent GUID type.
Uses PostgreSQL's UUID type, otherwise uses
CHAR(32), storing as stringified hex values.
"""
impl = CHAR
cache_ok = True
def load_dialect_impl(self, dialect):
if dialect.name == "postgresql":
return dialect.type_descriptor(UUID())
else:
return dialect.type_descriptor(CHAR(32))
def process_bind_param(self, value, dialect):
if value is None:
return value
elif dialect.name == "postgresql":
return str(value)
else:
if not isinstance(value, uuid.UUID):
return "%.32x" % uuid.UUID(value).int
else:
# hexstring
return "%.32x" % value.int
def _uuid_value(self, value):
if value is None:
return value
else:
if not isinstance(value, uuid.UUID):
value = uuid.UUID(value)
return value
def process_result_value(self, value, dialect):
return self._uuid_value(value)
def sort_key_function(self, value):
return self._uuid_value(value)
class ModelBase(Base):
__abstract__ = True
id = Column(GUID(), primary_key=True, default=lambda: str(uuid.uuid4()))
class File(ModelBase):
__tablename__ = "files"
name = Column(String(300), index=True)
file_id = Column(String(256), unique=True)
toolkit_id = Column(GUID(), ForeignKey("toolkits.id"), index=True)
toolkit = relationship("Toolkit", back_populates="files")
Hello. In my project I have a lot relationships with lazy="dynamic"
. But sqladmin don't supports it
I would like to see setting in config like load_lazys . If if is True load all relationships
No response
No response
master
.I am trying to update m2m field in form but i am getting error "sqlalchemy.exc.InvalidRequestError: Can't attach instance another instance with key is already present in this session"
No response
No response
No response
No response
Macos , python 3.9
No response
It is useful if we can configure default sort
and sortBy
in ModelAdmin
(e.g. sortBy="created_at"
and sort="desc"
for log tables).
class Log(Base):
__tablename__ = "logs"
id = Column(BigInteger, primary_key=True)
created_at = Column(DateTime)
class LogAdmin(ModelAdmin, model=Log):
sortBy = "created_at"
sort = "desc"
I think it is useful if there is a way to specify custom Statement
directly (like get_queryset
in django-admin) because it also adds functionality to optimize the query:
class LogAdmin(ModelAdmin, model=Log):
def get_statement(self, request):
...
Note that a pain point of Django's implementation is that get_queryset
is shared both in SELECT
and INSERT/UPDATE/DELETE
. We need a cleaner way to do it.
No response
master
.SQLModel does not store relationships data directly in attributes, so trying to use them like vanilla SQLAlchemy attributes like that
class ModelA(SQLModel, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)
class ModelB(SQLModel, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)
model_a: Optional[ModelA] = Relationship(sa_relationship=relationship("ModelA"))
class ModelBAdmin(ModelAdmin, model=ModelB):
column_list = [ModelB.model_a]
results in error:
AttributeError: type object 'ModelB' has no attribute 'model_a'
Trying to use attribute used by SQLModel does not work either:
class ModelBAdmin(ModelAdmin, model=ModelB):
column_list = [ModelB.__sqlmodel_relationships__["model_a"].sa_relationship]
error:
File "/usr/local/lib/python3.9/site-packages/sqladmin/models.py", line 590, in get_model_attr
assert isinstance(attr, (str, InstrumentedAttribute))
AssertionError
since what is checked in this assertion is sqlalchemy.orm.RelationshipProperty
I tried to work around that making some patch:
from typing import Union
from sqladmin.models import ModelAdmin
from sqlalchemy.orm import InstrumentedAttribute, RelationshipProperty, ColumnProperty
class ModelAdminWithSQLModelRelationships(ModelAdmin):
def get_model_attr(
self, attr: Union[str, InstrumentedAttribute, RelationshipProperty]
) -> Union[ColumnProperty, RelationshipProperty]:
if isinstance(attr, RelationshipProperty):
return attr
return super().get_model_attr(attr)
But it didn't work either
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 1214, in _fallback_getattr
raise AttributeError(key)
AttributeError: key
so I've added some utitlity function to workaround that:
def get_sqlmodel_relationship(model, name):
rel = model.__sqlmodel_relationships__[name].sa_relationship
rel.key = name
return rel
class ModelBAdmin(ModelAdminWithSQLModelRelationships, model=ModelB):
column_list = [get_sqlmodel_relationship(ModelB, "model_a")]
At this point app could complete startup and I could access admin panel, but when I tried to access list of ModelB
objects exception was raised:
sqlalchemy.exc.ArgumentError: Can't find property named "model_a" on mapped class ModelB->modelb in this Query.
so, at this point I gave up, it seems that it would need much more monkeypatching than I anticipated
No response
Possibility to use SQLModel Relationship in admin panel just like in vanilla SQLAlchemy
No response
No response
OS: Manjaro
Python: 3.9.7
SQLAlchemy: 1.4.36
No response
Hi.
I installed it with pip but i cant import "from sqladmin import Admin, ModelAdmin"... its not working.
Any help?
Thanks
Originally posted by Anton-Karpenko May 26, 2022
Hey, I am using sqlmodel to create models. I use the UUID type for the id columns.
class RandomModel(SQLModel, table=True):
id: uuid.UUID = Field(primary_key=True, index=True, nullable=False, default_factory=uuid.uuid4)
I added sqladmin to my project and I would like to create an instance within the admin panel. I cannot open create
page because of an error.
Exception: Could not find field converter for column id (<class 'sqlmodel.sql.sqltypes.GUID'>)
Can I apply a custom converter to it?
master
.get_converter()
in ModelConverterBase
expects that impl
class level attribute in column types inheriting TypeDecorator
has TypeEngine type, but it also accepts its instantiated value:
If the class level
impl
is not a callable (the unusual case), it will be assigned to the same instance attribute โas-isโ, ignoring those arguments passed to the constructor.
In that case, get_converter()
will raise AttributeError
with a message '...' object has no attribute '__name__'
.
By implementing the following code, http://[host]/admin/user/edit/1
will return Internal Server Error.
sqlalchemy_utc produces a custom UtcDateTime
type whose impl
attribute has DateTime(timezone=True)
instance instead of DateTime
class.
from sqlalchemy import Column, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utc import UtcDateTime, utcnow
Base = declarative_base()
engine = create_engine(...)
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
created_at = Column(UtcDateTime, default=utcnow())
Base.metadata.create_all(engine)
from fastapi import FastAPI
from sqladmin import Admin, ModelAdmin
app = FastAPI()
admin = Admin(app, engine)
class UserAdmin(ModelAdmin, model=User):
column_list = [User.id, User.created_at]
admin.register_model(UserAdmin)
No response
No response
Traceback (most recent call last):
...
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/application.py", line 312, in create
Form = await model_admin.scaffold_form()
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/models.py", line 834, in scaffold_form
return await get_model_form(
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/forms.py", line 415, in get_model_form
field = await converter.convert(
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/forms.py", line 232, in convert
converter = self.get_converter(model=model, prop=prop)
File "/home/myproject/.venv/lib/python3.9/site-packages/sqladmin/forms.py", line 113, in get_converter
if col_type.impl.__name__ in self._converters: # type: ignore
AttributeError: 'DateTime' object has no attribute '__name__'
No response
There doesn't seem to be an obvious way to register converter functions with @converts
or subclass ModelConverter
.
This might also be a bug where ModelConverterBase.get_converter
is unable to recognize TypeDecorator
types that extend a type that already has a converter.
Possibly utilizing a global registry for @converts
.
No response
Encountered while trying to create a ModelAdmin
for a SQLModel
(related to #57)
Exception: Could not find field converter for column name (<class 'sqlmodel.sql.sqltypes.AutoString'>).
where AutoString
extends String
EDIT:
Got it to work by setting the sa_column=
on the SQLModel field:
class MyModel(SQLModel):
# name: str = Field(..., index=True) # broken
name: str = Field(..., sa_column=Column(String(length=512))) # works
I believe the feature request still has value
Hello, great work ! :)
I would like to be able to add my own url paths below the root endpoint of the admin app.
For example I would like to be able to do a POST on the homepage (url "/")
Something that would look like this
@router.post("")
async def post_homepage(request: Request):
logger.warning("post !!")
return templates.TemplateResponse("index.html", {"request": request})
From what I understand it is not possible to access or modify the sub app
Neither is it possible to mount another sub application on the same endpoint (because routes would conflict)
It would be great if we could use the default routes but also add some and override existing routes
from backoffice import homepage
admin = Admin(app, create_engine(Settings().db_uri), base_url="/backoffice")
admin.include_router(homepage.router)
routes could be added before the existing routes to have priority
No response
No response
I need a QuerySelectField
alternative that can fetch a limited number of items on demand like autocomplete_fields in Django admin, instead of loading entire records of the related (possibly very huge) table when rendering the page.
No response
No response
No response
In the list page we have a select field: Show [10,25, 50, 100]
like that.
We need to change list pagination size by switching the size field.
This needs to send query like /admin/users/list?page_size=X
It is useful if the detail page has an edit button.
I think the edit button for each record in the list view can be removed if the detail page has it. The small icon in the list is a bit tiny and prone to misclick.
No response
No response
It is useful if ModelAdmin
has a setting like form_readonly_columns
that specifies columns the users can not edit.
No response
No response
The author of wtforms recommends just remove the "read-only" field from the input before storing them to the DB.
Currently the values for datetime columns seem to be rendered as ISO-8601 with millisecond precision which is unnecessary (eg 2022-04-04 22:43:30.027151
)
It'd be great if we had a way to pass some sort of custom formatter, ideally a callable that takes the DB value and returns the value that should be passed to the renderer.
No response
No response
master
.I have model with enum. When I open edit view, none of the options in the html have the selected attribute.
class CompanyPermissionEnum(enum.Enum):
project_create = "project_create"
project_read = "project_read"
project_update = "project_update"
class CompanyUserPermission(Base):
...
permission = Column(
Enum(CompanyPermissionEnum, name="company_permission"),
nullable=False,
)
No response
No response
No response
according to https://stackoverflow.com/a/51858425 I have fixed like this
def coerce_for_enum(enum):
def coerce(name):
if isinstance(name, enum):
return name
try:
return enum[name]
except KeyError:
raise ValueError(name)
return coerce
class CustomModelConverter(ModelConverter):
@converts("Enum")
def conv_Enum(
self, column: Column, field_args: dict, **kwargs: Any
) -> Field:
field_args["choices"] = [(e, e) for e in column.type.enums]
return SelectField(
**field_args,
coerce=coerce_for_enum(column.type.enum_class),
)
Add auto link in relationship. As example: https://python-sqladmin.herokuapp.com/admin/address/details/1 to get user I need to go to table users, find user(no search). Please make user_id a link to users
user_id is a link to users
No response
No response
I want to set up a custom objects_list for the QuerySelectField field, but I can't because this property is overridden in the ModelConverter.convert method.
No response
No response
No response
master
.Traceback during open 'Create' page (url for example): http://127.0.0.1:8000/admin/user/create
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/starlette/templating.py", line 37, in init
content = template.render(context)
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqladmin/templates/create.html", line 1, in top-level template code
{% extends "layout.html" %}
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqladmin/templates/layout.html", line 1, in top-level template code
{% extends "base.html" %}
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqladmin/templates/base.html", line 15, in top-level template code
{% block body %}
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqladmin/templates/layout.html", line 49, in block 'body'
{% block content %} {% endblock %}
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqladmin/templates/create.html", line 18, in block 'content'
{{ field() }}
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/wtforms/fields/core.py", line 172, in call
return self.meta.render_field(self, kwargs)
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/wtforms/meta.py", line 64, in render_field
return field.widget(field, **render_kw)
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/wtforms/widgets/core.py", line 174, in call
kwargs["value"] = field._value()
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/wtforms/fields/datetime.py", line 36, in _value
return self.data and self.data.strftime(self.format[0]) or ""
File "/Users/iuliia_volkova2/Library/Caches/pypoetry/virtualenvs/admin-panel-service-Ji2bEy0B-py3.7/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 582, in bool
raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined
I think something in model cause in issue - I send the sample
Also we use async SQLAlchemy engine. I will be glad if you will do some input where to dig or what can be a reason of the problem.
Create form open correctly without issues.
Impossible to open Create form
No response
SQLAdmin == 0.1.9
SQLAlchemy == 1.4.37
No response
Right now the pagination only shows the current page plus previous and next.
It would be great to always have 7 pages shown (if applicable) and show previous and next pages.
master
.I used SQLAdmin
in my personal project(That's awesome ๐ฅณ), But the datetime field need to enter manually:
Maybe choose from panel is better:
No response
No response
No response
No response
os: mac
python: 3.9
sqladmin: lastest
No response
master
.The details page fails to render the list value formatted by column_formatters
and column_formatters_detail
because the following template tries to pass it to _url_for_details()
instead of the original model value.
sqladmin/sqladmin/templates/details.html
Lines 24 to 26 in 83d8d25
from typing import List
from sqlalchemy import Column, ForeignKey, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine(...)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
addresses: List["Address"] = relationship("Address", back_populates="user")
class Address(Base):
__tablename__ = "addresses"
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
user: User = relationship("User", back_populates="addresses")
Base.metadata.create_all(engine)
from fastapi import FastAPI
from sqladmin import Admin, ModelAdmin
app = FastAPI()
admin = Admin(app, engine)
class UserAdmin(ModelAdmin, model=User):
column_list = [User.id, User.address]
column_formatters = {
User.addresses: lambda m, a: [a.id for a in m.addresses],
}
admin.register_model(UserAdmin)
No response
No response
File "/myproject/.venv/lib/python3.9/site-packages/sqladmin/templates/details.html", line 25, in block 'content'
<a href="{{ model_admin._url_for_details(value) }}">({{ value }})</a>
File "/myproject/.venv/lib/python3.9/site-packages/sqladmin/models.py", line 567, in _url_for_details
pk = getattr(obj, inspect(obj).mapper.primary_key[0].name)
File "/myproject/.venv/lib/python3.9/site-packages/sqlalchemy/inspection.py", line 71, in inspect
raise exc.NoInspectionAvailable(
sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'str'>
No response
I am trying to emulate all the functionality of a Flask-Admin panel I made using SQLAdmin. The Flask website I'm attempting to emulate is open source and available here. It is able to be deployed in "demo" mode to Heroku so anyone can run it. (set FLASK_ENV=demo
as you deploy it).
So far, I am running into an issue with complicated lazy relationships. Take the following SQLModel as an example:
This is a SQLModel with lots of complicated relationships at the bottom, but these relationships do not need to be manually defined in the admin panel. In the case of latest_prediction
it's resolved via max(timestamp)
. In the case of all_predictions
, it is a many-to-one relationship that is resolved through an associative entity (named Reach
).
In Flask-Admin, I would work around this by explicitly defining form_columns
and excluding these complicated fields. And for Flask-Admin, this is what I get for my Boathouse
entity type:
But due to lack of a form_columns
, I cannot make this happen in SQLAdmin. It is forcing me to include these columns, which means I effectively cannot use both SQLAdmin and these complicated fields at the same time:
Flask-Admin has a concept called form_columns
for its ModelView
class. The form_columns
attribute controls which columns that WTForms creates fields for.
This is a good catchall solution for many problems because it lets users avoid any issues relating to fields that do not need to be assigned as part of the initialization of an object (e.g. optional fields, fields with defaults, complicated relationships, and more).
Flask-Admin implements form_columns
here, primarily: https://github.com/flask-admin/flask-admin/blob/7cff9c742d44d42a8d3495c73a6d71381c796396/flask_admin/contrib/sqla/form.py#L94
Right now, the function sqladmin.forms.get_model_form
can handle inclusion or exclusion of fields. However, this functionality is not used. So the function would need to be passed a form_columns
, or similar, from the ModelAdmin object.
This should not be too hard to implement-- just add form_columns
to the ModelAdmin class (form_columns
is adherent to the Flask-Admin API and is thus preferrable, albeit another naming such as form_column_list
would be acceptable if deviations are allowed), and have that be passed through the scaffold_form()
method.
No response
No response
I want to be able to use model types provided by sqlalchemy_utils such as EmailType, IPAddressType, and UUIDType.
I would like the admin page to work without crashing when they are used (just treating them all as strings would work fine for me).
I could convert them all to strings in my model, but that would take away a lot of functionality.
No response
When using BigIntegers in sqlalchemy together with "with_variant", e.g. Column(BigInteger().with_variant(Integer, "sqlite"))
the error "Could not find field converter for column id (<class 'sqlalchemy.sql.type_api.Variant'>)" is thrown.
No response
Using form_overrides seems to work fine as workaround however native support would be much appreciated :)
No response
I would really like to see some screenshots in the documentation similar to Fastapi Admin
This will help you better understand what the admin panel is like without downloading and importing the library.
No response
No response
No response
I'm writing custom formatters:
class AddressAdmin(ModelAdmin, model=Address):
...
_formatters = {
Address.user: lambda m, a: formatters.format_user(m.user, a),
}
column_formatters = _formatters
column_formatters_detail = _formatters
but accessing its attribute like m.user
everytime in the format function is a bit verbose and error prone. I'd like to use get_attr_value
method implemented in ModelAdmin
.
No response
No response
No response
master
.The form adds the required
attribute to its checkbox
input when the corresponding Boolean
column is not nullable
, but in this situation, the browser never accepts a false value due to its configured validation.
(It says "Please check this box if you want to proceed." in Japanese)
from sqlalchemy import Boolean, Column, ForeignKey, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine(...)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
is_active = Column(Boolean, nullable=False, default=False)
Base.metadata.create_all(engine)
from fastapi import FastAPI
from sqladmin import Admin, ModelAdmin
app = FastAPI()
admin = Admin(app, engine)
class UserAdmin(ModelAdmin, model=User):
column_list = [User.id, User.is_active]
admin.register_model(UserAdmin)
No response
No response
No response
No response
No response
No response
No response
No response
I want to be ablet to add new users in batch, but I didn't find such a feature
No response
No response
No response
Right now we have List/Create/Detail/Delete.
Next one will be a simple Edit page.
There are:
class JSONField(fields.TextAreaField):
Necessary:
class JSONField(fields.FileField):
In the web forms I have configured https://accent-starlette.github.io/starlette-files/handling_files/
file = sa.Column(FileType.as_mutable(sa.JSON), nullable=True)
views.py
The result is excellent
In the admin area of the coma
Alternative solution: I have not found.
Now the json field is only for viewing and printing. Automatic generation is needed.
Originally posted by javtau February 19, 2022
Hi, this is so great,
Are you thinking on implement the multiple pk support for foreign primary keys like flask Admin?
It'd be great to expose the middleware
and debug
parameters to pass to the Starlette admin app. This would allow, for example, to create a middleware that checks for an "admin" session cookie and redirect the user in case the cookie doesn't exist. The debug option is useful when developing.
No response
No response
No response
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.