1

I want my visitors to have function for creating and get list of Proposals.

User sends all of the data except the author of Proposal (because the auth is user himself), so I'm trying to extend request.data with request.user like this:

# proposals/views.py
class ProposalsList(ListCreateAPIView):
    permission_classes = (IsAuthenticatedOrReadOnly,)
    queryset = Proposal.objects.all()
    serializer_class = ProposalSerializer

    def post(self, request, *args, **kwargs):
         serializer = self.get_serializer(data={
            **request.data,
            "author": request.user.id,
          })
          serializer.is_valid(raise_exception=True)
          self.perform_create(serializer)
          headers = self.get_success_headers(serializer.data)
          return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

Although, I want to GET the proposals list with serialized author (user), so my serializer looks like:

# proposals/serializers.py
class ProposalSerializer(serializers.ModelSerializer):
    author = UserSerializer()
    class Meta:
         model = SeekerProposal
         fields = ('text', 'author')

The problem is that I GET users list correctly (serialized to dict), but I can't POST (create new) Proposal, because it wants to "author" be a dict (it happens because I'm using nested serializer author = UserSerializer()).

Questions:

  1. Is there a way to let view be ListCreateAPIView and author = UserSerializer() while GET list with serialized data and create proposal by request.user.id?
  2. Maybe there is another way to add authorized user to Proposal author field?

Also, this is my model:

# proposals/models.py
class Proposal(models.Model):
    text = models.TextField(blank=False, null=False)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )

Answer

User @zaidfazil helped me with solution. I needed to add just one more additional field to my serializer for author details to be shown serialized:

# proposals/serializers.py
class ProposalSerializer(serializers.ModelSerializer):
    author_details = UserSerializer(source='author', read_only=True)
    class Meta:
        model = SeekerProposal
        # author will be user id, and author_details will be serialized dict
        fields = ('text', 'author', 'author_details')

Because author is still just user id and author_details is read_only=True I will get all the data for author in GET request and can create new proposal by author=request.user.id.

One moment:

I didn't use blank=True on author field, because I must be sure that this field is not empty. So my view looks the same as I wrote it above (post on ProposalsList).

Again, thanks a lot to @zaidfazil! If I wrote something wrong please write me, I'm kind of nooby on stackoverflow.

1
  • Some kind of answer was creating new serializer called ProposalNestedSerializer that inherits my ProposalSerializer and extends author = UserSerializer(), while removing it from ProposalSerializer. So now, I'm using ProposalNestedSerializer for GET (and getting serialized author in response) and using ProposalSerializer with POST (and can create Proposals with just request.user.id) Commented Jul 24, 2017 at 18:14

1 Answer 1

1

Usual way would be defining your author field as blank=True in your models and passing the user when saving the serializer,

author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user), blank=True)

serializers.py,

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'first_name', .....)

class ProposalSerializer(serializers.ModelSerializer):
    author_details = UserSerializer(source='author', read_only=True)
    class Meta:
        model = SeekerProposal
        fields = ('text', 'author', 'author_details')

Then, in your view,

class ProposalsList(ListCreateAPIView):
    permission_classes = (IsAuthenticatedOrReadOnly,)
    queryset = SeekerProposal.objects.all()
    serializer_class = SeekerProposalSerializer

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! But theres still problems: Firstly, on GET i need a list of proposals with serialized author and on POST creating proposal with author=request.user.id (but I can't, because if I use author = UserSerializer() in ProposalSerializer it ask for object while creating) Secondly, I don't want to make author blank=True, because it's a bit danger (I need auth for lots of situations)
making author blank=True would not cause any effect, cuz assigning user will only be handled from behind the scenes. Otherwise, it'd lose the security itself, also user field is still mandatory. For your question about the author details, you could add a read_only fields in the GET request, to view the details of the existing author info. I'll update my answer shortly.
You gave me way to solve this problem! I'll describe it in my question. But two things: I need to be sure that author is not blank, so I really don't want to user blank=True and I didn't, also can you add 'author_details' to tuple in your answer for anyone else to be not confused why they getting error)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.