Package: pynecone-admin
pynecone-adminA generic CRUDModelboilerplate for the python-based full stackpyneconeframework.Simple, extendable login state and redirect helpersadd_crud_routesmethod adds Create, Update, Read, Delete
capabilities to specified modelsExampleSee./example/example/example.py.UsageIncludepynecone-adminin your projectrequirements.txt.Callpynecone_admin.add_crud_routes(app=app, obs=[pynecone_admin.User, Widget], prefix="/crud")pc init && pc runAccess models at/crud.APIAuthenticationPer-page authentication is provided bypynecone_admin.login_required. It can be used
as a decorator on a page function.@pynecone_admin.login_required(State)defpage():returnpc.text("You are logged in as ",State.authenticated_user_id)A customlogin_componentcan be passed as a parameter, seepynecone_admin.auth.default_login_componentas an example for how to customize
the logic. A custom component must callState._login(self, user_id)to
authenticate a session for the givenuser_id.If no users exist in the database, the default login component will create the
first user to login as an admin.By default, onlyauthenticated_user_idis provided, if access to the provided User model is needed, implement a small helper in the local appState(from the example):classState(pc.State):@pc.cached_vardefauthenticated_user(self)->User:ifself.authenticated_user_id>=0:withpc.session()assession:ifuser:=session.exec(User.select.where(User.id==self.authenticated_user_id),).one_or_none():returnuserreturnUser()Persistent TokenUsing thelogin_requiredfunction will automatically augment the passedStateclass with
additional variables and functionality:current_token: a persistent (localStorage-backed) value that identifies
the client browser. This value is updated by thePersistentToken.on_changeevent handler defined inside thelogin_requiredfunction.authenticated_user_id: the user_id associated with a non-expired auth session
matching the state'scurrent_token. If no such session exists,-1.do_logout: event handler that disassociates the state'scurrent_tokenwith any valid auth session_login: backend-only function that associates the state'scurrent_tokenwith the givenuser_id(values less than 0 are ignored).
To implement a custom login method, the code must somehow callState._login(self, user_id)after properly authenticating the user_id.CRUD - Create Read Update DeleteThe primary entry point ispynecone_admin.add_crud_routes. Two arguments are required:app: pass an instance of yourpc.Appobjs: pass a sequence ofpc.Modelclasses that should be available for editingAdditional arguments are available to customize the crud pages:form_component: function called to render the object create/edit form, defaults topynecone_admin.crud.default_form_component.field_component: function called to render a single field in the form, defaults topynecone_admin.crud.default_field_component.login_component: function called to render the user login form, defaults to to no login form. If protected access is required, passpynecone_admin.default_login_componentor another custom login component.can_access_resource: access control function accepting state instance as first parameter, defaults to open access if not presentprefix: route prefix for admin operations, defaults to/crudSupported Field TypesSeepynecone_admin.crud.default_field_component.Simple Typesstr,float: standardpc.inputint:pc.number_inputbool:pc.check_boxSpecial Typesenum.Enum:pc.selectdrop down boxdatetime.datetime:pc.inputwithtype_="datetime-local", which renders a date picker on modern
browsers.uuid.UUID: standardpc.inputwith a "random" button that sets the value to"random"(handled inset_subfield).Why are these types special? Because pynecone cannot handle them out of the box,
although they work fine via sqlmodel / sqlalchemy. The solution is to convert
them to serializable types by overriding thedict()method of the model:from__future__importannotationsimportdatetimeimportenumimportuuidimportpyneconeaspcimportpynecone_adminimportsqlmodelclassTokenStatus(enum.Enum):ACTIVE="active"DISABLED="disabled"classTokenOwner(pc.Model,table=True):user_id:inttoken_uuid:uuid.UUIDcreated:datetime.datetime=sqlmodel.Field(sa_column=sqlmodel.Column(sqlmodel.DateTime(timezone=True),server_default=sqlmodel.func.now(),),)status:TokenStatuscomment:str|None=Nonedefdict(self,*args,**kwargs):d=super().dict(*args,**kwargs)d["token_uuid"]=str(self.token_uuid)ifself.token_uuidelseNoned["created"]=(self.created.replace(microsecond=0).isoformat()ifself.createdelseNone)d["status"]=self.status.nameifself.statuselseNonereturndclassState(pc.State):passapp=pc.App(state=State)pynecone_admin.add_crud_routes(app,[TokenOwner],prefix="/")app.compile()The save field handler,set_subfield, currently handles deserializing these types as
special cases.Customizing Per-Model Behaviorpynecone-adminrespects specially named hook methods or attributes attached to
Models, to allow behavioral customization:__pynecone_admin_fields__: Sequence[str]: names of fields to include in the
table and editor form. Allows for rendering a subset of available fields. Default
uses all fields defined on the model.__pynecone_admin_load_object_hook__: method called on each instance
after it is loaded from the database for editing.__pynecone_admin_load_row_hook__: method called on each instance after it is loaded
from the database during enumeration (for the table).__pynecone_admin_filter_where_hook__: classmethod accepting a string,filter_value, that returns
an expression passable to sqlmodelwhere()selector to filter the table query
based on a user-supplied value. Default filter hook casts all columns as string and performs
a wildcard match (LIKE %{filter_value}%) on each.__pynecone_admin_save_object_hook__: method called on each instance
before it is persisted to the database. The includedUsermodel, implements this
hook to hash password strings that don't look like valid hashes before saving.__pynecone_admin_delete_object_hook__: method called on each instance
before it is deleted from the database.Changelogv0.1a0 - 2023-05-31Alpha Release