Search code examples
pythondjangodjango-rest-frameworkdjango-fixtures

Django fixtures and AttributeError: 'QuerySet' object has no attribute <custom_model_method>


I am seeing this error with a simple integration test. The django app is called storageadmin with a model called Disk with a custom model method called pool_name. I am using South and django rest framework and have SOUTH_TESTS_MIGRATE = False in settings.py

The fixture is created with this command. The default database is populated with a few models by the app prior to dumpdata, just enough for testing.

./bin/django dumpdata storageadmin oauth2_provider auth.User --indent=2 > src/rockstor /storageadmin/fixtures/storageadmin.json

The error concerns the following model

class Disk(models.Model):
    pool = models.ForeignKey(Pool, null=True, on_delete=models.SET_NULL)
    name = models.CharField(max_length=10, unique=True)    

def pool_name(self, *args, **kwargs):
    try:
        return self.pool.name
    except:
        return None

class Meta:
    app_label = 'storageadmin'

There is a serializer which is used in a view to send the response

class DiskInfoSerializer(serializers.ModelSerializer):
    pool_name = serializers.CharField(source='pool_name')

    class Meta:
        model = Disk

The View returns a response like so

ds = DiskInfoSerializer(Disk.objects.all())
return Response(ds.data)

EDIT: As indicated in the correct answer, the problem is in the above view. I was using a very old DRF(2.1.15) but the version currently being tested(2.4.3) requires ds = DiskInfoSerializer(Disk.objects.all(), many=True)

The simple test case triggering the error is:

class DiskTests(APITestCase):
    fixtures = ['storageadmin.json']
    BASE_URL = '/api/disks/scan'

    def test_disk_scan(self):
        self.client.login(username='admin', password='admin')
        response = self.client.post(self.BASE_URL, data=None, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

And finally, the error is

File "/opt/rock-dep/src/rockstor/storageadmin/views/disk.py", line 88, in _scan
    return Response(ds.data)
File "/opt/rock-dep/eggs/djangorestframework-2.4.3-py2.7.egg/rest_framework   /serializers.py", line 572, in data
    self._data = self.to_native(obj)
File "/opt/rock-dep/eggs/djangorestframework-2.4.3-py2.7.egg/rest_framework/serializers.py", line 351, in to_native
    value = field.field_to_native(obj, field_name)
File "/opt/rock-dep/eggs/djangorestframework-2.4.3-py2.7.egg/rest_framework/fields.py", line 336, in field_to_native
    return super(WritableField, self).field_to_native(obj, field_name)
File "/opt/rock-dep/eggs/djangorestframework-2.4.3-py2.7.egg/rest_framework/fields.py", line 207, in field_to_native
    value = get_component(value, component)
File "/opt/rock-dep/eggs/djangorestframework-2.4.3-py2.7.egg/rest_framework/fields.py", line 58, in get_component
    val = getattr(obj, attr_name)
AttributeError: 'QuerySet' object has no attribute 'pool_name'

The code works fine, the problem is only while testing it.


Solution

  • Like the error says, you're passing a queryset, but you're not telling DRF that's what you're doing. You need to pass many=True:

    ds = DiskInfoSerializer(Disk.objects.all(), many=True)