access and elevations

This commit is contained in:
Jun-te Kim 2025-06-20 16:05:01 +00:00
parent 24d2550cb8
commit db1635ce4c
8 changed files with 411 additions and 28 deletions

View file

@ -3,6 +3,7 @@
"python.REPL.sendToNativeREPL": true,
"notebook.output.scrolling": true,
"terminal.integrated.defaultProfile.linux": "bash",
"editor.rulers": [79],
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash"

View file

@ -0,0 +1,132 @@
"""add elevation
Revision ID: 544f060f1eb8
Revises: 881142a89edb
Create Date: 2025-06-19 09:54:43.770068
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '544f060f1eb8'
down_revision: Union[str, None] = '881142a89edb'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('secondaryheating')
op.drop_table('heating_from_condition_report')
op.drop_table('generalconditionheatingsystem')
op.drop_table('conditionreport')
op.drop_table('mainheatingtwo')
op.drop_table('conservatoryoroutbuilding')
op.drop_table('mainheatingone')
op.drop_table('elevation')
op.drop_table('generalinformation')
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('elevation',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('protected_conservatory_or_aonb', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('material_type', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('are_there_any_visible_signs_of_existing_wall_insulation', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('does_the_existing_ground_level_on_any_elevation_bridge_the_dpc', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='elevation_pkey')
)
op.create_table('mainheatingone',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('as_defined_by', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('fuel', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('type', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='mainheatingone_pkey')
)
op.create_table('conservatoryoroutbuilding',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('is_there_a_conservatory', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_there_a_cellar_present', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_there_an_outbuilding', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='conservatoryoroutbuilding_pkey')
)
op.create_table('mainheatingtwo',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('is_there_a_main_heating_two', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='mainheatingtwo_pkey')
)
op.create_table('conditionreport',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('project_site_name', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('property_reference_code', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('property_address', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('postcode', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('general_information_id', sa.UUID(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['general_information_id'], ['generalinformation.id'], name='conditionreport_general_information_id_fkey'),
sa.PrimaryKeyConstraint('id', name='conditionreport_pkey')
)
op.create_table('generalconditionheatingsystem',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('is_the_heating_system_in_working_order', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('does_the_occupant_have_a_smart_meter', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_there_any_smart_monitoring_devices', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_the_gas_and_electricity_meters_accessible', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('dual_or_single_electric_meter', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='generalconditionheatingsystem_pkey')
)
op.create_table('heating_from_condition_report',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('room_stat_in_temperature_in_celsius', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('room_stat_location', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('is_the_heating_pattern_known', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='heating_from_condition_report_pkey')
)
op.create_table('externalelevation',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('structural_defects_of_elevation', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('does_any_structural_defect_need_resolving_before_retrofit', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_there_any_signs_of_water_penetration_caused_by_failed_rainw', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_there_any_visible_signs_of_movement', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_there_any_visible_signs_of_cracking_to_the_existing_externa', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='externalelevation_pkey')
)
op.create_table('generalinformation',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('assessor_details_id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('inspection_and_project_id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('the_property_id', sa.UUID(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['assessor_details_id'], ['assessordetails.id'], name='generalinformation_assessor_details_id_fkey'),
sa.ForeignKeyConstraint(['inspection_and_project_id'], ['inspectionandproject.id'], name='generalinformation_inspection_and_project_id_fkey'),
sa.ForeignKeyConstraint(['the_property_id'], ['theproperty.id'], name='generalinformation_the_property_id_fkey'),
sa.PrimaryKeyConstraint('id', name='generalinformation_pkey')
)
op.create_table('secondaryheating',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('is_there_a_secondary_heating', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('fuel', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('electric_heating_type', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.Column('gas_heating_type', sa.VARCHAR(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='secondaryheating_pkey')
)
op.create_table('propertyaccess',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('are_there_any_road_restriction_in_the_locality', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_on_street_parking_available', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('are_there_any_overhead_wires_or_cables', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_the_access_gated', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_there_restricted_space_for_contractors_to_access_the_wall_ar', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_there_restricted_space_for_contractors_to_access_the_roof_ar', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_there_more_than_1_point_5_meters_in_width_to_fence_or_neighb', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_access_to_the_rear_provided_by_use_of_a_ginnel', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.Column('is_access_to_the_rear_provided_by_use_of_a_secured_alleyway', sa.BOOLEAN(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='propertyaccess_pkey')
)
# ### end Alembic commands ###

View file

@ -0,0 +1,38 @@
"""is there an fourth external elevation
Revision ID: c373a9a083f1
Revises: ceffde5b28ac
Create Date: 2025-06-20 15:08:31.752580
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'c373a9a083f1'
down_revision: Union[str, None] = 'ceffde5b28ac'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('externalelevationgabletwo', sa.Column('is_there_a_fourth_external_elevation', sa.Boolean(), nullable=False))
op.drop_column('externalelevationgabletwo', 'do_all_answers_for_the_front_elevation_apply_to_this_wall')
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('externalelevationgabletwo', sa.Column('do_all_answers_for_the_front_elevation_apply_to_this_wall', sa.BOOLEAN(), autoincrement=False, nullable=False))
op.drop_column('externalelevationgabletwo', 'is_there_a_fourth_external_elevation')
op.add_column('externalelevation', sa.Column('are_there_any_visible_signs_of_cracking_to_the_existing_externa', sa.BOOLEAN(), autoincrement=False, nullable=False))
op.add_column('externalelevation', sa.Column('any_signs_of_water_penetration_caused_by_failed_rainwater_goods', sa.BOOLEAN(), autoincrement=False, nullable=False))
op.drop_column('externalelevation', 'are_there_any_visible_signs_of_cracking_to_the_existing_external_finish')
op.drop_column('externalelevation', 'any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework')
# ### end Alembic commands ###

View file

@ -0,0 +1,43 @@
"""added new column
Revision ID: ceffde5b28ac
Revises: 544f060f1eb8
Create Date: 2025-06-19 10:23:37.567361
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision: str = 'ceffde5b28ac'
down_revision: Union[str, None] = '544f060f1eb8'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('elevation',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('protected_conservatory_or_aonb', sa.Boolean(), nullable=False),
sa.Column('material_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('visible_signs_of_existing_wall_insulation', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('ground_level_bridge_the_dpc', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.add_column('elevationinfo', sa.Column('elevation_id', sa.Uuid(), nullable=True))
op.create_foreign_key(None, 'elevationinfo', 'elevation', ['elevation_id'], ['id'])
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'elevationinfo', type_='foreignkey')
op.drop_column('elevationinfo', 'elevation_id')
op.drop_table('elevation')
# ### end Alembic commands ###

View file

@ -3,9 +3,7 @@ from sqlmodel import SQLModel, Field, Relationship
from typing import Optional, List
import uuid
from datetime import datetime
class BaseModel(SQLModel):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
from etl.models.topLevel import BaseModel, Documents
class AssessorDetails(BaseModel, table=True):
assessor_name_and_id: str
@ -25,7 +23,7 @@ class TheProperty(BaseModel, table=True):
orientation_in_degrees_front_elevation: str
exposure_zone: str
main_wall_construction: str
class ElevationInfo(BaseModel, table=True):
elevation_type: str
cavity_wall_depth: str
@ -51,3 +49,73 @@ class Elevation(BaseModel, table=True):
ground_level_bridge_the_dpc: bool
info: List["ElevationInfo"] = Relationship(back_populates="elevation_table")
class GeneralInformation(BaseModel, table=True):
assessor_detail_id: uuid.UUID = Field(foreign_key="assessordetails.id")
inspection_and_project_id: uuid.UUID = Field(foreign_key="inspectionandproject.id")
the_property_id: uuid.UUID = Field(foreign_key="theproperty.id")
main_elevation_id: uuid.UUID = Field(foreign_key="mainelevation.id")
elevations_id: uuid.UUID = Field(foreign_key="elevation.id")
assessor_details: AssessorDetails = Relationship()
inspection_and_project: InspectionAndProject = Relationship()
the_property: TheProperty = Relationship()
main_elevation: MainElevation = Relationship()
elevations: Elevation = Relationship()
class PropertyAccess(BaseModel, table=True):
are_there_any_road_restriction_in_the_locality: bool
is_on_street_parking_available: bool
are_there_any_overhead_wires_or_cables: bool
is_the_access_gated: bool
is_there_restricted_space_for_contractors_to_access_the_wall_area: bool
is_there_restricted_space_for_contractors_to_access_the_roof_area: bool
more_than_1_5_meters_in_width_to_fence_or__along_the_full_gable_elevation: bool
is_access_to_the_rear_provided_by_use_of_a_ginnel: bool
is_access_to_the_rear_provided_by_use_of_a_secured_alleyway: bool
class ExternalElevation(BaseModel, table=True):
structural_defects_of_elevation: str
does_any_structural_defect_need_resolving_before_retrofit: bool
any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework: bool
are_there_any_visible_signs_of_movement: bool
are_there_any_visible_signs_of_cracking_to_the_existing_external_finish: bool
class ExternalElevationFront(BaseModel, table=True):
external_elevation_id: uuid.UUID = Field(foreign_key="externalelevation.id")
external_elevation: ExternalElevation = Relationship()
class ExternalElevationRear(BaseModel, table=True):
do_all_answers_for_the_front_elevation_apply_to_this_wall: bool
external_elevation_id: Optional[uuid.UUID] = Field(foreign_key="externalelevation.id")
external_elevation: Optional[ExternalElevation] = Relationship()
class ExternalElevationGableOne(BaseModel, table=True):
do_all_answers_for_the_front_elevation_apply_to_this_wall: bool
external_elevation_id: Optional[uuid.UUID] = Field(foreign_key="externalelevation.id")
external_elevation: Optional[ExternalElevation] = Relationship()
class ExternalElevationGableTwo(BaseModel, table=True):
is_there_a_fourth_external_elevation: bool
external_elevation_id: Optional[uuid.UUID] = Field(foreign_key="externalelevation.id")
class ConservatoryOrOutbuilding(BaseModel, table=True):
is_there_a_conservatory: bool
is_there_a_cellar_present: bool
is_there_an_outbuilding: bool
class AccessAndElevations(BaseModel, table=True):
property_access_id: uuid.UUID = Field(foreign_key="propertyaccess.id")
external_elevation_front_id: uuid.UUID = Field(foreign_key="externalelevationfront.id")
external_elevation_back_id: uuid.UUID = Field(foreign_key="externalelevationrear.id")
external_elevation_gable_one_id: uuid.UUID = Field(foreign_key="externalelevationgableone.id")
external_elevation_gable_two_id: uuid.UUID = Field(foreign_key="externalelevationgabletwo.id")
conservatory_or_out_building_id: uuid.UUID = Field(foreign_key="conservatoryoroutbuilding.id")
property_access: PropertyAccess = Relationship()
external_elevation_front: ExternalElevationFront = Relationship()
external_elevation_back: ExternalElevationRear = Relationship()
external_elevation_gable_one: ExternalElevationGableOne = Relationship()
external_elevation_gable_two: ExternalElevationGableTwo = Relationship()
conservatory_or_out_building: ConservatoryOrOutbuilding = Relationship()

View file

@ -18,6 +18,15 @@ from etl.models.conditionReport import (
TheProperty, ElevationInfo,
MainElevation,
Elevation,
GeneralInformation,
PropertyAccess,
ExternalElevation,
ExternalElevationFront,
ExternalElevationRear,
ExternalElevationGableOne,
ExternalElevationGableTwo,
ConservatoryOrOutbuilding,
AccessAndElevations,
)
from etl.models.topLevel import(
@ -50,7 +59,7 @@ class surveyedDataProcessor():
def load_condition_report(self, db_session):
# My task to complete load
# [] general_information = self.get_section_1()
# [x] general_information = self.get_section_1()
# [] access_and_elevations = self.get_section_2()
# [] rooms = self.get_section_3()
# [] heating_system = self.get_section_4()
@ -69,22 +78,104 @@ class surveyedDataProcessor():
# occupancy_assessment=occupant_assessment,
# )
#
# Load General Information:
#
# assessor_details = self.get_assessor_details()
# inspection_and_project = self.get_inspection_and_project()
# the_property = self.get_the_property()
# main_elevation = self.get_main_elevation()
# elevations = self.get_all_elevations()
# return GeneralInformation(
# assessor_details=assessor_details,
# inspection_and_project=inspection_and_project,
# the_property=the_property,
# main_elevation=main_elevation,
# elevations=elevations
# Load Assessor Information:
# return AccessAndElevations(
# property_access=pa,
# external_elevation_front=front,
# external_elevation_back=back,
# external_elevation_gable_one=one,
# external_elevation_gable_two=two,
# conservatory_or_out_building=co,
# )
self.load_general_information_from_condition_report(db_session)
general_information = self.load_general_information_from_condition_report(db_session)
_ = self.load_access_and_elevations_from_condition_report(db_session)
pprint(_)
def load_access_and_elevations_from_condition_report(self, db_session):
pa = self.get_attribute_and_load(
self.condition_report.master_obj.access_and_elevations,
"property_access",
PropertyAccess,
db_session=db_session,
additional_fields={
"more_than_1_5_meters_in_width_to_fence_or__along_the_full_gable_elevation": self.condition_report.master_obj.access_and_elevations.property_access.is_there_more_than_1_point_5_meters_in_width_to_fence_or_neighbouring_boundary_along_the_full_gable_elevation
}
)
print(f"hello junte {pa.id}")
# Front
obj = self.condition_report.master_obj.access_and_elevations.external_elevation_front
external_elevation = self.get_attribute_and_load(
obj,
"external_elevation",
ExternalElevation,
db_session=db_session,
additional_fields={
"any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework": obj.external_elevation.are_there_any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework,
},
)
external_elevation_front = self.upsert_record(
db_session=db_session,
model_class=ExternalElevationFront,
data_dict={
"external_elevation_id": external_elevation.id
},
lookup_field=None,
)
def external_elevation_load_for_side(obj, pydanticModel, different="do_all_answers_for_the_front_elevation_apply_to_this_wall"):
external_elevation = None
data_dict={
different: getattr(obj, different),
}
if getattr(obj, different) is False:
if getattr(obj, "external_elevation") is not None:
external_elevation = self.get_attribute_and_load(
obj,
"external_elevation",
ExternalElevation,
db_session=db_session,
additional_fields={
"any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework": obj.external_elevation.are_there_any_signs_of_water_penetration_caused_by_failed_rainwater_goods_or_pipework,
},
)
data_dict.update({"external_elevation_id": external_elevation.id})
return self.upsert_record(
db_session=db_session,
model_class=pydanticModel,
data_dict=data_dict,
)
# Back
back = external_elevation_load_for_side(self.condition_report.master_obj.access_and_elevations.external_elevation_back, ExternalElevationRear)
# One
gable_one = external_elevation_load_for_side(self.condition_report.master_obj.access_and_elevations.external_elevation_gable_one, ExternalElevationGableOne)
# Two
gable_two = external_elevation_load_for_side(self.condition_report.master_obj.access_and_elevations.external_elevation_gable_two, ExternalElevationGableTwo, different="is_there_a_fourth_external_elevation")
# CO
co = self.get_attribute_and_load(
self.condition_report.master_obj.access_and_elevations,
"conservatory_or_out_building",
ConservatoryOrOutbuilding,
db_session=db_session,
)
return self.upsert_record(
db_session=db_session,
model_class=AccessAndElevations,
data_dict={
"property_access_id": pa.id,
"external_elevation_front_id": external_elevation_front.id,
"external_elevation_back_id": back.id,
"external_elevation_gable_one_id": gable_one.id,
"external_elevation_gable_two_id": gable_two.id,
"conservatory_or_out_building_id": co.id,
}
)
def load_general_information_from_condition_report(self, db_session):
assessors_data = self.condition_report.master_obj.general_information.assessor_details.model_dump()
@ -153,8 +244,18 @@ class surveyedDataProcessor():
data.update({"elevation_id": elevations.id})
elevation_info = upload_elevation_and_return_elevation(data)
print(elevations.info)
print("Check database please")
return self.upsert_record(
db_session=db_session,
model_class=GeneralInformation,
data_dict={
"assessor_detail_id": assessor_details.id,
"inspection_and_project_id": inspection_and_project.id,
"the_property_id": the_property.id,
"main_elevation_id": main_elevation.id,
"elevations_id": elevations.id,
},
lookup_field=None,
)
def load_pre_site_notes_summary_table(self, db_session):
summary_data = self.pre_site_note.survey_information.model_dump()
@ -179,7 +280,7 @@ class surveyedDataProcessor():
lookup_field="UPRN",
)
def get_attribute_and_load(self, obj, attr_string, pydanticModel, db_session, lookup_field=None):
def get_attribute_and_load(self, obj, attr_string, pydanticModel, db_session, lookup_field=None, additional_fields={}):
found = getattr(obj, attr_string, None)
if found:
print(f"Uploading to data base {found}")
@ -190,7 +291,8 @@ class surveyedDataProcessor():
db_session=db_session,
model_class=pydanticModel,
data_dict=found.model_dump(),
lookup_field=lookup_field
lookup_field=lookup_field,
additional_fields=additional_fields
)
return db
return None
@ -517,7 +619,7 @@ class surveyedDataProcessor():
db_session,
model_class,
data_dict,
lookup_field,
lookup_field=None,
update_if_exists: bool = False,
additional_fields: dict = None
):

View file

@ -51,7 +51,6 @@ class PropertyAccess(BaseModel):
is_there_restricted_space_for_contractors_to_access_the_roof_area: bool
is_there_more_than_1_point_5_meters_in_width_to_fence_or_neighbouring_boundary_along_the_full_gable_elevation: bool
is_access_to_the_rear_provided_by_use_of_a_ginnel: bool
is_access_to_the_rear_provided_by_use_of_a_ginnel: bool
is_access_to_the_rear_provided_by_use_of_a_secured_alleyway: bool
class ExternalElevation(BaseModel):

View file

@ -1,6 +1,6 @@
#poetry run alembic revision --autogenerate -m "added new column"
poetry run alembic revision --autogenerate -m "access and elevations"
poetry run alembic upgrade head
#poetry run alembic upgrade head
# See which hash I'm at
#poetry run alembic current