2013-08-26 9 views
10

Ho un modello Commento che quando creato può o non può creare un nuovo utente. Per questo motivo, la mia API richiede un campo password quando si crea un nuovo commento. Qui è il mio modello Commento:Aggiunta di un campo che non si trova nel modello per il serializzatore nel framework REST di Django

class Comment(models.Model): 
    commenter = models.ManyToManyField(Commenter) 
    email = models.EmailField(max_length=100) 
    author = models.CharField(max_length=100) 
    url = models.URLField(max_length=200) 
    content = models.TextField(blank=True, null=True) 
    ip = models.IPAddressField(max_length=45) 
    date = models.DateTimeField(default=datetime.now) 
    post_title = models.CharField(max_length=200) 
    post_url = models.URLField(max_length=200) 
    rating = models.IntegerField(max_length=10, default=0) 

Qui è la mia opinione API:

class CommentNewView(CreateAPIView): 
    model = Comment 
    serializer_class = CommentCreateSerializer 

ecco la mia serializzatore:

class CommentCreateSerializer(serializers.ModelSerializer): 
    commenter_pw = serializers.CharField(max_length=32, required=False) 

    class Meta: 
     model = Comment 
     fields = ('email', 'author', 'url', 'content', 'ip', 'post_title', 'post_url', 'commenter_pw') 

Qui è l'errore che sto ottenendo:

Environment: 


Request Method: POST 
Request URL: http://127.0.0.1:8000/api/comment/create/ 

Django Version: 1.5.2 
Python Version: 2.7.2 
Installed Applications: 
('commentflow.apps.dashboard', 
'commentflow.apps.commenter', 
'commentflow.apps.comment', 
'rest_framework', 
'rest_framework.authtoken', 
'django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.sites', 
'django.contrib.messages', 
'django.contrib.staticfiles', 
'django.contrib.admin', 
'django.contrib.admindocs') 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.locale.LocaleMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware') 


Traceback: 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 
    115.       response = callback(request, *callback_args, **callback_kwargs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/django/views/generic/base.py" in view 
    68.    return self.dispatch(request, *args, **kwargs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view 
    77.   return view_func(*args, **kwargs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 
    327.    response = self.handle_exception(exc) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/views.py" in dispatch 
    324.    response = handler(request, *args, **kwargs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/generics.py" in post 
    372.   return self.create(request, *args, **kwargs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/mixins.py" in create 
    50.   if serializer.is_valid(): 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/serializers.py" in is_valid 
    479.   return not self.errors 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/serializers.py" in errors 
    471.     ret = self.from_native(data, files) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/serializers.py" in from_native 
    867.   instance = super(ModelSerializer, self).from_native(data, files) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/serializers.py" in from_native 
    324.    return self.restore_object(attrs, instance=getattr(self, 'object', None)) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/rest_framework/serializers.py" in restore_object 
    852.    instance = self.opts.model(**attrs) 
File "/Users/tlovett1/.virtualenvs/commentflow/lib/python2.7/site-packages/django/db/models/base.py" in __init__ 
    415.     raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) 

Exception Type: TypeError at /api/comment/create/ 
Exception Value: 'commenter_pw' is an invalid keyword argument for this function 

risposta

9

Se qualcuno è curioso, la soluzione è quella di sostituire il metodo restore_object e aggiungere la variabile di istanza in più per l'oggetto commento dopo che è stato istanziato:

def restore_object(self, attrs, instance=None): 
     if instance is not None: 
      instance.email = attrs.get('email', instance.email) 
      instance.author = attrs.get('author', instance.author) 
      instance.url = attrs.get('url', instance.url) 
      instance.content = attrs.get('content', instance.content) 
      instance.ip = attrs.get('ip', instance.ip) 
      instance.post_title = attrs.get('post_title', instance.post_title) 
      instance.post_url = attrs.get('post_url', instance.post_url) 
      return instance 

     commenter_pw = attrs.get('commenter_pw') 
     del attrs['commenter_pw'] 

     comment = Comment(**attrs) 
     comment.commenter_password = commenter_pw 

     return comment 
+0

Oh! Mi ha aiutato, molto utile! thx – brunozrk

+0

Questo non funziona per me. Ottengo: l'oggetto 'Commento' non ha attributo 'commenter_pw' –

+0

Ok. Ho dovuto impostare write_only = True –

0

Quello che puoi fare è sovrascrivere lo pre_save o create ed estrarre lo commenter_pw dai campi di dati che vengono inviati (non è sicuro, ma probabilmente lo si può estrarre dal modulo request.POST o dopo averlo serializzato), quindi il framework non dovrebbe far sorgere l'errore.

Inoltre, se si dispone di una logica aggiuntiva, è possibile implementarlo lì prima di salvarlo (come ad esempio quello per verificare se l'utente deve essere creato o cosa).

+0

Ho provato quello e non sembra funzionare. – tlovett1

2

Grazie per la vostra risposta, mi ha un ha aiutato molto :)

Ma penso che questo è un po 'più generico, dal momento che ho ancora voglia di chiamare il metodo sulla super-classe serializer

def restore_object(self, attrs, instance=None): 
    ''' 
    we have to ensure that the temporary_password is attached to the model 
    even though it is no field 
    ''' 
    commenter_pw = attrs.pop('comment_pw', None) 
    obj = super(
     CommentCreateSerializer, self 
    ).restore_object(attrs, instance=instance) 
    if commenter_pw: 
     obj.commenter_pw = commenter_pw 
    return obj 
6

risp Precedente non ha funzionato su DRF3.0, il metodo restore_object() è ora deprecato.

La soluzione che ho usato è terribile ma non ne ho trovata una migliore. Ho messo un manichino getter/setter per questo campo sul modello, questo permette di usare questo campo come qualsiasi altro sul modello.

Ricordarsi di impostare il campo come write_only sulla definizione del serializzatore.

class Comment(models.Model): 
    @property 
    def commenter_pw(): 
     return None 

    @commenter_pw.setter 
    def commenter_pw(self, value): 
     pass 

class CommentCreateSerializer(serializers.ModelSerializer): 
    commenter_pw = serializers.CharField(max_length=32, write_only=True, required=False) 

    class Meta: 
     model = Comment 
     fields = ('email', 'author', 'url', 'content', 'ip', 'post_title', 'post_url', 'commenter_pw') 
Problemi correlati