posting a List using Django Rest Frameworks

2019-08-26 00:06发布

问题:

New to using DRF. Curious as to what approaches some of you have used regarding storing a List.... I tried to implement the newly added ListField but I was not able to get it working. I'm using MySql as the db. I figured there was a DRF-specific way of achieving this.

For example, say this is the expected output:

{
    "somenames": ["james", "jim"],
    "somekey": "username",
}

models.py

class StringListField(serializers.ListField):
    child = serializers.CharField()

class SomeClass(models.Model):
    somenames = StringListField,
    somekey =  models.CharField(max_length=140, default='username')


    def publish(self):
        self.save()

    def __str__(self):
        return self.somekey

serializers.py

class MentionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Mention
        fields = ('somekey', 'somenames')

One option I could implement is just storing the List as a seperate table then reflecting them in the table I need them to nest them in with Foreign Key or ManyToManyField. Thanks for any suggestion.

回答1:

I use this

deep_link = serializers.ListSerializer(child=serializers.CharField())

it's basically a shortcut of yours. The problem with your code is that you are confusing Models with Serializers. The Model is the database representation of your data. The model does not specify serializers. The serializer is the serialized representation of your model coming from the DB, used mostly for data transfer.

class SomeClass(models.Model):
    somenames = StringListField
    somekey =  models.CharField(max_length=140, default='username')

here, you are telling your model that your Django model's field "somenames" is of type serializers.ListSerializers. That is not what you want. If you want to link a model to a list of strings you need to create a ManyToMany relationship or whatever you need. Below an example

class Name(models.Model):
    name = models.CharField(max_length=100)

class SomeClass(models.Model):
    somekey = models.CharField(max_length=100)
    somenames = models.ManyToManyField(Names)

Then in your serializers you will have

class NameSerializer(serializers.ModelSerializer):
    name = serializers.CharField()

class SomeClassSerializer(serializers.ModelSerializer):
    somenames = NameSerializer(many=True)
    somekey = serializers.CharField()

    class Meta:
        model = SomeClass


回答2:

Ok so after delving into the DRF documentation, along with the help of @xbirkettx answer, I was able to achieve the result I wanted:

in models.py Create your models. I set a ForeignKey relationship to the parent class (in this case the Mention class)

class Mention(models.Model):
     ...


class Hashtag(models.Model):
    mention = models.ForeignKey(Mention, related_name='hashtags')
    tagname = models.CharField(max_length=100)

    class Meta:
        unique_together = ('mention', 'tagname')

    def __unicode__(self):
        return '%s' % (self.tagname)

in serializers.py Create the serializers for the item in the List (Hashtag) for read/write you need to define to_internal_value method

class HashListingField(serializers.RelatedField):  
    def to_internal_value(self, data):
        tagname = data
        return {
            'tagname': tagname
        }
    def to_representation(self, value):
        return value.tagname

be sure to add the queryset argument to the serializer for write access

class MentionSerializer(serializers.ModelSerializer):
    hashtags = HashListingFieldSerializer(many=True, queryset=Hashtag.objects.all())
    class Meta:
        model = Mention


    def create(self, validated_data):
        tags_data = validated_data.pop('hashtags')
        mention = Mention.objects.create(**validated_data)
        for tags_data in tags_data:
            Hashtag.objects.create(mention=mention, **tags_data)
        return mention