2016-07-30 6 views
0

Ich versuche das Tutorial von DRF und ich fand etwas verwirrt. ich ein User-Modell haben die auth.User erstreckt einfach wie diesedjango rest framework wie man benötigte Felder pro ViewSet Aktion definiert

class User(DefaultUser): 
""" 
Represents a registered User 
""" 
EMAIL_VALIDATOR_LENGTH = 6 

email_validated = models.BooleanField(default=False) 
# using a 6-digit numbers for email validation 
email_validator = models.CharField(
    max_length=6, 
    default=_get_random_email_validator(EMAIL_VALIDATOR_LENGTH), 
    editable=False 
) 
phone_number = models.CharField(validators=[phone_regex], 
           blank=True, null=True, max_length=64) 
# country is required 
country = models.ForeignKey('Country', null=False, blank=False) 
# subdivision is optional 
subdivision = models.ForeignKey('Subdivision', null=True, blank=True) 

Dann habe ich meine Grund UserSerializer:

class UserSerializer(serializers.ModelSerializer): 

class Meta: 
    model = User 
    fields = ('id', 'email', 'password', 'email_validated', 
       'email_validator', 'country', 'subdivision', 'phone_number', 
       'last_login', 'is_superuser', 'username', 'first_name', 
       'last_name', 'is_staff', 'is_active', 'date_joined') 

In meinem views.py habe ich UserViewSet:

class UserViewSet(viewsets.ModelViewSet): 
queryset = User.objects.all() 
serializer_class = UserSerializer 

@detail_route(methods=['get', 'post'], url_path='validate-email') 
def validate_email(self, request, pk): 
    user = self.get_object() 
    serializer = UserSerializer(data=request.data) 
    if serializer.is_valid(): 
     user.is_active = True 
     user.save() 
     return Response({'status': 'email validated'}) 
    else: 
     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

@detail_route(methods=['post'], url_path='set-password') 
def set_password(self, request, pk): 
    pass 

@list_route() 
def test_list_route(self, request): 
    pass 

Das Problem ist, in validate_email, ich brauche eigentlich nur pk, aber wenn ich die API testen, sagte mir, dass Benutzername und E-Mail ebenfalls erforderlich sind.

Ich fügte dann folgenden Code zu meinem UserSerializer

 extra_kwargs = {'country': {'required': False}, 
        'password': {'required': False}, 
        'username': {'required': False}, 
        } 

nun das oben genannten Problem ist weg, aber wenn ich einen Benutzer zu schaffen versucht, ich will eigentlich Benutzername und E-Mail erforderlich.

Gibt es eine Möglichkeit, dass ich angeben kann, welche Felder pro Aktion benötigt werden? Zum Beispiel, für meine set_password(), möchte ich das Passwort-Feld erfordern.

Danke,

Antwort

0

Try Serializer Konstruktor überschreiben Felder auf zusätzliche Argumente basieren zu ändern. Testete das nicht, aber es sollte funktionieren:

class UserSerializer(ModelSerializer): 

    def __init__(self, *args, **kwargs): 
     super(UserSerializer, self).__init__(*args, **kwargs) 
     require_password = kwargs.get('require_password', False) 
     require_email = kwargs.get('require_email', False) 

     if require_password: 
      self.fields['password'].required = True 

     if require_email: 
      self.fields['email'].required = True 

Dann require_password oder/und require_email Argumente übergeben, wenn Sie brauchen:

serializer = UserSerializer(data=request.data, require_password=True, require_email=True) 
+0

danke für Ihre Antwort, aber ich denke, es funktioniert nicht. Ich füge folgenden Code zu meinem UserSerializer hinzu und benötige immer noch den Benutzernamen: self.fields ['username']. Require = False –

0

Ich stellte sich heraus, es selbst zu implementieren, so dass ich im Grunde alle Felder Option, aber in Aktionen, habe ich einen Dekorator hinzugefügt, um sicherzustellen, dass der Anfragetext die angegebenen Schlüssel enthält.

Dekorateur:

class AssertInRequest(object): 
""" 
A decorator to decorate ViewSet actions, this decorator assumes the first 
positional argument is request, so you can apply this decorator any methods 
that the first positional argument is request. 

This decorator itself takes a list of strings as argument, and will check 
that the request.data.dict() actually contains these keys 

For example, if you have a action to set user password which you expect that 
in the request body should have 'password' provided, use this decorator for 
the method like 

@detail_route() 
@AssertInRequest(['password']) 
def set_password(self, request, pk): 
    pass 
""" 

def __init__(self, keys): 
    self.keys = [] 
    for key in keys: 
     if hasattr(key, 'upper'): 
      self.keys.append(key.lower()) 

def __call__(self, func): 
    def wrapped(*args, **kwargs): 
     if self.keys: 
      try: 
       request = args[1] 
      except IndexError: 
       request = kwargs['request'] 
      if request: 
       json_data = get_json_data(request) 
       for key in self.keys: 
        if key not in json_data or not json_data[key]: 
         return DefaultResponse(
          'Invalid request body, missing required data [%s]' % key, 
          status.HTTP_400_BAD_REQUEST) 
     return func(*args, **kwargs) 

    return wrapped 

Wie man es verwendet:

@detail_route(methods=['post'], url_path='set-password', permission_classes=(IsAuthenticated,)) 
@AssertInRequest(['password']) 
def set_password(self, request, pk): 
    user = self.get_object() 
    json_data = get_json_data(request) 
    user.set_password(json_data['password']) 
    user.save() 
    return DefaultResponse(_('Successfully set password for user %s' 
          % user.email), status.HTTP_200_OK) 

Ich denke, es ist nicht elegant, aber wahrscheinlich genug für mich jetzt.

Verwandte Themen