Package: django-typomatic
django-typomaticA simple solution for generating Typescript interfaces from yourDjango Rest Framework Serializers.Since I now require a simple package to generate Typescript interfaces for Django Rest Framework serializers, I've decided to port over myTypemallowpackage for use with DRF serializers!Usage:Using django-typomatic is just as simple!First, install the packagepip install django-typomaticOption 1: DecoratorsFor your Django Rest Framework serializers that you wish to generate Typescript interfaces for, simply importts_interfaceandgenerate_tsfrom thedjango_typomaticmodule, and add the@ts_interface()class decorator to your Django Rest Framework serializer class.All that is required to generate your Typescript interfaces is to call thegenerate_ts()function, and provide a filepath as a parameter to output the result.main.pyfromdjango_typomaticimportts_interface,generate_tsfromrest_frameworkimportserializers@ts_interface()classFoo(serializers.Serializer):some_field=serializers.CharField()another_field=serializers.DateTimeField()generate_ts('./output.ts')output.tsexportinterfaceFoo{some_field:string;another_field:date;}Alternatively, you can callget_ts(), which will return the generated interfaces as a raw string, rather than writing the results to a file:main.pyfromdjango_typomaticimportts_interface,get_tsfromrest_frameworkimportserializers@ts_interface()classFoo(serializers.Serializer):some_field=serializers.ListField(child=serializers.IntegerField())another_field=serializers.CharField()print(get_ts())which outputs the following string:export interface Foo {\n some_field: number[];\n another_field: string;\n}\n\ndjango-typomaticsupports nested serializers, as well as list fields and other fields that act as lists (any field with many=True)main.pyfromdjango_typomaticimportts_interface,generate_tsfromrest_frameworkimportserializers@ts_interface()classFoo(serializers.Serializer):some_field=serializers.ListField(child=serializers.IntegerField())another_field=serializers.CharField()@ts_interface()classBar(serializers.Serializer):foo=Foo()foos=Foo(many=True)bar_field=serializers.CharField()output.tsexportinterfaceFoo{some_field:number[];another_field:string;}exportinterfaceBar{foo:Foo;foos:Foo[];bar_field:string;}django-typomaticalso supports ChoiceField serializers, as well as any other serializer fields that makes use of choices.main.pyfromdjango_typomaticimportts_interfacefromrest_frameworkimportserializersfromdjango.dbimportmodelsclassActionType(models.TextChoices):ACTION1="Action1",("Action1")ACTION2="Action2",("Action2")ACTION3="Action3",("Action3")classNumberType(models.IntegerChoices):LOW=1MEDIUM=2HIGH=3@ts_interface('choices')classChoiceSerializer(serializers.Serializer):action=serializers.ChoiceField(choices=ActionType.choices)num=serializers.ChoiceField(choices=NumberType.choices)output.tsexportinterfaceActionSerializer{action:"Action1"|"Action2"|"Action3";num:1|2|3;}Extended Usage:The@ts_interface()decorator function accepts an optional parameter,context, which defaults to... well... 'default'."Why is this the case?"When a Serializer is identified with with@ts_interfacedecorator, it is added to a list in a dictionary of serializers, with the dictionary key being the value provided to thecontextparameter. If you were to provide different contexts for each serializer, additional keys will be created if they do not exist, or the serializer will simply be appended to the list at the existing key.This comes in handy, as thegenerate_ts()functionalsoaccepts an optionalcontextparameter, which will filter only serializers in the dictionary at the specific key.This is useful if you wish to output different contexts to different files, e.g.main.py...fromdjango_typomaticimportts_interface,generate_tsfromrest_frameworkimportserializers@ts_interface(context='internal')classFoo(serializers.Serializer):foo=serializers.CharField()@ts_interface(context='internal')classBar(serializers.Serializer):bar=serializers.CharField()@ts_interface(context='external')classFooBar(serializers.Serializer):foo_bar=serializers.CharField()'''we're telling django-typomatic that we only want to generate interfaces from serializers withan 'internal' context to './internal.ts''''generate_ts('./internal.ts',context='internal')'''only generate interfaces from serializers with an 'external' context to './external.ts''''generate_ts('./external.ts',context='external')internal.tsexportinterfaceFoo{foo:string;}exportinterfaceBar{bar:string;}external.tsexportinterfaceFooBar{foo_bar:string;}CamelizeYou can use django dependencies that converts the response fromsnake_casingtocamelCasing. The solution offered for this is camelize:fromdjango_typomaticimportts_interface,generate_tsfromrest_frameworkimportserializers@ts_interface()classFoo(serializers.Serializer):some_field=serializers.CharField()generate_ts('./output.ts',camelize=True)Different from the main example. The interface attributes are now camel casing.output.tsexportinterfaceFoo{someField:string;}TypeScript enums from ChoiceFieldsdjango-typomaticalso allows for generating anenumfor a ChoiceField. Theenumwill follow the naming ofModelFieldNameChoiceEnumfor a model field with the namemodel_field_name, note that the interface field still remainsmodel_field_name.main.pyfromdjango_typomaticimportts_interfacefromrest_frameworkimportserializersfromdjango.dbimportmodelsclassActionType(models.TextChoices):ACTION1="Action1",("Action1")ACTION2="Action2",("Action2")ACTION3="Action3",("Action3")classNumberType(models.IntegerChoices):LOW=1MEDIUM=2HIGH=3@ts_interface('enumChoices')classChoiceSerializer(serializers.Serializer):action=serializers.ChoiceField(choices=ActionType.choices)num=serializers.ChoiceField(choices=NumberType.choices)output.tsexportenumActionChoiceEnum{ACTION1='Action1',ACTION2='Action2',ACTION3='Action3',}exportenumNumChoiceEnum{LOW=1,MEDIUM=2,HIGH=3,}exportinterfaceEnumChoiceSerializer{action:ActionChoiceEnum;num:NumChoiceEnum;}Option 2: CLI (Preferred)Since version 2.1, you can now generate all interfaces via a CLI. This will be the preferred method going forward, as you will no longer need to decorate your serializers, or manually call thegenerate_tsfunction, resulting in less complexity overall.NOTE:In order to use the CLI, you will need to adddjango_typomatictoINSTALLED_APPS.Special thanks to @bigpe for brewing up the first version of this CLI!Usage--serializers [SERIALIZERS ...], -s [SERIALIZERS ...]
                         Serializers enumeration formats: module_name.SerializerName | module_name
   --all Generate TS types for all project serializers
   --trim, -t Trim "serializer" from type name
   --camelize, -c Camelize field names
   --annotations, -a Add js doc annotations for validations (eg. for Zod)
   --enum_choices, -ec Add choices to external enum type instead union
   --enum_values, -ev Add enum to obtain display name for choices field
   --enum_keys, -ev Add enum to obtain the choices field keys by valuesUsing the newgenerate_tsmanagement command, you can fine tune the generation of your interfaces similarly to how you would via the decorator method, with some additional functionality. For example, you can call the command with the--allflag and get all the generated types to the folder specified (they will be grouped by the application name, all external applications will be excluded, only the project applications).You can also generate modules separately, as an example,-s userwill restrict generation to all serializers in theuserapplication, and-s user.UserSerializerwill restrict generation to just theUserSerializerserializer belonging to theuserapplication.ExamplesGenerate TS foruserapp./manage.py generate_ts -s userGenerate TS for specific serializer from user app./manage.py generate_ts -s user.UserSerializerGenerate TS for many apps or serializers./manage.py generate_ts -s user.UserSerializer group role.RoleSerializer role.RoleListSerializerGenerate TS for user app with annotations, choices enums, trim serializer, camelize, enum values and custom output path./manage.py generate_ts -s user -a -ec -t -c -ev -o "./custom_folder/"