how to: creating a view and serializer for adding,

2019-06-08 23:39发布

问题:

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

回答1:

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.



回答2:

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
            })