Giter Club home page Giter Club logo

django-typomatic's People

Contributors

00defeat avatar adenh93 avatar bigpe avatar biolds avatar bradwells avatar gabrielvidal1 avatar ghferrari avatar jessielaf avatar memo-indeed avatar ptevans avatar robertazzopardi avatar rrauenza avatar sjdemartini avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

django-typomatic's Issues

This project is great.

We've been using this library in production for a while now, and I just want to express my gratitude to the developer(s). It's made my work as a full-stack developer much more enjoyable. I don't have a lot of time on my hands to formally contribute to this project but I would like to just dump my hacked-together method that wraps get_ts() and writes Typescript files here, perhaps if someone finds this interesting they can distill the shortcomings I've encountered that this method works around.

from django_typomatic import (
    __field_mappings,
    __mapping_overrides,
    __serializers,
    get_ts,
)
import re, sys

# This method is called at the bottom of each of my serializers.py files
def write_typescript(file, imports=[], renames=[]):
    if (
        settings.DEBUG
        and settings.GENERATE_TYPESCRIPT_SOURCES
        and len(sys.argv) >= 2
        and sys.argv[0] == "manage.py"
        and sys.argv[1] == "runserver"
    ):
        try:
            f = open(f"/types/{file}.ts", "w") # /types is mounted (via docker) to a folder shared between backend and frontend sources, so frontend can directly use these generated files
            ts = re.sub(r"[\?]", "", get_ts()).replace('"', "'")

            for rename in renames:
                ts = ts.replace(f"{rename[0]}Serializer {{", f"{rename[1]} {{")

            ts = (
                ts.replace("Serializer", "")
                .replace(" File ", " string ")
                .replace(" File;\n", " string;\n")
                .replace(": number | string | null;\n", ": number | null;\n")
                .replace(": number | string;\n", ": number;\n")
            )

            # Allow for some customizations
            ts = re.sub(r"export interface ([_A-Za-z0-9]+) \{", r"export type \g<1> = {", ts)
            matches = re.findall(r"export type ([_A-Za-z0-9]+) = \{\n(.+?)\}\n\n", ts, re.DOTALL)
            for match in matches:
                interface_name = match[0]
                for rename in renames:
                    if interface_name == rename[1]:
                        interface_name = rename[0]
                        break

                interface_body_original = f"export type {match[0]} = {{\n{match[1]}}}\n\n"
                interface_body = interface_body_original

                for serializer in __serializers["default"]:
                    if serializer.__name__ == interface_name + "Serializer":
                        serializer_fields = serializer().fields
                        field_matches = re.findall(r"    ([a-z0-9_]+): (.+);\n", match[1])
                        for field_match in field_matches:
                            serializer_field = serializer_fields[field_match[0]]
                            if isinstance(serializer_field, serializers.ChoiceField):
                                if serializer_field.allow_blank:
                                    interface_body = interface_body.replace(
                                        f"    {field_match[0]}: {field_match[1]};\n",
                                        f"    {field_match[0]}: {field_match[1]} | '';\n",
                                    )
                            if isinstance(serializer_field, serializers.ManyRelatedField):
                                interface_body = interface_body.replace(
                                    f"    {field_match[0]}: {field_match[1]};\n",
                                    f"    {field_match[0]}: number[];\n",
                                )

                        break

                ts = ts.replace(interface_body_original, interface_body)

            f.write("/* eslint-disable prettier/prettier */\n\n")

            if imports:
                for line in imports:
                    f.write(f"{line}\n")
                f.write("\n")

            f.write(ts)
            f.close()

            __serializers.clear()
            __field_mappings.clear()
            __mapping_overrides.clear()
        except PermissionError:
            print("Unable to generate TypeScript sources")

Make readonly=true and required=false optional fields

I've rewritten and monkey patched my own instance -- but maybe you want to incorporate it as well?

def alternate_get_ts_interface(serializer, context):
    '''
    Generates and returns a Typescript Interface by iterating
    through the serializer fields of the DRF Serializer class
    passed in as a parameter, and mapping them to the appropriate Typescript
    data type.
    '''
    name = serializer.__name__
    django_typomatic._LOG.debug(f"Creating interface for {name}")
    fields = []
    if issubclass(serializer, serializers.ModelSerializer):
        instance = serializer()
        fields = instance.get_fields().items()
    else:
        fields = serializer._declared_fields.items()
    ts_fields = []
    for key, value in fields:
        ts_field = django_typomatic.__process_field(key, value, context, serializer)
        if value.read_only or not value.required:
            op = '?:'
        else:
            op = ':'
        ts_fields.append(f"    {ts_field[0]}{op} {ts_field[1]};")
    collapsed_fields = '\n'.join(ts_fields)
    return f'export interface {name} {{\n{collapsed_fields}\n}}\n\n'

ValueError when using "enumChoices" or "choices"

I am trying to generate enums for my choice fields in my models, but get a Value error when generate_ts() is called. This is also the case for the example from the README, for both "enumChoices" and "choices"

from django_typomatic import ts_interface, generate_ts
from rest_framework import serializers
from django.db import models


class ActionType(models.TextChoices):
    ACTION1 = "Action1", ("Action1")
    ACTION2 = "Action2", ("Action2")
    ACTION3 = "Action3", ("Action3")


class NumberType(models.IntegerChoices):
    LOW = 1
    MEDIUM = 2
    HIGH = 3


@ts_interface('enumChoices')
class ChoiceSerializer(serializers.Serializer):
    action = serializers.ChoiceField(choices=ActionType.choices)
    num = serializers.ChoiceField(choices=NumberType.choices)

generate_ts("some path relative to the root")

I get the following stacktrace:

Exception in thread django-main-thread:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.11/threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "/opt/venv/lib/python3.11/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/opt/venv/lib/python3.11/site-packages/django/core/management/commands/runserver.py", line 125, in inner_run
autoreload.raise_last_exception()
File "/opt/venv/lib/python3.11/site-packages/django/utils/autoreload.py", line 87, in raise_last_exception
raise _exception[1]
File "/opt/venv/lib/python3.11/site-packages/django/core/management/init.py", line 398, in execute
autoreload.check_errors(django.setup)()
File "/opt/venv/lib/python3.11/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/opt/venv/lib/python3.11/site-packages/django/init.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/opt/venv/lib/python3.11/site-packages/django/apps/registry.py", line 124, in populate
app_config.ready()
File "/app/backend/asset/apps.py", line 9, in ready
import backend.asset.serializers
File "/app/backend/asset/serializers.py", line 4, in
from config.typomatic import generate_ts_types
File "/app/config/typomatic.py", line 34, in
generate_ts_types()
File "/app/config/typomatic.py", line 8, in generate_ts_types
generate_ts("./frontend/src/drf.d.ts")
File "/opt/venv/lib/python3.11/site-packages/django_typomatic/init.py", line 219, in generate_ts
enums_string, interfaces = __get_enums_and_interfaces_from_generated(interfaces_enums)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/venv/lib/python3.11/site-packages/django_typomatic/init.py", line 196, in __get_enums_and_interfaces_from_generated
interfaces, enums = [list(tup) for tup in zip(*interfaces_enums)]
^^^^^^^^^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 0)

I am running all of this in a Docker container, but everything annotated with just ts_interface works fine

Add support for typescript uniont types

I'd like to be able to compile typescript union types. Something like what's below.

interface Bird {
  fly(): void;
  layEggs(): void;
}
 
interface Fish {
  swim(): void;
  layEggs(): void;
}

type Animal = Bird | Fish;

Create a management command to generate the .d.ts file

I have created my own custom command, and figured it could be of use to other people it currently goes through each installed app checks for serializers and will automatically apply the @ts_interafce decorator to them:

import importlib
import inspect
import os
from types import ModuleType
from django.apps import AppConfig
from django.conf import settings
from django.core.management.base import BaseCommand
from django_typomatic import ts_interface, get_ts
from rest_framework.serializers import Serializer

class Command(BaseCommand):
    EXCLUDED_APPS = ['rest_framework']
    help = 'Creates a TypeScript definition file for all models registered in DRF serializers under src/ts/@types/django-models.d.ts'

    def create_model_mappings(self, app_config: AppConfig):
        """Updates the custom mappings with related models and their type in ts"""
        mappings = {}
        for model in app_config.get_models():
            for field in model._meta.get_fields():
                if field.related_model is not None:
                    ts_type = field.related_model.__name__
                    if field.many_to_many or field.one_to_many:
                        ts_type += '[]'
                    mappings[field.name] = ts_type
        return mappings

    def handle(self, *args, **options):
        from django.apps import apps
        for app_config in apps.get_app_configs():
            if app_config.name not in self.EXCLUDED_APPS:
                self.handle_app_config(app_config)
        # Remove Serializer from type name since it's redundant in TS
        ts = get_ts().replace('Serializer', '')
        type_file_location = os.path.join(settings.BASE_DIR, 'src/ts/@types/django-models.d.ts')
        with open(type_file_location, 'w') as type_file:
            type_file.write(ts)
        self.stdout.write(self.style.SUCCESS(f'Type file sucessfully generated at {type_file_location}'))

    def handle_app_config(self, app_config: AppConfig):
        try: #Check to see the app has serializers
            serializers_module: ModuleType = importlib.import_module(app_config.name + '.serializers')
        except ImportError:
            return
        mappings = self.create_model_mappings(app_config)
        serializers = inspect.getmembers(serializers_module, lambda member: self.is_serializer(member, serializers_module))
        for name, serializer in  serializers:
            # Get the class def and apply the ts_interface decorator to it
            base_class = getattr(serializers_module, name)
            ts_interface(mapping_overrides=mappings)(base_class)
    
    def is_serializer(self, member: object, module):
        """Checks to see if the given member is a serializer class and is a part of the given module"""
        return inspect.isclass(member) and issubclass(member, Serializer) and member.__module__ == module.__name__

serializers.ChoiceField options getting converted to 'any'

Given the following code:
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from django.db import models

@ts_interface()
class ActionType(models.TextChoices):
ACTION1 = "Action1", _("Action1")
ACTION2 = "Action2", _("Action2")

@ts_interface()
class ActionSerializer(serializers.Serializer[Any]):
action = serializers.ChoiceField(choices=ActionType.choices)

The output of conversion is:
export interface ActionSerializer {
action: any; -> wrong!
}

I would expect 'action' to be a union class of 'Action1' | 'Action2' or 'ACTION1' | 'ACTION2'. Am I using django-typomatic incorrectly or is this simply a limitation of the library?

Thanks!

Use Python Enum names instead of capitalizing display names or values

Consider the following enum:

class ClassLevel(models.IntegerChoices):
    UNKNOWN = -100, "Unknown"

    UNKNOWN_FIRST_OR_LOWER = -99, "Unknown (Class 1 or lower)"

    LOWER_KINDERGARTEN = -1, "LKG"
    UPPER_KINDERGARTEN = 0, "UKG"

    FIRST = 1, "1"
    SECOND = 2, "2"
    THIRD = 3, "3"
    FOURTH = 4, "4"
    FIFTH = 5, "5"
    SIXTH = 6, "6"
    SEVENTH = 7, "7"
    EIGHTH = 8, "8"
    NINTH = 9, "9"
    TENTH = 10, "10"
    ELEVENTH = 11, "11"
    TWELFTH = 12, "12"

    UNKNOWN_TWELFTH_OR_HIGHER = 13, "Unknown (12+)"

When generating types for this I would like the enum to be created with the python enum name instead of taking the display name or value and trying to capitalize it.

Trying to capitalize display name or value and have it as a key in typescript enums leaves it with parentheses and may not be valid typescript depending on special characters.

I would like the following enum:

export enum CurrentClassChoiceEnum {
    UNKNOWN = -100,
    UNKNOWN_FIRST_OR_LOWER = -99
    ...
}

Instead of the current:

export enum CurrentClassChoiceEnum {
    UNKNOWN = -100,
    UNKNOWN_(CLASS_1_OR_LOWER) = -99,
    ...
}

Example for how to get python enum names:

choices = ClassLevel.choices
print("Python enum name,", "Value,", "Display name")
for choice in choices:
    print(ClassLevel(choice[0]).name, choice[0], choice[1])

Release 2.5.0 to pypi

๐Ÿ‘‹๐Ÿผ @adenh93

Thanks for this utility! I noticed that you dropped a new release a few days ago. Do you plan to release this onto pypi so that we can pip install the new versions and test drive it out?

Generate mypy types

It would be nice to have the option to generate mypy types in addition to TypeScript definitions.

The use case would allow you to pass around typed dictionaries in Python code that is either passed into or returned from a DRF Serializer.

process_field should also check child_relation for "many"

>virtualenv-3.6.8/lib64/python3.6/site-packages/django_typomatic/__init__.py(75)__process_field()
     74         import ipdb; ipdb.set_trace()
---> 75     is_many = hasattr(field, 'child')
     76     field_type = is_many and type(field.child) or type(field)

ipdb> field                                                                                                                                          
ManyRelatedField(child_relation=PrimaryKeyRelatedField(read_only=True, source='testdetails'), read_only=True, source='testdetails')
ipdb> field.child                                                                                                                                    
*** AttributeError: 'ManyRelatedField' object has no attribute 'child'
ipdb> field                                                                                                                                          
ManyRelatedField(child_relation=PrimaryKeyRelatedField(read_only=True, source='testdetails'), read_only=True, source='testdetails')
ipdb>                                                                                                                                                
ManyRelatedField(child_relation=PrimaryKeyRelatedField(read_only=True, source='testdetails'), read_only=True, source='testdetails')
ipdb> field.child_relation                                                                                                                           
PrimaryKeyRelatedField(read_only=True, source='testdetails')
ipdb>                      

(Pull request pending)

TypeError when used with Permission model

I really like this library for copying and pasting types into my UI (I do a find/replace for 'Serializer' and replace it with nothing and commit it to my UI codebase).

However, I'm running into a problem with the builtin Permissions model.

# serializers.py
from django.contrib.auth.models import Permission
from django_typomatic import ts_interface
from rest_framework.serializers import ModelSerializer


@ts_interface
class PermissionSerializer(ModelSerializer):
    class Meta:
        model = Permission
        fields = '__all__'
# views.py
@api_view(["GET"])
@permission_classes((permissions.IsAuthenticated,))
def get_all_permissions_for_groups(request):
    all_permissions = Permission.objects \
        .prefetch_related('group_set', 'content_type') \
        .filter(group__user=request.user
                )
    serializer = PermissionSerializer(all_permissions, many=True)
    return JsonResponse(serializer.data, safe=False)

Expected output:

[]
# or list of Permission objects of the groups I am part of

Actual output:

<SNIP>

  File "C:\Users\bradl\lji\projects\childlight_django\app\rest\permissions\views.py", line 34, in get_all_permissions
    serializer = PermissionSerializer(all_permissions, many=True)
TypeError: decorator() got an unexpected keyword argument 'many'

commenting out the @ts_interface annotation results in the expected output

Enums created when using Related Fields in more complicated models

There are some outputs produced like this:

any
export enum NumChoiceEnum {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3,
}

export enum NumChoiceEnumKeys {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3,
}

export enum StatusChoiceEnum {
    1 = '1',
    2 = '2',
    3 = '3',
    4 = '4',
    5 = '5',
    6 = '6',
}

export enum StatusChoiceEnumKeys {
    ARCHIVED = '1',
    PRE-SAVED = '2',
    SAVED = '3',
    USER'S_LIKES = '4',
    USER'S_DISLIKES = '5',
    NONE = '6',
}

export enum StatusChoiceEnumValues {
    1 = 'Archived',
    2 = 'Pre-saved',
    3 = 'Saved',
    4 = 'User\'s likes',
    5 = 'User\'s dislikes',
    6 = 'None',
}


export interface AlbumSerializer {
    id?: number;
    tracks?: TracksChoiceEnum[];
    num: NumChoiceEnum;
    album_name: string;
    artist: string;
    status: StatusChoiceEnum;
}

The "any" in the first line comes from the TracksChoiceEnum not having any database entries (thus having no choices). If there would be database entries, those would be printed as enum choices. This is undesired behavior since the database entries should not be printed as types.
This should be fixed by not checking if a field has the attribute choices but some other element (like choice_strings_to_values) which is not an attribute of a Related Field.

The produced output should look as follows:

export enum NumChoiceEnum {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3,
}

export enum NumChoiceEnumKeys {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3,
}

export enum StatusChoiceEnum {
    '1' = '1',
    '2' = '2',
    '3' = '3',
    '4' = '4',
    '5' = '5',
    '6' = '6',
}

export enum StatusChoiceEnumKeys {
    'ARCHIVED' = '1',
    'PRE-SAVED' = '2',
    'SAVED' = '3',
    'USER\'S_LIKES' = '4',
    'USER\'S_DISLIKES' = '5',
    'NONE' = '6',
}

export enum StatusChoiceEnumValues {
    '1' = 'Archived',
    '2' = 'Pre-saved',
    '3' = 'Saved',
    '4' = 'User\'s likes',
    '5' = 'User\'s dislikes',
    '6' = 'None',
}


export interface AlbumSerializer {
    id?: number;
    tracks?: any[];
    num: NumChoiceEnum;
    album_name: string;
    artist: string;
    status: StatusChoiceEnum;
}

(The models used can be found in #50)

Licensing

Hey!

Hope you're doing well. Is there any chance you'd be willing to relicense (or perhaps dual license) your package to MIT/BSD? There's a bit of an aversion at my company to using GPL on certain projects so it'd help greatly with buy in.

Thank you

Command line support for serializers in submodules

I have a serializer named MySerializer in my_app/my_submodule/serializers.py

Unfortunately, the command line is not recursive, so using ./manage.py generate_ts -s my_app does not work as my_app doesn't have a serializers.py file within it.

./manage.py generate_ts -s my_app.my_submodule also does work just as above, because the command like thinks my_submodule is the class name of the serializer.

./manage.py generate_ts -s my_app.my_submodule.serializers.MySerializer and ./manage.py generate_ts -s my_app.my_submodule.MySerializer both fail because the commandline does not expect submodules.

I would like to propose that ./manage.py generate_ts -s my_app does a recursive search for files named serializers.py and that ./manage.py generate_ts -s my_app.my_submodule should check for a python module, and if it finds one, do a recursive search for serializers.py files in that module (otherwise it would fall back to checking if my_app.serializers.py exists and has a my_submodule class name)

Allow SerializerMethodField fields to return nested iterables

In our project we have the need to create typescript interfaces for complex serializers, which include the following:

class MeteringPointSerializer(serializers.ModelSerializer):
    # some fields...

    vacancy_time_slices = serializers.SerializerMethodField()

    def get_vacancy_time_slices(self, instance) -> List[Tuple[date, date]]:
        # some implementation returning a list of tuples....

    # rest of the serializer

Trying to create typescript interface for this serializer results in the following error:

Traceback (most recent call last):
  File "/workspace/api/app/./manage_debug.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/workspace/api/.venv/lib/python3.11/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/workspace/api/.venv/lib/python3.11/site-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/workspace/api/.venv/lib/python3.11/site-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/workspace/api/.venv/lib/python3.11/site-packages/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/management/commands/generate_ts.py", line 147, in handle
    self._generate_ts(app_name, serializer_name, output, **options)
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/management/commands/generate_ts.py", line 114, in _generate_ts
    generate_ts(
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/__init__.py", line 513, in generate_ts
    interfaces_enums = __generate_interfaces_and_enums(
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/__init__.py", line 416, in __generate_interfaces_and_enums
    return [
           ^
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/__init__.py", line 417, in <listcomp>
    __get_ts_interface_and_enums(
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/__init__.py", line 373, in __get_ts_interface_and_enums
    ts_property, ts_type, ts_enum, ts_enum_value = __process_field(
                                                   ^^^^^^^^^^^^^^^^
  File "/workspace/api/.venv/lib/python3.11/site-packages/django_typomatic/__init__.py", line 248, in __process_field
    if issubclass(return_type, BaseSerializer):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class

After some debugging I discovered, that it was because of the TODO comments topic of allowing nested iterables.

It would be awesome to have support for this.

Should not use choices for PrimaryKeyRelatedField

Great library, has saved me a lot of time!

One issue I had is that it would use choices for PrimaryKeyRelatedField - populating the types with a list of every possible ID in the database. This isn't desirable because there's no reason you should be referencing database IDs in your frontend code, and even if you were, it's likely your local dev environment where you're writing this will be out of sync with production.

My workaround to this was to do this in my management command where I generate the ts:

from django_typomatic import get_ts, ts_field
from rest_framework import serializers

ts_field("number")(serializers.PrimaryKeyRelatedField)

A more permanent solution could be to add an extra elif clause before the choices check to specifically check if it is a PrimaryKeyRelatedField, and then somehow figure out the type of the pk for that field (DRF doesn't store this anywhere I can see). Alternatively we could use number | string as the type or just number since that's how Django automatically generates IDs.

Enum generation errors with Django Simple History

#33 created difficulties when combining Django Typomatic with https://github.com/jazzband/django-simple-history. This issue is because of the following;

export enum HistoryTypeChoiceEnum {
    + = '+',
    ~ = '~',
    - = '-',
}

Using the new enum_values option doesn't resolve this since the following code also is incorrect:

export enum HistoryTypeChoiceEnumValues {
    + = 'Created',
    ~ = 'Changed',
    - = 'Deleted',
}

The solution of version 1.7.0 does work since enum_choices gave:

export enum HistoryTypeChoiceEnum {
    CREATED = '+',
    CHANGED = '~',
    DELETED = '-',
}

For now, I can stick to version 1.7.0 but might be nice to give an update

KeyError: 'default' | elif field_type in __field_mappings[context]:

Had a problem in __process_field: elif field_type in __field_mappings[context]:
it was expecting the key 'default' exist in __field_mappings, but __field_mappings was populated only in ts_field.decorator which I was not using.

Solved it by adding the same population logic in ts_interface.decorator:

    def decorator(cls):
        if issubclass(cls, serializers.Serializer):
            if context not in __field_mappings:
                __field_mappings[context] = dict()
            if context not in __serializers:
                __serializers[context] = []
            __serializers[context].append(cls)

and it worked :)

I think with Serializer you should also call get_fields()

In your code, you go after _declared_fields, but the Serializer implementation actually implements get_fields(). Bypassing this method makes it difficult to derive my own Serializer that builds its own fields.

fields = serializer._declared_fields.items()

https://github.com/encode/django-rest-framework/blob/0407a0df8a16fdac94bbd08d49143a74a88001cd/rest_framework/serializers.py#L377

In other words, I think these two cases are the same and should just do the ModelSerializer method?:

    if issubclass(serializer, serializers.ModelSerializer):
        instance = serializer()
        fields = instance.get_fields().items()
    else:
        fields = serializer._declared_fields.items()

Support for older versions of Django

HI! I worked with this package for a project and it was really great all the time it saved me, now I am working on a different project that sadly has too old version of both Dango and DRF, even Python to be honest (Python ~2.7). So I was wondering if it would be too difficult to make support for older versions of Django and DRF. I've never tried to update or in this case make support for older versions of a package so I don't know if it is difficult. I really want to use this package on this project because the time it would save on creating the types would be insane.

django==1.8.19
djangorestframework==2.3.9

I also looked. for other options online because I thought that maybe there were similar packages for the same thing that supported older versions but I. didn't find anything.

Django 5.0 support

Is there Django 5.0 support planned and when if so?

17.28 ERROR: Cannot install -r /requirements.txt (line 11), -r /requirements.txt (line 12), -r /requirements.txt (line 13) and django~=5.0 because these package versions have conflicting dependencies.
17.28 
17.28 The conflict is caused by:
17.28     The user requested django~=5.0
17.28     djangorestf
[2023-12-28T09:14:42.188Z] ramework 3.14.0 depends on django>=3.0
17.28     django-cors-headers 4.3.1 depends on Django>=3.2
17.28     drf-typescript-generator 0.1.1 depends on Django<4.0.0 and >=3.2.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.