I am having a very hard time connecting all the documentation on django and django rest framework on how to create a view and serializer that allows for a foreign key.
edit:
I might have an answer here:
http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
Example I have these models.
class SearchCity(models.Model):
city = models.CharField(max_length=200)
class SearchNeighborhood(models.Model):
city = models.ForeignKey(SearchCity, on_delete=models.CASCADE)
neighborhood = models.CharField(max_length=200)
I want to be able to choose a city and then view all the neighborhoods that city has, and be able to add a neighborhood, edit and neighborhood and delete a neighborhood.
so perhaps the url to get all the neighborhoods a city has or create a new neighborhood for a city
url(r'^neighborhood/(?P<citypk>[0-9]+)$', SearchNeighborhoodListCreate.as_view()),
and one to edit and delete a neighborhood:
url(r'^neighborhood/(?P<citypk>[0-9]+)/(?P<neighborhoodpk>[0-9]+)$',SearchNeighborhoodDetail.as_view()),
I am currently using the ListCreateAPIView
and the RetreiveUpdateDestoryAPIView
from DRF Generics
I understand that we have options like query_setrelated
that allow us to get all the relations a model has.
I know we have the x_set
option. used like this in my example. Searchcity.SearchNeighborhood_set.all()
I know we have related serializers
and that the proper way I create them is such:
class CityNeighborhoodSerializer(serializers.ModelSerializer):
neighborhood = serializers.PrimaryKeyRelatedField(many=True, read_only=False)
class Meta:
model = SearchCity
fields = ('City', 'neighborhood')
But how do I use it in this use case?
http://www.django-rest-framework.org/api-guide/relations/#serializer-relations
There is a good reference on getting all objects in a relation the link is here
http://gregblogs.com/tlt-how-to-retrieve-the-fields-of-a-related-model-from-a-django-rest-framework-endpoint/
but does that work with editing, deleting, objects that are related?
Ultimately I have a done alot of research but I am asking help on filling in the cracks and really understanding this thing. This is a common use case and I am sure many of you have done it before.
edit:
It looks like this question indirectly answers mine but I am still not sure. I am going to keep looking at it and test it out. See what I find.
Deletion objects that is used as foreign key
Here are my thoughts on this:
Urls:
url(r'^city/(?P<city_pk>[0-9]+)/neighborhood/', SearchNeighborhoodListCreateView.as_view()),
url(r'^city/(?P<city_pk>[0-9]+)/neighborhood/(?P<pk>[0-9]+)$', SearchNeighborhoodDetailView.as_view()),
Since every city has one or more neighborhoods
Serializers:
Just create a serializer for SearchNeighborhood
like this:
class NeighborhoodSerializer(serializers.ModelSerializer):
class Meta:
model = SearchNeighborhood
fields = ('id', 'city', 'neighborhood')
if you want the list of neighborhoods in your city api you can use this:
class CityNeighborhoodSerializer(serializers.ModelSerializer):
neighborhoods = NeighborhoodSerializer(many=True, source='searchneighborhood_set.all')
class Meta:
model = SearchCity
fields = ('city', 'neighborhoods')
I suggest having a related name on SearchNeighborhood
model in the city
fields, eg.: related_name='neighborhoods'
, then you can use source='neighborhoods.all'
, it's more readable.
Views:
The trick here is to get only the neighborhoods related to a city
class SearchNeighborhoodListCreateView(generics.ListCreateAPIView):
queryset = SearchNeighborhood.objects.all()
serializer_class = NeighborhoodSerializer
def get_city(self):
queryset = SearchCity.objects.all()
return get_object_or_404(queryset, pk=self.kwargs['city_pk'])
def get_queryset(self):
city = self.get_city()
return super().get_queryset().filter(city=city)
def perform_create(self, serializer):
city = self.get_city()
serializer.save(city=city)
Hope you get the main idea.
Here I go answering my own question again...
The best way was to create my own view for creating and getting objects by city.
# create and get list of Search Neighborhood objects by city
class CityNeighborhoodsListCreate(APIView):
# this get request gets all the neighborhoods by city
def get (self, request, format=None, *args, **kwargs):
citypk = kwargs.get('citypk', None)
city = get_object_or_404(SearchCity,pk=citypk)
neighborhoods = city.searchneighborhood_set.all()
serialized = SearchNeighborhoodSerializer(neighborhoods, many=True)
return Response({
'neighborhoods': serialized.data
})
def post(self, request, *args, **kwargs):
citypk = kwargs.get('citypk', None)
city=get_object_or_404(SearchCity,pk=citypk)
serialized = SearchNeighborhoodSerializer(data=request.data)
if serialized.is_valid(raise_exception=True):
validatedData = serialized.validated_data
neighborhood = validatedData.get('neighborhood')
neighborhoodobject = SearchNeighborhood(neighborhood= neighborhood, city = city)
neighborhoodobject.save()
createdneighborhood = SearchNeighborhoodSerializer(neighborhoodobject)
return Response({
'neighborhood': createdneighborhood.data
})