简体   繁体   中英

Django/Rest Framework Nest Serialization

I'm having a bit of trouble with implementing the serialization for my server. It is a host to demonstrate homomorphic encryption. Storage on the server consists of integers (really two integer tuples (X,q)), which are tied to a single set, sets are tied to sessions, sessions are tied to users... sets & sessions can both be posted. Posting a set includes the user_id, session_id and multiple integers in the request. Posting a set includes the user_id, session_id, then multiple sets in the request. Also, for a set the server generates an ID and sets that value for all integers in the set, and includes it in the response. Ideally, the user_id and session_id are going to be put in once in either type of request. So for a session post, each set does not have the user_id, session_id, but for a set post the set does have those values.

For get requests, similar idea... one instance of user_id, session_id, and this time set_id because it was created in the post. A user can request a set or session in the GET request as well.

I understand the basic idea of serialization, but I have trouble when nesting comes into play. I scoured the web and found a few articles/tutorials (ex, https://cheat.readthedocs.io/en/latest/django/drf_serializers.html ) and tried to string together some stuff, with no luck.

models.py, any reference to Token is the device token auth from Django rest_framework.

class Session(models.Model):
    session_id = models.CharField(max_length=40,primary_key=True) # pk
    user_id = models.ForeignKey(Token,on_delete=models.CASCADE) # foreign key from token 

class Set(models.Model):
    set_id = models.CharField(max_length=40,primary_key=True) # primary key, not null
    session_id = models.ForeignKey(Session,on_delete=models.CASCADE)
    
class Integer(models.Model):
    class Meta:
        unique_together = (("set_id","index"),) 
        # Django/DRF offer no multi-field PK, so
        # will use autogenerated PK, then utilize
        # uniqueness 

    set_id = models.ForeignKey(Set,on_delete=models.CASCADE)
    index = models.IntegerField(default=0)
    X = models.IntegerField(default=0)
    q = models.IntegerField(default=0)

    def __str__(self):
        return "%s[%d]" % (self.set_id,self.index)

serializers.py

class IntegerSerializer(serializers.ModelSerializer):
    user_id =  serializers.CharField(required=False,allow_blank=False)
    session_id = serializers.CharField(required=False,allow_blank=False)
    
    set_id = serializers.CharField(required=False,allow_blank=False) # max length needed?
    
    index = serializers.IntegerField(required=False,min_value=0) # cap set size w/ max_value? 
    X = serializers.IntegerField(required=True)
    q = serializers.IntegerField(required=True)
    
    class Meta:
        model = Integer
        fields = '__all__' 



class SetSerializer(serializers.ModelSerializer):
    user_id = serializers.CharField(required=False,allow_blank=False)
    session_id = serializers.CharField(required=False,allow_blank=False)  
    set_id =  serializers.CharField(required=False,allow_blank=False)
    
    integer =  IntegerSerializer(many=True)

    def create(self, validated_data):
        str_index = list(self.validated_data.keys())[-1] 
        integer_data = self.validated_data[str_index]
        if str_index == "user_id" or str_index == "session_id":
            return super().create(validated_data) 

        integer_serializer = IntegerSerializer(data=integer_data)
        
        integer_serializer.is_valid(raise_exception=True)
        
        serializer.validated_data['user_id'] = validated_data['user_id']
        serializer.validated_data['session_id'] = validated_data['session_id']
        serializer.validated_data['set_id'] = validated_data['set_id']
        serializer.validated_data['index'] = int(str_index)
        
        integer_serializer.save()
        
        validated_data[str_index] = integer_serializer.save()
        instance = super().create(validated_data)
        return instance 

    class Meta:
        depth = 1
        model = Set
        fields = '__all__'

# exclusively for grabbing user_id and session_id
class SessionInfoSerializer()
    user_id = serializers.CharField(required=True,allow_blank=False)
    session_id = serializers.CharField(required=True,allow_blank=False)
    class Meta: 
        model = Session
        fields '__all__'


class SessionSerializer(serializers.ModelSerializer):
    user_id = serializers.CharField(required=True,allow_blank=False)
    session_id = serializers.CharField(required=True,allow_blank=False)  
    
    sets = SetSerializer(many=True)

    class Meta:
        depth = 2 
        model = Session
        fields = '__all__' 

Thank you for any help!

  1. Currently in your models, session.user_id will actually return a Token object then the actual id will be in session.user_id_id .

    So in SessionSerializer the user_id field is actually returning a Token object instead of string.

    When you have a field django.db.models.ForeignKey in a model, you actually have two properties that you can access in the model instance. So for instance you have this model:

     class User(models.Model): profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    You have user.profile and user.profile_id . user.profile will return a Profile object while user.profile_id will return the foreign key id that is stored in the database


  1. In SessionSerializer , you have a sets . You have to assign the related_name of Set.session_id :
     class Set(models.Model): session_id = models.ForeignKey(Session,on_delete=models.CASCADE, related_name="sets")
    otherwise accessing the reverse one-to-many will be set to the default session.set_set ( <model_name>_set ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM