@@ -477,15 +477,14 @@ class UserAdmin(TortoiseModelAdmin):
477477 list_display_links = (" id" , " username" )
478478 list_filter = (" id" , " username" , " is_superuser" , " is_active" )
479479 search_fields = (" username" ,)
480- formfield_overrides = { # noqa: RUF012
480+ formfield_overrides: tp.Any = { # noqa: RUF012
481481 " username" : (WidgetType.SlugInput, {" required" : True }),
482482 " password" : (WidgetType.PasswordInput, {" passwordModalForm" : True }),
483483 " avatar_url" : (
484- WidgetType.Upload ,
484+ WidgetType.UploadImage ,
485485 {
486486 " required" : False ,
487- # Disable crop image for upload field
488- # "disableCropImage": True,
487+ # "disableCropImage": True, # optional: disable image cropping
489488 },
490489 ),
491490 }
@@ -505,10 +504,9 @@ class UserAdmin(TortoiseModelAdmin):
505504 user.hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
506505 await user.save(update_fields = (" hash_password" ,))
507506
508- async def orm_save_upload_field (self , obj : tp.Any, field : str , base64 : str ) -> None :
509- # convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
510- setattr (obj, field, base64)
511- await obj.save(update_fields = (field,))
507+ async def upload_file (self , obj : tp.Any, field_name : str , file_name : str , file_content : bytes ) -> str :
508+ # save file to media directory or s3/filestorage, then return the file url
509+ return f " /media/ { file_name} "
512510
513511```
514512
@@ -531,6 +529,8 @@ class UserAdmin(TortoiseModelAdmin):
531529
532530
533531``` python
532+ import typing as tp
533+
534534from django.db import models
535535
536536from fastadmin import DjangoModelAdmin, register
@@ -541,6 +541,7 @@ class User(models.Model):
541541 hash_password = models.CharField(max_length = 255 )
542542 is_superuser = models.BooleanField(default = False )
543543 is_active = models.BooleanField(default = False )
544+ avatar_url = models.ImageField(null = True )
544545
545546 def __str__ (self ):
546547 return self .username
@@ -562,6 +563,10 @@ class UserAdmin(DjangoModelAdmin):
562563 return None
563564 return obj.id
564565
566+ def upload_file (self , obj : tp.Any, field_name : str , file_name : str , file_content : bytes ) -> str : # type: ignore [ override ]
567+ # save file to media directory or s3/filestorage, then return the file url
568+ return f " /media/ { file_name} "
569+
565570```
566571
567572
@@ -591,7 +596,7 @@ from sqlalchemy import Boolean, Integer, String, Text, select, update
591596from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
592597from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
593598
594- from fastadmin import SqlAlchemyModelAdmin, register
599+ from fastadmin import SqlAlchemyModelAdmin, WidgetType, register
595600
596601sqlalchemy_engine = create_async_engine(
597602 " sqlite+aiosqlite:///:memory:" ,
@@ -625,6 +630,9 @@ class UserAdmin(SqlAlchemyModelAdmin):
625630 list_display_links = (" id" , " username" )
626631 list_filter = (" id" , " username" , " is_superuser" , " is_active" )
627632 search_fields = (" username" ,)
633+ formfield_overrides = { # noqa: RUF012
634+ " avatar_url" : (WidgetType.UploadImage, {" required" : False }),
635+ }
628636
629637 async def authenticate (self , username : str , password : str ) -> uuid.UUID | int | None :
630638 sessionmaker = self .get_sessionmaker()
@@ -646,13 +654,9 @@ class UserAdmin(SqlAlchemyModelAdmin):
646654 await session.execute(query)
647655 await session.commit()
648656
649- async def orm_save_upload_field (self , obj : tp.Any, field : str , base64 : str ) -> None :
650- sessionmaker = self .get_sessionmaker()
651- async with sessionmaker() as session:
652- # convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
653- query = update(self .model_cls).where(User.id.in_([obj.id])).values(** {field: base64})
654- await session.execute(query)
655- await session.commit()
657+ async def upload_file (self , obj : tp.Any, field_name : str , file_name : str , file_content : bytes ) -> str :
658+ # save file to media directory or s3/filestorage, then return the file url
659+ return f " /media/ { file_name} "
656660
657661```
658662
@@ -681,7 +685,7 @@ import uuid
681685import bcrypt
682686from pony.orm import Database, LongStr, Optional, PrimaryKey, Required, commit, db_session
683687
684- from fastadmin import PonyORMModelAdmin, register
688+ from fastadmin import PonyORMModelAdmin, WidgetType, register
685689
686690db = Database()
687691db.bind(provider = " sqlite" , filename = " :memory:" , create_db = True )
@@ -707,6 +711,9 @@ class UserAdmin(PonyORMModelAdmin):
707711 list_display_links = (" id" , " username" )
708712 list_filter = (" id" , " username" , " is_superuser" , " is_active" )
709713 search_fields = (" username" ,)
714+ formfield_overrides = { # noqa: RUF012
715+ " avatar_url" : (WidgetType.UploadImage, {" required" : False }),
716+ }
710717
711718 @db_session
712719 def authenticate (self , username : str , password : str ) -> uuid.UUID | int | None :
@@ -726,14 +733,9 @@ class UserAdmin(PonyORMModelAdmin):
726733 obj.hash_password = hash_password
727734 commit()
728735
729- @db_session
730- def orm_save_upload_field (self , obj : tp.Any, field : str , base64 : str ) -> None :
731- obj = next ((f for f in self .model_cls.select(id = obj.id)), None )
732- if not obj:
733- return
734- # convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
735- setattr (obj, field, base64)
736- commit()
736+ def upload_file (self , obj : tp.Any, field_name : str , file_name : str , file_content : bytes ) -> str : # type: ignore [ override ]
737+ # save file to media directory or s3/filestorage, then return the file url
738+ return f " /media/ { file_name} "
737739
738740```
739741
0 commit comments