2016-01-07 28 views
6

Voglio salvare un modello semplice con Django REST Framework. L'unico requisito è che UserVote.created_by sia impostato automaticamente nel metodo perform_create(). Ciò non riesce con questa eccezione:Django REST Framework: "Questo campo è richiesto." con required = False e unique_together

{ 
    "created_by": [ 
     "This field is required." 
    ] 
} 

Suppongo che sia a causa dell'indice unique_together.

models.py:

class UserVote(models.Model): 
    created_by = models.ForeignKey(User, related_name='uservotes') 
    rating = models.ForeignKey(Rating) 

    class Meta: 
     unique_together = ('created_by', 'rating') 

serializers.py

class UserVoteSerializer(serializers.ModelSerializer): 
    id = serializers.IntegerField(read_only=True) 
    created_by = UserSerializer(read_only=True) 

    class Meta: 
     model = UserVote 
     fields = ('id', 'rating', 'created_by') 

views.py

class UserVoteViewSet(viewsets.ModelViewSet): 
    queryset = UserVote.objects.all() 
    serializer_class = UserVoteSerializer 
    permission_classes = (IsCreatedByOrReadOnly,) 

    def perform_create(self, serializer): 
     serializer.save(created_by=self.request.user) 

Come posso salvare il mio modello in DRF, senza dover all'utente di fornire created_by e invece imposta questo campo automaticamente nel codice?

Grazie in anticipo!

risposta

5

Ho avuto un problema simile e l'ho risolto creando e passando esplicitamente una nuova istanza al serializzatore. Nella UserVoteViewSet devi sostituire perform_create con create:

def create(self, request, *args, **kwargs): 
    uv = UserVote(created_by=self.request.user) 
    serializer = self.serializer_class(uv, data=request.data) 
    if serializer.is_valid(): 
     serializer.save() 
     return Response(serializer.data, status=status.HTTP_201_CREATED) 
    else: 
     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 
+1

Questo è pulito! Funziona come un fascino! Grazie mille per il suggerimento! –

+0

importazioni mancanti. – Nisk

2

L'altro modo strano che puoi fare è segnali uso come questo

@receiver(pre_save, sender=UserVote) 
def intercept_UserVote(sender, instance, *args, **kwargs): 
    import inspect 
    for frame_record in inspect.stack(): 
     if frame_record[3]=='get_response': 
      request = frame_record[0].f_locals['request'] 
      break 
    else: 
     request = None 

    instance.pre_save(request) 

Quindi in pratica si possono definire pre_save nel modello

def pre_save(self, request): 
    # do some other stuff 
    # Although it shouldn't happen but handle the case if request is None 
    self.created_by = request.user 

Il vantaggio di questo sistema è che è possibile utilizzare lo stesso bit di codice per ogni modello. Se devi cambiare qualcosa cambia semplicemente in pre_save(). È possibile aggiungere più cose pure