feat: Implement V3 ID Vision and fields_to_exclude_from_db across core models

This commit refactors numerous Pydantic models to align with the V3 ID Vision standard, ensuring that primary and foreign key fields are represented as clean string IDs in the API. It also introduces and populates the  ClassVar in each model to prevent view-only fields and linked objects from being inadvertently written to the database during PATCH/POST operations.

Specifically, this includes:
- Adding  to exclude view-derived or joined fields such as , , nested objects (e.g., , ), and convenience fields (e.g., ).
- Adjusting root validators to correctly map string IDs and strip internal integer IDs for API responses.
- Resolving a KeyError by adding  to .

These changes are crucial for maintaining data integrity and consistency with the V3 API architecture.
This commit is contained in:
Scott Idem
2026-02-24 16:21:27 -05:00
parent 9d89d4c8e4
commit 0f4b4d2f51
22 changed files with 611 additions and 585 deletions

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import get_id_random, redis_lookup_id_random from app.db_sql import get_id_random, redis_lookup_id_random
@@ -120,6 +120,11 @@ class Address_Base(BaseModel):
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'country_subdivision_name', 'country_name'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -49,6 +49,7 @@ base_fields['event_person_tracking_id_random'] = xxx_id_random_field_schema
base_fields['event_presentation_id_random'] = xxx_id_random_field_schema base_fields['event_presentation_id_random'] = xxx_id_random_field_schema
base_fields['event_presenter_id_random'] = xxx_id_random_field_schema base_fields['event_presenter_id_random'] = xxx_id_random_field_schema
base_fields['event_registration_id_random'] = xxx_id_random_field_schema base_fields['event_registration_id_random'] = xxx_id_random_field_schema
base_fields['event_registration_cfg_id_random'] = xxx_id_random_field_schema
base_fields['event_session_id_random'] = xxx_id_random_field_schema base_fields['event_session_id_random'] = xxx_id_random_field_schema
base_fields['event_track_id_random'] = xxx_id_random_field_schema base_fields['event_track_id_random'] = xxx_id_random_field_schema
base_fields['flask_cfg_id_random'] = xxx_id_random_field_schema base_fields['flask_cfg_id_random'] = xxx_id_random_field_schema

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import get_id_random, redis_lookup_id_random from app.db_sql import get_id_random, redis_lookup_id_random
@@ -139,6 +139,11 @@ class Contact_Base(BaseModel):
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'linked_address_id', 'timezone_name', 'address'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -27,6 +27,7 @@ class Event_Abstract_Base(BaseModel):
id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random']) event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random']) event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
@@ -96,6 +97,8 @@ class Event_Abstract_Base(BaseModel):
values['id'] = rid values['id'] = rid
values['event_abstract_id'] = rid values['event_abstract_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid values['event_id'] = e_rid
if ep_rid := values.get('event_person_id_random'): if ep_rid := values.get('event_person_id_random'):
@@ -110,12 +113,18 @@ class Event_Abstract_Base(BaseModel):
values['grant_id'] = g_rid values['grant_id'] = g_rid
# 2. Prevent "Collision Population" # 2. Prevent "Collision Population"
for k in ['id', 'event_abstract_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']: for k in ['id', 'event_abstract_id', 'account_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None: if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k] del values[k]
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'event_session_code', 'event_session_name',
'event_file_list', 'event_person', 'event_presenter_list'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False
@@ -136,6 +145,7 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base):
id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random']) event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random']) event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
@@ -181,6 +191,8 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base):
values['id'] = rid values['id'] = rid
values['event_abstract_id'] = rid values['event_abstract_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid values['event_id'] = e_rid
if ep_rid := values.get('event_person_id_random'): if ep_rid := values.get('event_person_id_random'):
@@ -195,12 +207,17 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base):
values['grant_id'] = g_rid values['grant_id'] = g_rid
# 2. Prevent "Collision Population" # 2. Prevent "Collision Population"
for k in ['id', 'event_abstract_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']: for k in ['id', 'event_abstract_id', 'account_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None: if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k] del values[k]
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False
@@ -246,4 +263,9 @@ class Event_Abstract_Ext(Event_Abstract_Base_New):
# event_track: Optional[Event_Track_Base] # event_track: Optional[Event_Track_Base]
# poc_event_person: Optional[Event_Person_Base] # Maybe change this to primary_event_person? # poc_event_person: Optional[Event_Person_Base] # Maybe change this to primary_event_person?
# poc_person: Optional[Person_Base] # Maybe change this to primary_person? # poc_person: Optional[Person_Base] # Maybe change this to primary_person?
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = Event_Abstract_Base_New.fields_to_exclude_from_db + [
'event_session_code', 'event_session_name', 'event_cfg', 'event_file_list', 'event_person'
]
# ### END ### API Event Abstract Models ### Event_Abstract_Ext() ### # ### END ### API Event Abstract Models ### Event_Abstract_Ext() ###

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -191,6 +191,11 @@ class Event_Badge_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'order', 'ticket_list', 'event_badge_template'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True
@@ -329,6 +334,11 @@ class Event_Badge_Basic_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'event_badge_template'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -15,16 +15,40 @@ class Event_Cfg_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_cfg_id_random'], id: Optional[str] = Field(None, **base_fields['event_cfg_id_random'])
alias = 'event_cfg_id_random', event_cfg_id: Optional[str] = Field(None, **base_fields['event_cfg_id_random'])
)
id: Optional[int] = Field(
alias = 'event_cfg_id'
)
event_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
event_id: Optional[int] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_cfg_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_cfg_id_random'):
values['id'] = rid
values['event_cfg_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_cfg_id', 'account_id', 'event_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
enable: Optional[bool] enable: Optional[bool]
enable_from: Optional[datetime.datetime] enable_from: Optional[datetime.datetime]
@@ -105,6 +129,11 @@ class Event_Cfg_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'event_id', 'event_registration_cfg'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -148,7 +148,7 @@ class Event_Device_Base(BaseModel):
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table # Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = ['event_cfg', 'event_location'] fields_to_exclude_from_db: ClassVar[list] = ['account_id', 'event_cfg', 'event_location']
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -143,6 +143,11 @@ class Event_Exhibit_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'event_exhibit_tracking_list'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -215,6 +215,28 @@ class Event_Exhibit_Tracking_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id',
'event_badge_pronouns', 'event_badge_pronouns_override', 'event_badge_informal_name',
'event_badge_title_names', 'event_badge_given_name', 'event_badge_middle_name',
'event_badge_family_name', 'event_badge_designations',
'event_badge_professional_title', 'event_badge_professional_title_override',
'event_badge_full_name', 'event_badge_full_name_override',
'event_badge_affiliations', 'event_badge_affiliations_override',
'event_badge_email', 'event_badge_email_override',
'event_badge_phone', 'event_badge_phone_override',
'event_badge_address_line_1', 'event_badge_address_line_2', 'event_badge_address_line_3',
'event_badge_city', 'event_badge_county', 'event_badge_country_subdivision_code',
'event_badge_state_province', 'event_badge_state_province_abb', 'event_badge_postal_code',
'event_badge_country_alpha_2_code', 'event_badge_country',
'event_badge_location', 'event_badge_location_override',
'event_person_informal_name', 'event_person_given_name', 'event_person_family_name',
'event_person_full_name', 'event_person_full_name_override',
'event_person_affiliations', 'event_person_email', 'event_exhibit_name',
'event_person'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import get_id_random, redis_lookup_id_random from app.db_sql import get_id_random, redis_lookup_id_random
@@ -206,6 +206,22 @@ class Event_File_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'filename_no_ext', 'filename_w_ext',
'hosted_file_hash_sha256', 'hosted_file_subdirectory_path',
'hosted_file_content_type', 'hosted_file_size',
'event_name', 'event_code', 'event_start_datetime', 'event_end_datetime',
'event_location_code', 'event_location_name', 'event_presentation_code',
'event_presentation_type_code', 'event_presentation_name',
'event_presentation_start_datetime', 'event_presentation_end_datetime',
'event_presenter_code', 'event_presenter_given_name', 'event_presenter_family_name',
'event_presenter_full_name', 'event_presenter_email', 'event_session_code',
'event_session_type_code', 'event_session_name', 'event_session_start_datetime',
'event_session_end_datetime', 'event_track_code', 'event_track_name',
'hosted_file'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -129,6 +129,16 @@ class Event_Location_Base(BaseModel):
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id',
'location_type', 'file_count', 'internal_use_count', 'event_file_id_li_json', 'file_count_all',
'event_name', 'event_start_datetime', 'event_end_datetime',
'event_abstract_list', 'event_device_list', 'event_file_list',
'event_file_internal_use_list', 'event_presentation_list',
'event_presenter_list', 'event_session_list', 'event_track_list'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -228,6 +228,17 @@ class Event_Base(BaseModel):
return str(v) return str(v)
return v return v
# Fields that are part of the model (for reading) but should not be saved to the DB table.
# These convenience fields and related objects are joined in the view.
fields_to_exclude_from_db: ClassVar[list] = [
'file_count', 'internal_use_count', 'event_file_id_li_json', 'file_count_all',
'address_location', 'contact_1', 'contact_2', 'contact_3',
'event_abstract_list', 'event_cfg', 'event_device_list', 'event_exhibit_list',
'event_file_list', 'event_location_list', 'event_person_list',
'event_presentation_list', 'event_presenter_list', 'event_session_list',
'event_track_list', 'poc_person'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -22,40 +22,33 @@ class Event_Person_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_person_id_random'], id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
alias = 'event_person_id_random', event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
)
id: Optional[int] = Field(
alias = 'event_person_id'
)
account_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[int] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_id_random: Optional[str] event_badge_id: Optional[str] = Field(None, **base_fields['event_badge_id_random'])
event_id: Optional[int] event_badge_vendor_id: Optional[str] = Field(None, **base_fields['event_badge_id_random'])
event_badge_vip_id: Optional[str] = Field(None, **base_fields['event_badge_id_random'])
event_badge_id_random: Optional[str] # Default attendee badge event_person_profile_id: Optional[str] = Field(None, **base_fields['event_person_profile_id_random'])
event_badge_id: Optional[int] event_registration_id: Optional[str] = Field(None, **base_fields['event_registration_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
event_badge_vendor_id_random: Optional[str] # Additional vendor badge # --- Standardized Legacy / Internal IDs (Excluded) ---
event_badge_vendor_id: Optional[int] id_random: Optional[str] = Field(None, alias='event_person_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_badge_vip_id_random: Optional[str] # Additional VIP badge event_id_random: Optional[str] = Field(None, exclude=True)
event_badge_vip_id: Optional[int] event_badge_id_random: Optional[str] = Field(None, exclude=True)
event_badge_vendor_id_random: Optional[str] = Field(None, exclude=True)
event_person_profile_id_random: Optional[str] event_badge_vip_id_random: Optional[str] = Field(None, exclude=True)
event_person_profile_id: Optional[int] event_person_profile_id_random: Optional[str] = Field(None, exclude=True)
event_registration_id_random: Optional[str] = Field(None, exclude=True)
event_registration_id_random: Optional[str] person_id_random: Optional[str] = Field(None, exclude=True)
event_registration_id: Optional[int] user_id_random: Optional[str] = Field(None, exclude=True)
person_id_random: Optional[str]
person_id: Optional[int]
user_id_random: Optional[str]
user_id: Optional[int]
external_id: Optional[str] # Generated internally or externally. Needs to be stable. It should not change. external_id: Optional[str] # Generated internally or externally. Needs to be stable. It should not change.
external_event_id: Optional[str] # Event ID generated by external system. Needs to be stable. It should not change. external_event_id: Optional[str] # Event ID generated by external system. Needs to be stable. It should not change.
@@ -159,81 +152,54 @@ class Event_Person_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('event_person_id_random', always=True) @root_validator(pre=True)
def event_person_id_random_copy(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if values['id_random']: """
return values['id_random'] Vision Transformer:
return None Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_person_id_random'):
values['id'] = rid
values['event_person_id'] = rid
if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): values['event_id'] = e_rid
if b_rid := values.get('event_badge_id_random'): values['event_badge_id'] = b_rid
if bv_rid := values.get('event_badge_vendor_id_random'): values['event_badge_vendor_id'] = bv_rid
if bvip_rid := values.get('event_badge_vip_id_random'): values['event_badge_vip_id'] = bvip_rid
if ep_rid := values.get('event_person_profile_id_random'): values['event_person_profile_id'] = ep_rid
if er_rid := values.get('event_registration_id_random'): values['event_registration_id'] = er_rid
if p_rid := values.get('person_id_random'): values['person_id'] = p_rid
if u_rid := values.get('user_id_random'): values['user_id'] = u_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_person_id', 'account_id', 'event_id', 'event_badge_id', 'event_badge_vendor_id', 'event_badge_vip_id', 'event_person_profile_id', 'event_registration_id', 'person_id', 'user_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
@validator('id', always=True) # Fields that are part of the model (for reading) but should not be saved to the DB table
def event_person_id_lookup(cls, v, values, **kwargs): fields_to_exclude_from_db: ClassVar[list] = [
if isinstance(v, int) and v > 0: return v 'file_count',
elif id_random := values.get('id_random'): 'informal_name', 'given_name', 'middle_name', 'family_name', 'full_name_override', 'full_name',
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') 'affiliations', 'email', 'website_url',
return None 'event_badge_informal_name', 'event_badge_given_name', 'event_badge_middle_name',
'event_badge_family_name', 'event_badge_full_name', 'event_badge_full_name_override',
@validator('account_id', always=True) 'event_badge_affiliations', 'event_badge_email', 'event_badge_city',
def account_id_lookup(cls, v, values, **kwargs): 'event_badge_state_province', 'event_badge_country_alpha_2_code', 'event_badge_country',
if isinstance(v, int) and v > 0: return v 'event_person_informal_name', 'event_person_given_name', 'event_person_middle_name',
elif id_random := values.get('account_id_random'): 'event_person_family_name', 'event_person_name_override', 'event_person_full_name',
return redis_lookup_id_random(record_id_random=id_random, table_name='account') 'event_person_affiliations', 'event_person_email', 'event_person_extended_json',
return None 'person_informal_name', 'person_given_name', 'person_middle_name', 'person_family_name',
'person_full_name', 'person_full_name_override', 'person_affiliations', 'person_email',
@validator('event_id', always=True) 'user_email', 'user_name', 'user_username',
def event_id_lookup(cls, v, values, **kwargs): 'event_badge', 'event_badge_vendor', 'event_badge_vip', 'event_exhibit_list',
if isinstance(v, int) and v > 0: return v 'event_file_list', 'event_location_list', 'event_person_profile',
elif id_random := values.get('event_id_random'): 'event_presentation_list', 'event_presenter_list', 'event_registration',
return redis_lookup_id_random(record_id_random=id_random, table_name='event') 'event_session', 'event_track', 'person', 'user'
return None ]
@validator('event_badge_id', always=True)
def event_badge_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_badge_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_badge')
return None
@validator('event_badge_vendor_id', always=True)
def event_badge_vendor_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_badge_vendor_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_badge')
return None
@validator('event_badge_vip_id', always=True)
def event_badge_vip_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_badge_vip_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_badge')
return None
@validator('event_person_profile_id', always=True)
def event_person_profile_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_person_profile_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person_profile')
return None
@validator('event_registration_id', always=True)
def event_registration_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_registration_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_registration')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
@validator('user_id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('user_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='user')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
@@ -247,17 +213,17 @@ class Event_Person_New_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
**base_fields['event_person_id_random'], id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
alias = 'event_person_id_random', event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
)
id: Optional[int] = Field( account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
alias = 'event_person_id' event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
)
account_id_random: Optional[str] # --- Standardized Legacy / Internal IDs (Excluded) ---
account_id: Optional[int] id_random: Optional[str] = Field(None, alias='event_person_id_random', exclude=True)
event_id_random: Optional[str] account_id_random: Optional[str] = Field(None, exclude=True)
event_id: Optional[int] event_id_random: Optional[str] = Field(None, exclude=True)
extended_json: Optional[Union[Json, None]] extended_json: Optional[Union[Json, None]]
@@ -319,32 +285,43 @@ class Event_Person_New_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('event_person_id_random', always=True) @root_validator(pre=True)
def event_person_id_random_copy(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if values['id_random']: """
return values['id_random'] Vision Transformer:
return None Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_person_id_random'):
values['id'] = rid
values['event_person_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_person_id', 'account_id', 'event_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
@validator('id', always=True) # Fields that are part of the model (for reading) but should not be saved to the DB table
def event_person_id_lookup(cls, v, values, **kwargs): fields_to_exclude_from_db: ClassVar[list] = [
if isinstance(v, int) and v > 0: return v 'informal_name', 'given_name', 'middle_name', 'family_name', 'full_name',
elif id_random := values.get('id_random'): 'full_name_override', 'affiliations', 'email', 'website_url', 'state_province_name',
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') 'event_badge_informal_name', 'event_badge_given_name', 'event_badge_middle_name',
return None 'event_badge_family_name', 'event_badge_full_name', 'event_badge_full_name_override',
'event_badge_affiliations', 'event_badge_email', 'event_badge_city',
@validator('account_id', always=True) 'event_badge_state_province', 'event_badge_country_alpha_2_code', 'event_badge_country',
def account_id_lookup(cls, v, values, **kwargs): 'event_person_informal_name', 'event_person_given_name', 'event_person_middle_name',
if isinstance(v, int) and v > 0: return v 'event_person_family_name', 'event_person_name_override', 'event_person_full_name',
elif id_random := values.get('account_id_random'): 'event_person_affiliations', 'event_person_email',
return redis_lookup_id_random(record_id_random=id_random, table_name='account') 'person_given_name', 'person_middle_name', 'person_family_name',
return None 'person_full_name', 'person_full_name_override', 'new_password'
]
@validator('event_id', always=True)
def event_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -17,28 +17,23 @@ class Event_Person_Profile_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
**base_fields['event_person_profile_id_random'], id: Optional[str] = Field(None, **base_fields['event_person_profile_id_random'])
alias = 'event_person_profile_id_random', event_person_profile_id: Optional[str] = Field(None, **base_fields['event_person_profile_id_random'])
)
id: Optional[int] = Field(
alias = 'event_person_profile_id'
)
account_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[int] contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
organization_id: Optional[str] = Field(None, **base_fields['organization_id_random'])
contact_id_random: Optional[str] # --- Standardized Legacy / Internal IDs (Excluded) ---
contact_id: Optional[int] id_random: Optional[str] = Field(None, alias='event_person_profile_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] # Only in view contact_id_random: Optional[str] = Field(None, exclude=True)
event_id: Optional[int] # Only in view event_id_random: Optional[str] = Field(None, exclude=True)
event_person_id_random: Optional[str] = Field(None, exclude=True)
event_person_id_random: Optional[str] # Only in view organization_id_random: Optional[str] = Field(None, exclude=True)
event_person_id: Optional[int] # Only in view
organization_id_random: Optional[str]
organization_id: Optional[int]
pronouns: Optional[str] # Preferred pronouns pronouns: Optional[str] # Preferred pronouns
informal_name: Optional[str] informal_name: Optional[str]
@@ -65,21 +60,18 @@ class Event_Person_Profile_Base(BaseModel):
email: Optional[str] email: Optional[str]
website_url: Optional[str] website_url: Optional[str]
thumbnail_hosted_file_id: Optional[int] thumbnail_hosted_file_id: Optional[str] = Field(None, **base_fields['hosted_file_id_random'])
thumbnail_hosted_file_id_random: Optional[str]
thumbnail_path: Optional[str] thumbnail_path: Optional[str]
thumbnail_bg_color: Optional[str] thumbnail_bg_color: Optional[str]
# photo_path: Optional[str] # photo_path: Optional[str]
# photo_bg_color: Optional[str] # photo_bg_color: Optional[str]
picture_hosted_file_id: Optional[int] picture_hosted_file_id: Optional[str] = Field(None, **base_fields['hosted_file_id_random'])
picture_hosted_file_id_random: Optional[str]
picture_path: Optional[str] picture_path: Optional[str]
picture_bg_color: Optional[str] picture_bg_color: Optional[str]
about_hosted_file_id: Optional[int] about_hosted_file_id: Optional[str] = Field(None, **base_fields['hosted_file_id_random'])
about_hosted_file_id_random: Optional[str]
about_path: Optional[str] about_path: Optional[str]
email_allowed: Optional[bool] email_allowed: Optional[bool]
@@ -110,66 +102,37 @@ class Event_Person_Profile_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('event_person_profile_id_random', always=True) @root_validator(pre=True)
def event_person_profile_id_random_copy(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if values['id_random']: """
return values['id_random'] Vision Transformer:
return None Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_person_profile_id_random'):
values['id'] = rid
values['event_person_profile_id'] = rid
if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
if c_rid := values.get('contact_id_random'): values['contact_id'] = c_rid
if e_rid := values.get('event_id_random'): values['event_id'] = e_rid
if ep_rid := values.get('event_person_id_random'): values['event_person_id'] = ep_rid
if o_rid := values.get('organization_id_random'): values['organization_id'] = o_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_person_profile_id', 'account_id', 'contact_id', 'event_id', 'event_person_id', 'organization_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
@validator('id', always=True) # Fields that are part of the model (for reading) but should not be saved to the DB table
def event_person_profile_id_lookup(cls, v, values, **kwargs): fields_to_exclude_from_db: ClassVar[list] = [
if isinstance(v, int) and v > 0: return v 'account_id', 'event_id', 'event_person_id',
elif id_random := values.get('id_random'): 'full_name', 'full_name_override', 'display_name',
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person_profile') 'thumbnail_path', 'picture_path', 'about_path',
return None 'contact', 'event_cfg', 'organization'
]
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('contact_id', always=True)
def contact_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('contact_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='contact')
return None
@validator('organization_id', always=True)
def organization_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('organization_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='organization')
return None
@validator('thumbnail_hosted_file_id', always=True)
def thumbnail_hosted_file_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('thumbnail_hosted_file_id_random', None):
return redis_lookup_id_random(record_id_random=values['thumbnail_hosted_file_id_random'], table_name='thumbnail_hosted_file')
return None
@validator('picture_hosted_file_id', always=True)
def picture_hosted_file_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('picture_hosted_file_id_random', None):
return redis_lookup_id_random(record_id_random=values['picture_hosted_file_id_random'], table_name='picture_hosted_file')
return None
@validator('about_hosted_file_id', always=True)
def about_hosted_file_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('about_hosted_file_id_random', None):
return redis_lookup_id_random(record_id_random=values['about_hosted_file_id_random'], table_name='about_hosted_file')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -22,12 +22,22 @@ class Event_Presentation_Base(BaseModel):
id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random']) event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random']) event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random'])
event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random']) event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random'])
event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random']) event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_presentation_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
event_abstract_id_random: Optional[str] = Field(None, exclude=True)
event_location_id_random: Optional[str] = Field(None, exclude=True)
event_session_id_random: Optional[str] = Field(None, exclude=True)
event_track_id_random: Optional[str] = Field(None, exclude=True)
external_id: Optional[str] = Field( external_id: Optional[str] = Field(
# alias = 'event_presentation_external_id' # alias = 'event_presentation_external_id'
) )
@@ -109,6 +119,8 @@ class Event_Presentation_Base(BaseModel):
values['id'] = rid values['id'] = rid
values['event_presentation_id'] = rid values['event_presentation_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid values['event_id'] = e_rid
if ea_rid := values.get('event_abstract_id_random'): if ea_rid := values.get('event_abstract_id_random'):
@@ -121,12 +133,22 @@ class Event_Presentation_Base(BaseModel):
values['event_track_id'] = et_rid values['event_track_id'] = et_rid
# 2. Prevent "Collision Population" # 2. Prevent "Collision Population"
for k in ['id', 'event_presentation_id', 'event_id', 'event_abstract_id', 'event_location_id', 'event_session_id', 'event_track_id']: for k in ['id', 'event_presentation_id', 'account_id', 'event_id', 'event_abstract_id', 'event_location_id', 'event_session_id', 'event_track_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None: if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k] del values[k]
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'account_id', 'file_count',
'event_name', 'event_start_datetime', 'event_end_datetime', 'event_location_name',
'event_session_type_code', 'event_session_name', 'event_session_start_datetime',
'event_session_end_datetime', 'event_track_name',
'poc_event_person', 'poc_person', 'event_abstract_list', 'event_file_list',
'event_presenter_list', 'event_session'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -19,45 +19,32 @@ class Event_Presenter_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_presenter_id_random'], id: Optional[str] = Field(None, **base_fields['event_presenter_id_random'])
alias = 'event_presenter_id_random', event_presenter_id: Optional[str] = Field(None, **base_fields['event_presenter_id_random'])
)
id: Optional[int] = Field(
alias = 'event_presenter_id'
)
account_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[int] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random'])
event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random'])
event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_presenter_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
event_person_id_random: Optional[str] = Field(None, exclude=True)
event_presentation_id_random: Optional[str] = Field(None, exclude=True)
event_session_id_random: Optional[str] = Field(None, exclude=True)
event_track_id_random: Optional[str] = Field(None, exclude=True)
person_id_random: Optional[str] = Field(None, exclude=True)
external_id: Optional[str] external_id: Optional[str]
code: Optional[str] code: Optional[str]
event_id_random: Optional[str]
event_id: Optional[int]
# event_abstract_id_random: Optional[str]
# event_abstract_id: Optional[int]
event_location_id_random: Optional[str]
event_location_id: Optional[int]
event_person_id_random: Optional[str]
event_person_id: Optional[int]
event_presentation_id_random: Optional[str]
event_presentation_id: Optional[int]
event_session_id_random: Optional[str]
event_session_id: Optional[int]
event_track_id_random: Optional[str]
event_track_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
for_type: Optional[str] for_type: Optional[str]
for_id: Optional[int] for_id: Optional[int]
@@ -193,58 +180,52 @@ class Event_Presenter_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True) @root_validator(pre=True)
def event_presenter_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_presenter') Map DB keys to clean API keys and strip internal integers.
return None """
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_presenter_id_random'):
values['id'] = rid
values['event_presenter_id'] = rid
if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): values['event_id'] = e_rid
if ep_rid := values.get('event_person_id_random'): values['event_person_id'] = ep_rid
if epr_rid := values.get('event_presentation_id_random'): values['event_presentation_id'] = epr_rid
if es_rid := values.get('event_session_id_random'): values['event_session_id'] = es_rid
if et_rid := values.get('event_track_id_random'): values['event_track_id'] = et_rid
if p_rid := values.get('person_id_random'): values['person_id'] = p_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_presenter_id', 'account_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_session_id', 'event_track_id', 'person_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
@validator('account_id', always=True) # Fields that are part of the model (for reading) but should not be saved to the DB table
def account_id_lookup(cls, v, values, **kwargs): fields_to_exclude_from_db: ClassVar[list] = [
if isinstance(v, int) and v > 0: return v 'account_id', 'file_count', 'event_file_id_li_json',
elif id_random := values.get('account_id_random'): 'event_name', 'event_start_datetime', 'event_end_datetime',
return redis_lookup_id_random(record_id_random=id_random, table_name='account') 'event_location_code', 'event_location_name',
return None 'event_presentation_code', 'event_presentation_type_code', 'event_presentation_name',
'event_presentation_start_datetime', 'event_presentation_end_datetime',
@validator('event_id', always=True) 'event_session_code', 'event_session_type_code', 'event_session_name',
def event_id_lookup(cls, v, values, **kwargs): 'event_session_start_datetime', 'event_session_end_datetime',
if isinstance(v, int) and v > 0: return v 'event_track_code', 'event_track_name',
elif id_random := values.get('event_id_random'): 'person_external_id', 'person_external_sys_id', 'person_given_name',
return redis_lookup_id_random(record_id_random=id_random, table_name='event') 'person_family_name', 'person_professional_title', 'person_full_name',
return None 'person_affiliations', 'person_primary_email', 'person_passcode',
'event_abstract', 'event_abstract_list', 'event_cfg', 'event_file_list',
@validator('event_person_id', always=True) 'event_person', 'event_presentation', 'event_session'
def event_person_id_lookup(cls, v, values, **kwargs): ]
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person')
return None
@validator('event_presentation_id', always=True)
def event_presentation_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_presentation_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation')
return None
@validator('event_session_id', always=True)
def event_session_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_session_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_session')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Presenter Models ### Event_Presenter_Base() ### # ### END ### API Event Presenter Models ### Event_Presenter_Base() ###
@@ -255,48 +236,28 @@ class Event_Presenter_Out_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
**base_fields['event_presenter_id_random'], id: Optional[str] = Field(None, **base_fields['event_presenter_id_random'])
alias = 'event_presenter_id_random', event_presenter_id: Optional[str] = Field(None, **base_fields['event_presenter_id_random'])
)
id: Optional[int] = Field(
alias = 'event_presenter_id'
)
account_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[int] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_presenter_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
person_id_random: Optional[str] = Field(None, exclude=True)
event_presentation_id_random: Optional[str] = Field(None, exclude=True)
event_session_id_random: Optional[str] = Field(None, exclude=True)
external_id: Optional[str] external_id: Optional[str]
code: Optional[str] code: Optional[str]
event_id_random: Optional[str]
event_id: Optional[int]
# event_abstract_id_random: Optional[str]
# event_abstract_id: Optional[int]
# event_location_id_random: Optional[str]
# event_location_id: Optional[int]
# event_person_id_random: Optional[str]
# event_person_id: Optional[int]
event_presentation_id_random: Optional[str]
event_presentation_id: Optional[int]
event_session_id_random: Optional[str]
event_session_id: Optional[int]
# event_track_id_random: Optional[str]
# event_track_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
# for_type: Optional[str]
# for_id: Optional[int]
pronouns: Optional[str] # Preferred pronouns pronouns: Optional[str] # Preferred pronouns
informal_name: Optional[str] # Informal or nick name they commonly go by informal_name: Optional[str] # Informal or nick name they commonly go by
@@ -311,38 +272,24 @@ class Event_Presenter_Out_Base(BaseModel):
professional_title: Optional[str] # Professional title professional_title: Optional[str] # Professional title
# title: Optional[str] # NOTE: Phasing out! Use *professional_title* instead. # title: Optional[str] # NOTE: Phasing out! Use *professional_title* instead.
# display_name: Optional[str] # NOTE: This will be changed to full_name_override to match event_badge, event_person_profile, and person
# BEGIN # Auto created name variations # BEGIN # Auto created name variations
full_name: Optional[str] # title_names given_name middle_name family_name designations full_name: Optional[str] # title_names given_name middle_name family_name designations
full_name_override: Optional[str] # Override full_name; Actual name shown for presenter full_name_override: Optional[str] # Override full_name; Actual name shown for presenter
# degree: Optional[str] # NOTE: Phasing out! Use *designations* instead.
# degrees: Optional[str] # NOTE: Phasing out! Use *designations* instead.
# credentials: Optional[str] # NOTE: Phasing out! Use *designations* instead.
affiliations: Optional[str] # One or more affiliations with organizations, companies, and other groups affiliations: Optional[str] # One or more affiliations with organizations, companies, and other groups
# affiliation: Optional[str] # NOTE: Phasing out! Use *affiliations* instead. # affiliation: Optional[str] # NOTE: Phasing out! Use *affiliations* instead.
email: Optional[str] email: Optional[str]
website_url: Optional[str] website_url: Optional[str]
# phone_li_json: Optional[Union[Json, None]]
# For social media in a JSON object format. The Aether standard field names should be used. Examples: url, url_text, icon, etc. # For social media in a JSON object format. The Aether standard field names should be used. Examples: url, url_text, icon, etc.
social_li_json: Optional[Union[Json, None]] social_li_json: Optional[Union[Json, None]]
tagline: Optional[str] tagline: Optional[str]
biography: Optional[str] biography: Optional[str]
# picture_path: Optional[str] # Start using image_li_json instead
# picture_bg_color: Optional[str]
# For image files only in a JSON object format. The Aether standard field names should be used. Examples: url, url_text, alt_text, width, height, size (in bytes), etc. # For image files only in a JSON object format. The Aether standard field names should be used. Examples: url, url_text, alt_text, width, height, size (in bytes), etc.
image_li_json: Optional[Union[Json, None]] # "headshot" is probably the most common image_li_json: Optional[Union[Json, None]] # "headshot" is probably the most common
# media_li_json: Optional[Union[Json, None]]
# role: Optional[str]
data_json: Optional[Union[Json, None]] # For key value data. Careful with overwriting existing fields! data_json: Optional[Union[Json, None]] # For key value data. Careful with overwriting existing fields!
cfg_json: Optional[Union[Json, None]] # Store per presenter config options like theme, language, etc cfg_json: Optional[Union[Json, None]] # Store per presenter config options like theme, language, etc
@@ -356,13 +303,8 @@ class Event_Presenter_Out_Base(BaseModel):
comments: Optional[str] comments: Optional[str]
enable: Optional[bool] enable: Optional[bool]
# enable_from: Optional[datetime.datetime] = None
# enable_to: Optional[datetime.datetime] = None
hide: Optional[bool] hide: Optional[bool]
# public: Optional[bool]
# public_hide: Optional[bool]
# hide_event_launcher: Optional[bool]
priority: Optional[bool] priority: Optional[bool]
sort: Optional[int] # The presenter number if given sort: Optional[int] # The presenter number if given
@@ -372,24 +314,6 @@ class Event_Presenter_Out_Base(BaseModel):
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
# Including convenience data
# This is only for convenience. Probably going to keep unless it causes a problem.
# event_name: Optional[str]
# event_start_datetime: Optional[datetime.datetime]
# event_end_datetime: Optional[datetime.datetime]
# event_location_code: Optional[str]
# event_location_name: Optional[str]
# event_presentation_code: Optional[str]
# event_presentation_type_code: Optional[str]
# event_presentation_name: Optional[str]
# event_presentation_start_datetime: Optional[datetime.datetime]
# event_presentation_end_datetime: Optional[datetime.datetime]
# event_session_code: Optional[str]
# event_session_type_code: Optional[str]
# event_session_name: Optional[str]
# event_session_start_datetime: Optional[datetime.datetime]
# event_session_end_datetime: Optional[datetime.datetime]
person_external_id: Optional[str] person_external_id: Optional[str]
person_external_sys_id: Optional[str] person_external_sys_id: Optional[str]
person_given_name: Optional[str] person_given_name: Optional[str]
@@ -404,50 +328,32 @@ class Event_Presenter_Out_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True) @root_validator(pre=True)
def event_presenter_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_presenter') Map DB keys to clean API keys and strip internal integers.
return None """
# 1. Map Random Strings to Clean Names
@validator('event_id', always=True) if rid := values.get('id_random') or values.get('event_presenter_id_random'):
def event_id_lookup(cls, v, values, **kwargs): values['id'] = rid
if isinstance(v, int) and v > 0: return v values['event_presenter_id'] = rid
elif id_random := values.get('event_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event') if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
return None if e_rid := values.get('event_id_random'): values['event_id'] = e_rid
if epr_rid := values.get('event_presentation_id_random'): values['event_presentation_id'] = epr_rid
# @validator('event_person_id', always=True) if es_rid := values.get('event_session_id_random'): values['event_session_id'] = es_rid
# def event_person_id_lookup(cls, v, values, **kwargs): if p_rid := values.get('person_id_random'): values['person_id'] = p_rid
# if isinstance(v, int) and v > 0: return v
# elif id_random := values.get('event_person_id_random'): # 2. Prevent "Collision Population"
# return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') for k in ['id', 'event_presenter_id', 'account_id', 'event_id', 'event_presentation_id', 'event_session_id', 'person_id']:
# return None if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
@validator('event_presentation_id', always=True)
def event_presentation_id_lookup(cls, v, values, **kwargs): return values
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_presentation_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation')
return None
@validator('event_session_id', always=True)
def event_session_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_session_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_session')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Presenter Models ### Event_Presenter_Base() ### # ### END ### API Event Presenter Models ### Event_Presenter_Base() ###

View File

@@ -1,8 +1,8 @@
from __future__ import annotations from __future__ import annotations
import datetime, hashlib, logging, os, pytz, redis, secrets import datetime, hashlib, logging, os, pytz, redis, secrets
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -14,6 +14,41 @@ class Event_Registration_Cfg_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['event_registration_cfg_id_random'])
event_registration_cfg_id: Optional[str] = Field(None, **base_fields['event_registration_cfg_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_registration_cfg_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_registration_cfg_id_random'):
values['id'] = rid
values['event_registration_cfg_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_registration_cfg_id', 'account_id', 'event_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
start_on: Optional[datetime.datetime] start_on: Optional[datetime.datetime]
end_on: Optional[datetime.datetime] end_on: Optional[datetime.datetime]
@@ -50,6 +85,9 @@ class Event_Registration_Cfg_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = []
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import * from app.lib_general import *
@@ -15,24 +15,23 @@ class Event_Registration_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
**base_fields['event_registration_id_random'], id: Optional[str] = Field(None, **base_fields['event_registration_id_random'])
alias = 'event_registration_id_random', event_registration_id: Optional[str] = Field(None, **base_fields['event_registration_id_random'])
)
id: Optional[int] = Field(
alias = 'event_registration_id'
)
account_id_random: Optional[str] account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[int] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_id_random: Optional[str] organization_id: Optional[str] = Field(None, **base_fields['organization_id_random'])
event_id: Optional[int] contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
organization_id_random: Optional[str] person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
organization_id: Optional[int]
contact_id_random: Optional[str] # --- Standardized Legacy / Internal IDs (Excluded) ---
contact_id: Optional[int] id_random: Optional[str] = Field(None, alias='event_registration_id_random', exclude=True)
person_id_random: Optional[str] account_id_random: Optional[str] = Field(None, exclude=True)
person_id: Optional[int] event_id_random: Optional[str] = Field(None, exclude=True)
organization_id_random: Optional[str] = Field(None, exclude=True)
contact_id_random: Optional[str] = Field(None, exclude=True)
person_id_random: Optional[str] = Field(None, exclude=True)
priority: Optional[bool] priority: Optional[bool]
sort: Optional[int] sort: Optional[int]
@@ -48,69 +47,32 @@ class Event_Registration_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('event_registration_id_random', always=True) @root_validator(pre=True)
def event_registration_id_random_copy(cls, v, values, **kwargs): def map_v3_ids(cls, values):
log.setLevel(logging.WARNING) """
log.debug(locals()) Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_registration_id_random'):
values['id'] = rid
values['event_registration_id'] = rid
if a_rid := values.get('account_id_random'): values['account_id'] = a_rid
if e_rid := values.get('event_id_random'): values['event_id'] = e_rid
if o_rid := values.get('organization_id_random'): values['organization_id'] = o_rid
if c_rid := values.get('contact_id_random'): values['contact_id'] = c_rid
if p_rid := values.get('person_id_random'): values['person_id'] = p_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_registration_id', 'account_id', 'event_id', 'organization_id', 'contact_id', 'person_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
if values['id_random']: # Fields that are part of the model (for reading) but should not be saved to the DB table
return values['id_random'] fields_to_exclude_from_db: ClassVar[list] = ['cfg', 'event_person_list']
return None
@validator('id', always=True)
def event_registration_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['id_random']:
log.debug(values['id_random'])
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='event_registration')
return None
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['account_id_random']:
return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account')
return None
@validator('event_id', always=True)
def event_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['event_id_random']:
return redis_lookup_id_random(record_id_random=values['event_id_random'], table_name='event')
return None
@validator('organization_id', always=True)
def organization_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['organization_id_random']:
return redis_lookup_id_random(record_id_random=values['organization_id_random'], table_name='organization')
return None
@validator('contact_id', always=True)
def contact_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['contact_id_random']:
return redis_lookup_id_random(record_id_random=values['contact_id_random'], table_name='contact')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['person_id_random']:
return redis_lookup_id_random(record_id_random=values['person_id_random'], table_name='person')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True

View File

@@ -216,6 +216,7 @@ class Event_Session_Base(BaseModel):
# Fields that are part of the model (for reading) but should not be saved to the DB table # Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [ fields_to_exclude_from_db: ClassVar[list] = [
'account_id',
'file_count', 'internal_use_count', 'event_file_id_li_json', 'file_count_all', 'file_count', 'internal_use_count', 'event_file_id_li_json', 'file_count_all',
'event_name', 'event_start_datetime', 'event_end_datetime', 'event_name', 'event_start_datetime', 'event_end_datetime',
'event_location_name', 'event_track_name', 'event_location_name', 'event_track_name',

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
@@ -15,17 +15,19 @@ class Event_Track_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
**base_fields['event_track_id_random'], id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
alias = 'event_track_id_random', event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
)
id: Optional[int] = Field( account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
alias = 'event_track_id' event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
) event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random'])
event_id_random: Optional[str]
event_id: Optional[int] # --- Standardized Legacy / Internal IDs (Excluded) ---
event_location_id_random: Optional[str] # Can a location be assigned to one track? id_random: Optional[str] = Field(None, alias='event_track_id_random', exclude=True)
event_location_id: Optional[int] # Can a location be assigned to one track? account_id_random: Optional[str] = Field(None, exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
event_location_id_random: Optional[str] = Field(None, exclude=True)
lu_track_type_id: Optional[int] lu_track_type_id: Optional[int]
track_type_code: Optional[str] track_type_code: Optional[str]
@@ -54,6 +56,11 @@ class Event_Track_Base(BaseModel):
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
# Including convenience data
event_name: Optional[str]
event_start_datetime: Optional[datetime.datetime]
event_end_datetime: Optional[datetime.datetime]
# Including other related objects # Including other related objects
#event: Optional[Event_Base] #event: Optional[Event_Base]
event_abstract_list: Optional[list] # Optional[Event_Abstract_Base] event_abstract_list: Optional[list] # Optional[Event_Abstract_Base]
@@ -66,45 +73,41 @@ class Event_Track_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('event_track_id_random', always=True) @root_validator(pre=True)
def event_track_id_random_copy(cls, v, values, **kwargs): def map_v3_ids(cls, values):
log.setLevel(logging.WARNING) """
log.debug(locals()) Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('event_track_id_random'):
values['id'] = rid
values['event_track_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid
if el_rid := values.get('event_location_id_random'):
values['event_location_id'] = el_rid
# 2. Prevent "Collision Population"
for k in ['id', 'event_track_id', 'account_id', 'event_id', 'event_location_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
return values
if values['id_random']: # Fields that are part of the model (for reading) but should not be saved to the DB table
return values['id_random'] fields_to_exclude_from_db: ClassVar[list] = [
return None 'account_id', 'track_type',
'event_name', 'event_start_datetime', 'event_end_datetime',
@validator('id', always=True) 'event_abstract_list', 'event_device_list', 'event_file_list',
def event_track_id_lookup(cls, v, values, **kwargs): 'event_presentation_list', 'event_presenter_list', 'event_session_list', 'event_track_list'
log.setLevel(logging.WARNING) ]
log.debug(locals())
if values['id_random']:
log.debug(values['id_random'])
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='event_track')
return None
@validator('event_id', always=True)
def event_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['event_id_random']:
return redis_lookup_id_random(record_id_random=values['event_id_random'], table_name='event')
return None
@validator('event_location_id', always=True)
def event_location_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['event_location_id_random']:
return redis_lookup_id_random(record_id_random=values['event_location_id_random'], table_name='event_location')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Track Models ### Event_Track_Base() ### # ### END ### API Event Track Models ### Event_Track_Base() ###

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -86,6 +86,11 @@ class Organization_Base(BaseModel):
return values return values
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'contact'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False

View File

@@ -1,6 +1,6 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
from app.db_sql import redis_lookup_id_random from app.db_sql import redis_lookup_id_random
@@ -184,6 +184,19 @@ class Person_Base(BaseModel):
return True return True
return v return v
# Fields that are part of the model (for reading) but should not be saved to the DB table
fields_to_exclude_from_db: ClassVar[list] = [
'membership_person_id', 'first_last_name', 'first_middle_last_name',
'last_first_name', 'last_first_middle_name', 'informal_full_name',
'professional_full_name', 'lu_gender_name', 'email', 'cc_email',
'username', 'user_name', 'user_email', 'user_allow_auth_key',
'user_super', 'user_manager', 'user_administrator', 'user_public',
'event_list', 'hosted_file_list', 'journal_list', 'contact',
'membership_person', 'membership_group_list', 'membership_type_list',
'orders_info', 'order_list', 'order_cart', 'order_cart_v3',
'organization', 'post_list', 'user'
]
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = False allow_population_by_field_name = False