Skip to content

Commit 23548bf

Browse files
authored
Prevent EmbeddedJsonModel from generating primary keys (#797)
EmbeddedJsonModels are stored as part of their parent document, not as separate Redis keys, so they don't need primary keys. Fixes #496
1 parent a9792e7 commit 23548bf

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

aredis_om/model/model.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,14 @@ class Config:
25522552
# Set up PrimaryKeyAccessor descriptor for .pk access
25532553
setattr(new_class, "pk", PrimaryKeyAccessor())
25542554

2555+
# For embedded models, clear the primary_key from meta since they don't
2556+
# need primary keys - they're stored as part of their parent document,
2557+
# not as separate Redis keys. This fixes GitHub issue #496.
2558+
# Note: We keep the pk field in model_fields but the validator will
2559+
# return None and model_dump will exclude it.
2560+
if getattr(new_class._meta, "embedded", False):
2561+
new_class._meta.primary_key = None
2562+
25552563
if not getattr(new_class._meta, "global_key_prefix", None):
25562564
new_class._meta.global_key_prefix = getattr(
25572565
base_meta, "global_key_prefix", ""
@@ -2770,6 +2778,9 @@ async def expire(
27702778

27712779
@field_validator("pk", mode="after")
27722780
def validate_pk(cls, v):
2781+
# Skip pk generation for embedded models - they don't need primary keys
2782+
if getattr(cls._meta, "embedded", False):
2783+
return None
27732784
if not v or isinstance(v, ExpressionProxy):
27742785
v = cls._meta.primary_key_creator_cls().create_pk()
27752786
return v
@@ -2778,13 +2789,24 @@ def validate_pk(cls, v):
27782789

27792790
@field_validator("pk")
27802791
def validate_pk(cls, v):
2792+
# Skip pk generation for embedded models - they don't need primary keys
2793+
if getattr(cls._meta, "embedded", False):
2794+
return None
27812795
if not v or isinstance(v, ExpressionProxy):
27822796
v = cls._meta.primary_key_creator_cls().create_pk()
27832797
return v
27842798

27852799
@classmethod
27862800
def validate_primary_key(cls):
2787-
"""Check for a primary key. We need one (and only one)."""
2801+
"""Check for a primary key. We need one (and only one).
2802+
2803+
Embedded models are exempt from this check since they don't need
2804+
primary keys - they're stored as part of their parent document.
2805+
"""
2806+
# Skip validation for embedded models - they don't need primary keys
2807+
if getattr(cls._meta, "embedded", False):
2808+
return
2809+
27882810
primary_keys = 0
27892811
for name, field in cls.model_fields.items():
27902812
if (
@@ -3823,5 +3845,17 @@ def schema_for_type(
38233845

38243846

38253847
class EmbeddedJsonModel(JsonModel, abc.ABC):
3848+
"""
3849+
A model intended to be embedded within a JsonModel.
3850+
3851+
EmbeddedJsonModels are stored as part of their parent document, not as
3852+
separate Redis keys, so they do not need or generate primary keys.
3853+
3854+
The pk field is excluded from serialization by default.
3855+
"""
3856+
3857+
# Override pk to exclude it from serialization - embedded models don't need pks
3858+
pk: Optional[str] = Field(default=None, exclude=True)
3859+
38263860
class Meta:
38273861
embedded = True

redis_om/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from .model.types import Coordinates, GeoFilter
2121

22+
2223
# Backward compatibility alias - deprecated, use SchemaDetector or SchemaMigrator
2324
Migrator = SchemaDetector
2425

tests/test_json_model.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,9 @@ async def test_schema(m, key_prefix):
892892
# We need to build the key prefix because it will differ based on whether
893893
# these tests were copied into the tests_sync folder and unasynce'd.
894894
key_prefix = m.Member.make_key(m.Member._meta.primary_key_pattern.format(pk=""))
895+
# Note: EmbeddedJsonModel pk fields are not included in the schema since
896+
# embedded models don't need primary keys (they're stored as part of their
897+
# parent document, not as separate Redis keys). See GitHub issue #496.
895898
assert m.Member.redisearch_schema() == (
896899
f"ON JSON PREFIX 1 {key_prefix} SCHEMA "
897900
"$.pk AS pk TAG SEPARATOR | "
@@ -901,13 +904,9 @@ async def test_schema(m, key_prefix):
901904
"$.age AS age NUMERIC "
902905
"$.bio AS bio TAG SEPARATOR | "
903906
"$.bio AS bio_fts TEXT "
904-
"$.address.pk AS address_pk TAG SEPARATOR | "
905907
"$.address.city AS address_city TAG SEPARATOR | "
906908
"$.address.postal_code AS address_postal_code TAG SEPARATOR | "
907-
"$.address.note.pk AS address_note_pk TAG SEPARATOR | "
908909
"$.address.note.description AS address_note_description TAG SEPARATOR | "
909-
"$.orders[*].pk AS orders_pk TAG SEPARATOR | "
910-
"$.orders[*].items[*].pk AS orders_items_pk TAG SEPARATOR | "
911910
"$.orders[*].items[*].name AS orders_items_name TAG SEPARATOR |"
912911
)
913912

0 commit comments

Comments
 (0)