How to return data from nested serializers inside serializers built on the fly?

梦想的初衷 提交于 2019-12-23 02:37:37

问题


Recently I have been trying out new things with Django, to try and simplify writing responses in the views, might not be worth doing in the end, but I'm still interested to see if it can be done.

So typically, we would have the following serializer for returning back information;

# serializers.py
class SomeDefinedSerializer(serializers.ModelSerializer):
    extra_model = SomeExtraModelSerializer()
    greet_name = serializers.SerializerMethodField()

    class Meta:
        model = SomeDefinedModel
        fields = ('name', 'age', 'field1', 'field2')

    def get_greet_name(self, obj):
        return f"Hello {obj.name}"

Now with this defined serializer, we can return just the fields we want, and then assumming in SomeExtraModelSerializer() we have defined a subset of fields, we get back a nice dictionary of values with calling .data.

But doing this, with large-scale apps, we will end up writing loads and loads of serializers that just get used for specific tasks, resulting in a lot of code that is almost virtual similar. Of course, we dont HAVE to do it this way, we could make more general serializers, but that means that all the different tasks from the frontend end up getting a huge surplus of information, that in reality only a small percentage of the data gets used.

So my original thought was to create a base serializer class, that all other serializers would be based off, with a custom init method, that way you can just call a serializer, and pass in as kwargs the fields you want, or exclude...

But then I thought, but this way we are still having to define serializers for certain tasks.

What about if in the django views, I could define a serializer, and its nested serializers, all with their own specific fields I want back, on the fly, which would kinda work like:

# views.py
sus = SingleUseSerializer(userdata=userdata, \
                          model=SomeDefinedModel, \
                          many=False, \
                          fields=("name", "age", "field1", "field2",))
sus.load_extra_serializer(model=SomeExtraModel, \
                          return_name="extra_model", \
                          many=False, \
                          fields=("extra_field1", "extra_field2"))
return sus.checkout(query=my_queryset)

So I wrote the basic way of how to do it, and it actually works, except that while the main serializer returns the fields I wanted, the nested serializer returns back a list of the primary_keys, that are linked to the first table via a foreign key. Obviously I want just the fields "extra_field1", "extra_field2", but I can't actually see where I am going wrong. The code is below:

class SingleUseSerializer():

    def __init__(self, userdata, model, many=False, fields=None, exclude=None):
        if not fields and not exclude:
            cprint("SingleUseSerializer: fields and exclude are both None, can only have one.", "red")
        if fields and exclude:
            cprint("SingleUseSerializer: fields and exclude are both present, can only have one.", "red")
        self.main_serializer = {
            "model": model,
            "many": many,
            "fields": fields,
            "exclude": exclude
        }
        self.extra_serializers = {}
        self.userdata = userdata

    def load_extra_serializer(self, model, return_name, many=False, fields=None, exclude=None):
        self.extra_serializers[return_name] = {
            "model": model,
            "many": many,
            "fields": fields,
            "exclude": exclude
        }

    def checkout(self, query):

        def getSerializerClass(name):
            class A(serializers.ModelSerializer):
                def __init__(self, *args, **kwargs):
                    x = kwargs.get("fields", None)
                    if x:
                        self.Meta.fields = x
                        self.Meta.exclude = None
                        del kwargs["fields"]
                    y = kwargs.get("exclude", None)
                    if y:
                        self.Meta.exclude = y
                        self.Meta.fields = None
                        del kwargs["exclude"]
                    if not x and not y:
                        self.Meta.exclude = ('updated', 'created',)
                        self.Meta.fields = None
                    super(A, self).__init__(*args, **kwargs)
                class Meta:
                    model = None
            return type(name, (A,), {})

        main_serializer_class = getSerializerClass(name="MainSerializer")

        for k, v in self.extra_serializers.items():
            inner_serializer_class = getSerializerClass(name=str(k))
            inner_serializer_class.Meta.model = v["model"]
            inst = inner_serializer_class(many=True, fields=v["fields"])
            setattr(main_serializer_class, str(k), inst)
            self.main_serializer["fields"] += (str(k),)

        main_serializer_class.Meta.model = self.main_serializer["model"]
        x = main_serializer_class(query, context={"userdata": self.userdata}, fields=self.main_serializer["fields"])
        return x.data

Thus, my question is, how to successfully return back only select fields on nested serializers inside serializers built on the fly, rather than just the pk values. NOTE, the select fields for the main serializer DO work and return back just the ones I want...

来源:https://stackoverflow.com/questions/53568714/how-to-return-data-from-nested-serializers-inside-serializers-built-on-the-fly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!