ManyToMany validation issue.

37 views
Skip to first unread message

Jenna Pullen

unread,
Aug 10, 2016, 7:17:01 AM8/10/16
to Django REST framework
Hi Guys,

I have a m2m relationship (Question - Category) validation issue that I have solved but I am not sure if there is a better way or if I am missing some info from the docs. I have a form that posts a question that has a multi select with existing categories. When I come to save the question in QuestionSerializer my validate_category in CategorySerializer which checks to make sure that the category does not already exist is raising the exception because it does already exist. Which is good when I am actually creating categories in the database, not using an existing one when posting a question. My solution is to just perform the validation in the actual create method instead of the validate_category in CategorySerializer so that I can save a question with existing categories and still check that the category is unique when actually creating a new one?

Tom Christie

unread,
Aug 10, 2016, 8:15:53 AM8/10/16
to Django REST framework
If would inspect `self.instance` in your validate method. If it exists then an update is being performed and you can exclude `self.instance.pk` from the queryset against which you perform the "does this already exist". This way around any validation errors will be checked during the `is_valid` call, rather than during `.save()`.

Jenna Pullen

unread,
Aug 10, 2016, 8:28:46 AM8/10/16
to Django REST framework
Thanks Tom, I'll give that a try.

Jenna Pullen

unread,
Aug 10, 2016, 4:37:34 PM8/10/16
to Django REST framework
Hi Tom,

Unfortunately I think our wires are a little crossed. Your response helps with PUT requests for updates but I still have the validate_category being called when I am creating a new Question and posting existing categories to be added to that question with the Question form. If I move the validation to the save then I can get past the issue. If you picture a form with a question input box and category multi select filled with existing categories. Then when I post the question to save a new question, the new question and existing categories get posted and I then save the question and apply each category to the question. However because I have a validate_category method on the CategorySerializer this seems to be called because I presume it expects that I could be creating new categories at the same time instead of using existing ones posted? Is there a way around this issue? I will post the code so you can get a better picture.

<code>
class CategorySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Category
        fields = ('pk', 'category', 'user', 'url')
       
    user = serializers.ReadOnlyField(source='user.username')
   
    def validate_category(self, category):
        if self.instance is not None:
            #update
            category_exists = Category.objects.filter(user=None,
                                                      category__iexact=category)
        else:
            #insert
            category_exists = Category.objects.filter(Q(user=self.context['request'].user) | Q(user=None),
                                                      category__iexact=category)
        if category_exists:
                raise serializers.ValidationError({'category': 'Category %s already exists.'
                                                   % category})
        return category

class QuestionSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Question
        fields = ('pk', 'question', 'user', 'url', "categories")

    categories = CategorySerializer(many=True)   
    user = serializers.ReadOnlyField(source='user.username')
   
    def create(self, validated_data):
        categories = validated_data.pop('categories', None)
        question = Question.objects.create(**validated_data)
       
        if categories:
            for category in categories:
                try:
                    # Check if user category already exists and use it.
                    c = Category.objects.get(user=self.context['request'].user,
                                             **category)
                except Category.DoesNotExist:
                    # Check if default category already exists and use it.
                    c = Category.objects.get(user=None,
                                             **category)
                except Category.DoesNotExist:
                    # Category does exist, create new one.
                    c = Category.objects.create(user=self.context['request'].user,
                                                **category)
                question.categories.add(c)
        return question

</code>

Jenna Pullen

unread,
Aug 11, 2016, 4:29:25 PM8/11/16
to Django REST framework
Anyone come across this before?


On Wednesday, 10 August 2016 14:15:53 UTC+2, Tom Christie wrote:

Xavier Ordoquy

unread,
Aug 13, 2016, 7:54:45 AM8/13/16
to Django REST framework
Nested serializers don't work with html forms at the moment. Started to work on this is this is still work in progress.

Regards,
Xavier,
Linovia.

Jenna Pullen

unread,
Aug 13, 2016, 8:23:06 AM8/13/16
to Django REST framework
Thank you for clearing that up for me.
Reply all
Reply to author
Forward
0 new messages