Skip to content

Commit 07f48a8

Browse files
committed
fix inheriting class overwriting parents django fields
1 parent 424d314 commit 07f48a8

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

ninja/orm/metaclass.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,17 @@ def __new__(
8989
meta_conf = MetaConf.model_validate(conf_dict)
9090

9191
if meta_conf and meta_conf.model:
92+
base_model_fields = {}
93+
for base in bases:
94+
base_model_fields.update(**base.model_fields)
95+
9296
meta_conf = meta_conf.model_dump(exclude_none=True)
9397

9498
fields = factory.convert_django_fields(**meta_conf)
9599
namespace.setdefault("__annotations__", {})
96100
for field, val in fields.items():
97-
if not namespace["__annotations__"].get(field, None):
101+
# don't overwrite custom fields in annotations or previous django fields in base_model_fields
102+
if not namespace["__annotations__"].get(field, None) and not base_model_fields.get(field, None):
98103
# set type
99104
namespace["__annotations__"][field] = val[0]
100105
# and default value

tests/test_orm_metaclass.py

+72
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,75 @@ class Meta(ItemBaseModelSchema.Meta):
531531
"title": "ItemInMealsSchema",
532532
"type": "object",
533533
}
534+
535+
536+
def test_inherited_tables():
537+
class Foreign(models.Model):
538+
name = models.CharField()
539+
540+
class Meta:
541+
app_label = "tests"
542+
543+
544+
class Item(models.Model):
545+
id = models.PositiveIntegerField(primary_key=True)
546+
slug = models.CharField(blank=True, null=True)
547+
ref = models.ForeignKey(Foreign, on_delete=models.PROTECT)
548+
549+
class Meta:
550+
app_label = "tests"
551+
abstract = True
552+
553+
554+
class DiffItem(Item):
555+
special = models.CharField()
556+
557+
class Meta:
558+
app_label = "tests"
559+
560+
561+
class ForeignModelSchema(ModelSchema):
562+
class Meta:
563+
model = Foreign
564+
fields = "__all__"
565+
566+
567+
class ItemModelSchema(ModelSchema):
568+
ref: ForeignModelSchema
569+
class Meta:
570+
model = Item
571+
fields = "__all__"
572+
573+
class DiffItemModelSchema(ItemModelSchema):
574+
special: str
575+
576+
class Meta(ItemModelSchema.Meta):
577+
model = DiffItem
578+
579+
class OptionalDiffItemModelSchema(ItemModelSchema):
580+
special: str
581+
ref: Optional[ForeignModelSchema] = None
582+
583+
class Meta(ItemModelSchema.Meta):
584+
model = DiffItem
585+
586+
# assert that DiffItemModelSchema did not overwrite ItemModelSchema.ref with a 0 depth 'ref_id:integer' field
587+
j = DiffItemModelSchema.model_json_schema()
588+
assert not j["properties"].get("ref_id", None)
589+
assert j["properties"].get("ref", None)
590+
591+
# assert custom annotation can overwrite the ref field
592+
j = OptionalDiffItemModelSchema.model_json_schema()
593+
assert not j["properties"].get("ref_id", None)
594+
assert j["properties"].get("ref", None) == {
595+
'anyOf': [
596+
{
597+
'$ref': '#/$defs/ForeignModelSchema',
598+
},
599+
{
600+
'type': 'null',
601+
},
602+
],
603+
'default': None,
604+
}
605+
assert "ref" not in j["required"]

0 commit comments

Comments
 (0)