invalid literal for int() with base ten in listAPI

2019-08-02 22:49发布

问题:

I am using a view in django rest framework. In this view it takes an argument city to then fetch a list a neighborhoods in that city.

the example of the url looks like this:

http://127.0.0.1:8000/api/neighborhood-list/chicago/

the url code looks like this:

url(r'neighborhood-list/(?P<city>[a-zA-Z]+)/', VenueFilterOptionsView.as_view()),

the view:

class NeighborhoodListView(generics.ListAPIView):
lookup_field = 'city'

def list(self, request, city):
    self.city = city
    queryset = Neighborhood.objects.filter(city=self.city)
    serializer = NeighborhoodSerializer(queryset, many=True)

the serializer:

class NeighborhoodSerializer(serializers.ModelSerializer):
    class Meta:
        model = Neighborhood
        fields = 'neighborhood'

the model:

class  Neighborhood(models.Model):
city = models.ForeignKey(City, null=True)
neighborhood = models.CharField(max_length=150, null=False)

what I don't understand is I set the lookup field to city, unless that only works for instances not lists? And even so I am using the listAPIView generic

the exception location is here:

    /home/rickus/211hospitality/suitsandtables/backend/venv/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py in get_prep_value, line 966

and the code on line 966 is the following:

def get_prep_value(self, value):
        value = super(AutoField, self).get_prep_value(value)
        if value is None:
            return None
        return int(value)

the return value of this method in the init folder being referenced by the stack trace is being cast as an int every time. SO I guess now the question is how do we override this nonsense or work around it.

so now I am working my way back trying to figure out what is going on.

anyone have any ideas?

回答1:

Update - My original answer was incorrect. List view doesn't actually work with the lookup_field and lookup_url_kwarg attributes, those attributes are used by Rest Frameworks DetailView in the get_object(self) method to retrieve a single instance using those lookup fields.

I've updated the answer so it overrides the get_queryset(self) method to return the correctly filtered list. This is how ListView should be customised.


It looks like you haven't defined your ListView properly. The problem seems to be that you are trying to filter on the Cities Primary Key, which is an integer field, using a string that can't be parsed as an integer. I'll write up how I think your view should look presuming your trying to do your filtering based on some field on the City model.

# models.py
class City(models.Model):
    name = models.CharField(max_length=32)

class Neighbourhood(models.Model):
    city = models.ForeignKey(City)

# views.py
class NeighbourhoodListView(generics.ListAPIView):
    queryset = Neighbourhood.objects.all()
    serializer_class = NeighbourhoodSerializer

    def get_queryset(self):
        return self.queryset.filter(city__name=self.kwargs.get('city')

# urls.py
urlpatterns = [
    url(
        r'^neighbourhood-list/(?P<city>[a-zA-Z]+)/$',
        NeighbourhoodListView.as_view(),
        name='neighbourhood-list',
    )
]

This will filter your Neighbourhoods by the Cities name. If you want to filter Neighbourhoods by the cities Primary Key, then you should use:

# views.py
class NeighbourhoodListView(generics.ListAPIView):
    queryset = Neighbourhood.objects.all()
    serializer_class = NeighbourhoodSerializer

    def get_queryset(self):
        return self.queryset.filter(city=self.kwargs.get('city'))

# urls.py
urlpatterns = [
    url(
        r'^neighbourhood-list/(?P<city>\d+)/$',
        NeighbourhoodListView.as_view(),
        name='neighbourhood-list',
    )
]

This fixes the view and url's to filter Neighbourhoods by the Cities Primary Key. This would be more performant because it doesn't need to perform a join between City and Neighbourhood.