Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing One to Many Relationship in django REST framework

I have two classes person and test, where one person can have several tests. I've tried serializing this but everytime I try to add an object using

person= Person.objects.create(title="mr",name="name",address="address",city="city")

it throws the error IntegrityError: NOT NULL constraint failed: appname_person.tests_id

models.py

class Test(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    test_name = models.CharField(max_length=200,default='',blank=False)
    test_subject = models.CharField(max_length=100,default='')
    test_type = models.CharField(max_length=100,default='') 

    def __str__(self):
        return self.test_name

class Person(models.Model):
    tests = models.ForeignKey(Test)
    title = models.CharField(max_length=3,default="mr",blank=False)
    name = models.CharField(max_length=50,default='',blank=False)
    address = models.CharField(max_length=200,default='',blank=False)
    city = models.CharField(max_length=100,default='',blank=False)

    def __str__(self):
        return self.name

serializers.py

class TestSerializer(serializers.ModelSerializer):
    class Meta:
        model = Test
        fields = ('test_name','test_subject','test_type')

class PersonSerializer(serializers.ModelSerializer):

    tests = TestSerializer(many=True, read_only=True)
    class Meta:
        model = Person
        fields = ('id', 'title', 'name', 'address', 'city')
like image 553
WutWut Avatar asked Mar 14 '23 21:03

WutWut


2 Answers

Ok first of all, you got it the other way around, tests should have a foreign key pointing to the user model.

class Person(models.Model):
    title = models.CharField(max_length=3,default="mr",blank=False)
    name = models.CharField(max_length=50,default='',blank=False)
    address = models.CharField(max_length=200,default='',blank=False)
    city = models.CharField(max_length=100,default='',blank=False)

    def __str__(self):
        return self.name


class Test(models.Model):
    tests = models.ForeignKey(Person)
    date = models.DateTimeField(auto_now_add=True)
    test_name = models.CharField(max_length=200,default='',blank=False)
    test_subject = models.CharField(max_length=100,default='')
    test_type = models.CharField(max_length=100,default='') 

    def __str__(self):
        return self.test_name
like image 159
Bojan Jovanovic Avatar answered Mar 29 '23 22:03

Bojan Jovanovic


Is the error in the serializer or in your data layer? From your code it looks like the object that you are creating is throwing an error, not the serialization.

Please try this

class Person(models.Model):
    tests = models.ForeignKey(Test, null=True)
    title = models.CharField(max_length=3,default="mr",blank=False)
    name = models.CharField(max_length=50,default='',blank=False)
    address = models.CharField(max_length=200,default='',blank=False)
    city = models.CharField(max_length=100,default='',blank=False)

    def __str__(self):
        return self.name

Also take a look at the difference and use of null and blank.

EDIT

I can also see another mistake. Your ForeignKey is a ManytoOne/OneToOne relationship that means that you one person is linked to a test. However in your serializer you are defining the field test with many=True. That serializer will expect a ManyToMany field. Please adjust your serializer or

class PersonSerializer(serializers.ModelSerializer):

    tests = TestSerializer(read_only=True)
    class Meta:
        model = Person
        fields = ('id', 'title', 'name', 'address', 'city')

or adjust your model

class Person(models.Model):
    tests = models.ManyToManyField(Test)
    title = models.CharField(max_length=3,default="mr",blank=False)
    name = models.CharField(max_length=50,default='',blank=False)
    address = models.CharField(max_length=200,default='',blank=False)
    city = models.CharField(max_length=100,default='',blank=False)

    def __str__(self):
        return self.name

EDIT 2:

How to add tests to a person. I am not sure which documentation you are reading but this is how you should do it.

test1 = Test(...)
test1.save()
test2 = Test(...)
test2.save()
test3 = Test(...)
test3.save()

person = Person(....)
person.save()
person.tests.add(test1, test2)
person.tests.add(test3)

Remember to save the person before adding the tests because it will throw an exception otherwise. This must be done because the ManyToMany relation must know the id of the person object to which you are linking the tests. Please refer to this article for more documentation

like image 24
Simone Zandara Avatar answered Mar 29 '23 22:03

Simone Zandara