koxudaxi / datamodel-code-generator

Pydantic model and dataclasses.dataclass generator for easy conversion of JSON, OpenAPI, JSON Schema, and YAML data sources.
https://koxudaxi.github.io/datamodel-code-generator/
MIT License
2.45k stars 280 forks source link

Base class for main object, not for properties #1918

Open cmclaughlin opened 2 months ago

cmclaughlin commented 2 months ago

I would like to specify a base class, but not have it enabled on properties that are referenced, i.e. no base class on the properties classes.

I'm not sure if this is a usage question or not - I don't see support for this.

I am starting with JSON schema and generating data classes. The JSON schema that I am working with contains referenced fields.

Here's an example - base on https://koxudaxi.github.io/datamodel-code-generator/jsonschema/. refFieldExample is the new part.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    },
    "friends": {
      "type": "array"
    },
    "comment": {
      "type": "null"
    },
    "refFieldExample" : {
      "$ref" : "#/definitions/refFieldExample"
    }
  },
  "definitions" : {
    "refFieldExample" : {
      "type" : "object",
      "additionalProperties" : false,
      "properties" : {
        "example" : {
          "type" : "string",
          "enum" : [ "Enabled", "Disabled" ]
        }
      },
    }
  }
}

Running this

 datamodel-codegen --base-class=base.MyBase --output-model-type dataclasses.dataclass --input person.json --input-file-type jsonschema --output model.py

Results in:

# generated by datamodel-codegen:
#   filename:  person.json
#   timestamp: 2024-04-12T20:36:40+00:00

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from typing import List, Optional

from base import MyBase

class Example(Enum):
    Enabled = 'Enabled'
    Disabled = 'Disabled'

@dataclass
class RefFieldExample(MyBase):
    example: Optional[Example] = None

@dataclass
class Person(MyBase):
    firstName: Optional[str] = None
    lastName: Optional[str] = None
    age: Optional[int] = None
    friends: Optional[List] = None
    comment: None = None
    refFieldExample: Optional[RefFieldExample] = None

Is there a way for me to avoid RefFieldExample inheriting from MyBase while Person continues to inherit from MyBase?

The reason I want this in my actual application the parent constructor needs to create things for the Person object, but the RefFieldExample object is really just properties/data/input and can't share the same constructor.

I thought about trying to work around this with a custom template and extra template data to indicate which properties should inherit and which should not, but I have not gotten that working and it does not feel like a good appoach.

Thanks

koxudaxi commented 2 months ago

@cmclaughlin

I thought about trying to work around this with a custom template and extra template data to indicate which properties should inherit and which should not, but I have not gotten that working and it does not feel like a good approach.

Depending on what conditions distinguish the inheritance source from the non-inheritance source, the method I can show you now is to use the custom template you are talking about here. If you only want to operate on specific data classes, I think you can handle that.

In this way, data can be injected only into specific data classes. https://github.com/koxudaxi/datamodel-code-generator/pull/71/files#diff-7a19d9bb46b7a38df351f191f4a8b84be66f07bf0d44e00cb3ba2ed927439781R2-R4