Django Rest Framework & Entity–attribute–value model (EAV) Data Model

我只是一个虾纸丫 提交于 2019-12-07 14:59:02

问题


from django.db import models

# django user
from django.contrib.auth.models import User

class Entity(models.Model):
    """
    Entity of EAV
    """
    entity = models.CharField(max_length=216,
                            null=False, default='entity_name',
                            name='entity', verbose_name='Entity of EAV',
                            db_index=True,
                            unique=True
                            )


class Asset(models.Model):
    """
    Asset of EAV
    """
    asset = models.CharField(max_length=216, null=False,
                            default='asset', name='asset',
                            verbose_name='Asset of EAV'
                            )
    entity = models.ForeignKey(to=Entity)

    class Meta:
        unique_together = ("asset", "entity")


class Value(models.Model):
    """
    Value of EAV
    """
    value = models.CharField(max_length=216,
                             null=False, default='value',
                             name='value', verbose_name='Value of EAV'
                             )
    asset = models.ForeignKey(to=Asset)
    owner = models.ForeignKey(User, verbose_name='EAV Owner', related_name='eav')

    class Meta:
        unique_together = ('value', 'asset', 'owner')

Serializers

class EntitySerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    entity = serializers.CharField(label='Entity of EAV', max_length=216, required=False)


class AssetSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    asset = serializers.CharField(default='asset', label='Asset of EAV', max_length=216)
    entity = EntitySerializer(read_only=True)


class ValueSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    value = serializers.CharField(default='value', label='Value of EAV', max_length=216)
    asset = AssetSerializer(read_only=True)
    owner = UserModelSerializer(read_only=True)


class EntityAssetValueSerializer(serializers.Serializer):
    entity = EntitySerializer(many=True)
    asset = AssetSerializer(many=True)
    value = ValueSerializer(many=True)

Expected Serialization

{
  "entities": [
    {
      "entity": "Hero",
      "id": 1,
      "owner": {
        "name": "BatMan",
        "id": "1"
      },
      "groups": [
        {
          "id": "1",
          "name": "SuperHeroes Group"
        }
      ],
      "asset": [
        {
          "asset": "Name",
          "value": "BatMan",
          "asset_id": 1,
          "value_id": 1
        },
        {
          "asset": "Age",
          "value": "30",
          "asset_id": 1,
          "value_id": 2
        }
      ]
    },
    {
      "entity": "Hero",
      "id": 1,
      "owner": {
        "name": "SuperMan",
        "id": "2"
      },
      "groups": [
        {
          "id": "1",
          "name": "SuperHeroes Group"
        }
      ],
      "asset": [
        {
          "asset": "Name",
          "value": "SuperMan",
          "asset_id": 1,
          "value_id": 3
        },
        {
          "asset": "Age",
          "value": "30",
          "asset_id": 1,
          "value_id": 4
        }
      ]
    },
    {
      "entity": "Villian",
      "id": 1,
      "owner": {
        "name": "Joker",
        "id": "3"
      },
      "groups": [
        {
          "id": "2",
          "name": "SuperVillians Group"
        }
      ],
      "asset": [
        {
          "asset": "Name",
          "value": "Joker",
          "asset_id": 3,
          "value_id": 4
        },
        {
          "asset": "Age",
          "value": "30",
          "asset_id": 4,
          "value_id": 5
        }
      ]
    },
    {
      "entity": "Person",
      "id": 1,
      "owner": {
        "name": "Puny Human",
        "id": "3"
      },
      "groups": [
        {
          "id": "2",
          "name": "Humans Group"
        }
      ],
      "asset": [
        {
          "asset": "Name",
          "value": "Human Being",
          "asset_id": 5,
          "value_id": 6
        },
        {
          "asset": "Age",
          "value": "30",
          "asset_id": 6,
          "value_id": 7
        }
      ]
    }
  ]
}

Achieved Serialization

{
  "eav": [
    {
      "id": 1,
      "value": "Human",
      "asset": {
        "id": 1,
        "asset": "Name",
        "entity": {
          "id": 1,
          "entity": "Human"
        }
      },
      "owner": {
        "id": 1,
        "username": "PunyHuman"
      }
    },
    {
      "id": 2,
      "value": "26",
      "asset": {
        "id": 2,
        "asset": "Age",
        "entity": {
          "id": 1,
          "entity": "Human"
        }
      },
      "owner": {
        "id": 1,
        "username": "PunyHuman"
      }
    },
    {
      "id": 3,
      "value": "26",
      "asset": {
        "id": 3,
        "asset": "Age",
        "entity": {
          "id": 2,
          "entity": "Hero"
        }
      },
      "owner": {
        "id": 2,
        "username": "BatMan"
      }
    },
    {
      "id": 4,
      "value": "BatMan",
      "asset": {
        "id": 3,
        "asset": "Name",
        "entity": {
          "id": 2,
          "entity": "Hero"
        }
      },
      "owner": {
        "id": 2,
        "username": "BatMan"
      }
    },
    {
      "id": 5,
      "value": "26",
      "asset": {
        "id": 3,
        "asset": "Age",
        "entity": {
          "id": 2,
          "entity": "Hero"
        }
      },
      "owner": {
        "id": 3,
        "username": "SuperMan"
      }
    },
    {
      "id": 6,
      "value": "SuperMan",
      "asset": {
        "id": 4,
        "asset": "Name",
        "entity": {
          "id": 2,
          "entity": "Hero"
        }
      },
      "owner": {
        "id": 3,
        "username": "SuperMan"
      }
    }
  ]
}

API View

class EntityAssetValueAPIView(APIView):

    queryset = Value.objects.select_related('asset', 'asset__entity', 'owner')
    serializer_class = ValueSerializer

    # If you want to use object lookups other than pk, set 'lookup_field'.
    # For more complex lookup requirements override `get_object()`.
    lookup_field = 'pk'
    # lookup_url_kwarg = None

    # The filter backend classes to use for queryset filtering
    # filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

    # The style to use for queryset pagination.
    # pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    # def allowed_methods(self):
    #     http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    #     return http_method_names
    def get(self, request, *args, **kwargs):
        eav = self.queryset.all()
        serializer = self.serializer_class(eav, many=True)
        return Response(serializer.data)

What I want to do is, Get all the ENTITIES Assigned to a USER ( along with the ASSET & VALUES ).

The same data is posted for a NEW ENTITY ASSIGNMENT to USER .

From What I understood from DRF, I would need an API view, API view would call serializer, so, I would have to create a custom Serializer, then to save the data I have to override create method, where in I will have these separate serializers that would validate the data and save it.

I am not able to send the desired RESPONSE or ingest the REQUEST coming in.

What should be a way forward ?


回答1:


I have faced the similar problem So I'll explain a little scenario here. So you can take reference from that.

Added some related names in models :

class Asset(models.Model):
    """
    Asset of EAV
    """
    asset = models.CharField(max_length=216, null=False,
                            default='asset', name='asset',
                            verbose_name='Asset of EAV'
                            )
    entity = models.ForeignKey(to=Entity, related_name='asset_entity')

class Value(models.Model):
    """
    Value of EAV
    """
    value = models.CharField(max_length=216,
                             null=False, default='value',
                             name='value', verbose_name='Value of EAV'
                             )
    asset = models.ForeignKey(to=Asset, related_name='asset_value')
    owner = models.ForeignKey(User, verbose_name='EAV Owner', related_name='eav')

initial queryset looks like this, the idea is to fetch all information that is required initially:

 queryset = Entity.objects.filter('**condition comes here**')
                .values('id', 'entity', 'asset_entity', 'asset_entity__asset', 'asset_entity__asset_value', 'asset_entity__asset_value__value',
                    'asset_entity__asset_value__owner_id',)

Pass this queryset when trying to make response :

serializer = serializer(queryset, many=True, context={'request': request})

Serailizers :

class Owner_Serializer(serializers.ModelSerializer)

        class Meta:
            model = User
            exclude = ('**exclude fields you want to exclude**', )


class EntitySerializer(serializers.Serializer):

        id = serializers.IntegerField(source='id')
        entity = serializers.CharField(source='entity')
        owner =  serializers.SerializerMethodField()
        groups =  serializers.SerializerMethodField()
        asset =  serializers.SerializerMethodField()


        def get_owner(self, obj):
            return Owner_Serializer(obj.get('asset_entity__asset_value__owner_id'), context=self.context).data

Same process goes for groups and asset fields.

in get_owner() we have entity object and from that object we can get owner_id , as we have already fetched related data initially.

So the main idea here to fetch all data initially and then serilaize that data according to your requirement.

Existing Nested Serailization do not support the response format you required.

Note : Initial querset is vry important , you may need to use prefetch related there because we are fetching data using reverse relationship. Also I didn't test the queryset so have to make sure that correct related_names are used to fetch related data.



来源:https://stackoverflow.com/questions/36735911/django-rest-framework-entity-attribute-value-model-eav-data-model

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