Search code examples
pythondjangotastypie

Django Tastypie returns multiple instances when filtering relationships


I'm able to successfully query a one-to-many relationship by filter, but instead of just getting one single record with the matching objects, I get the same record repeated for every matching filtered object.

For example, if one restaurant has many inspections matching my filter, then Tastypie returns one instance of the restaurant with every matching score.

Is there any way to get a single record back even if it has multiple matching objects?

Query

http://test.com:8000/restaurants/api/restaurants/?format=json&onlinereports__insp_score__lte=35

models.py

class Restaurant(models.Model):
    rest_permit = models.IntegerField(primary_key=True, verbose_name='Permit', db_index=True)
    rest_name = models.CharField(max_length=200, verbose_name='Name', db_index=True)

    class Meta:
        ordering = ['rest_name']
        select_on_save = True


class OnlineReport(models.Model):
    insp_rest_permit = models.ForeignKey(Restaurant, null=False, to_field='rest_permit', related_name='onlinereports', db_index=True)
    insp_score = models.DecimalField(verbose_name='Score', decimal_places=2, max_digits=5, db_index=True, null=True)

    class Meta:
        ordering = ['insp_date']
        select_on_save = True

resources.py

class OnlineReportResource(ModelResource):

    class Meta:
        queryset = OnlineReport.objects.all()
        resource_name = 'onlinereports'
        filtering = {
            'insp_score': ALL,
        }

class RestaurantResource(ModelResource):

    class Meta:
        queryset = Restaurant.objects.all()
        resource_name = 'restaurants'
        filtering = {
            'onlinereports': ALL_WITH_RELATIONS,
        }

    onlinereports = fields.ToManyField(
        OnlineReportResource,
        'onlinereports',
        null=True,
        full=True
    )

Example return:

{
limit: 20,
next: null,
offset: 0,
previous: null,
total_count: 2
},
objects: [
    {
    onlinereports: [
        {
            id: 2526,
            insp_score: "11.00"
        },
        {
            id: 47882,
            insp_score: "-7.00"
        },
        {
            id: 47880,
            insp_score: "94.00"
        }
    ],
    rest_name: "Restaurant A",
    rest_permit: 2037
    },
    {
    onlinereports: [
        {
            id: 2526,
            insp_score: "11.00"
        },
        {
            id: 47882,
            insp_score: "-7.00"
        },
        {
            id: 47880,
            insp_score: "94.00"
        }
    ],
    rest_name: "Restaurant A",
    rest_permit: 2037
    }
]   

Desired return:

{
limit: 20,
next: null,
offset: 0,
previous: null,
total_count: 1
},
objects: [
    {
    onlinereports: [
        {
            id: 2526,
            insp_score: "11.00"
        },
        {
            id: 47882,
            insp_score: "-7.00"
        },
        {
            id: 47880,
            insp_score: "94.00"
        }
    ],
    rest_name: "Restaurant A",
    rest_permit: 2037
    }
]   

SOLUTION Adding .distinct() to the RestaurantResource() queryset worked:

class RestaurantResource(ModelResource):

    class Meta:
        queryset = Restaurant.objects.all().distinct()
        resource_name = 'restaurants'
        filtering = {
            'onlinereports': ALL_WITH_RELATIONS,
        }

Solution

  • Use distinct() for your queryset. This eliminates duplicate rows from the query results.

    queryset = OnlineReport.objects.all().distinct()