2016-07-30 56 views
0

我正在尝试DRF的教程,并且发现了一些困惑。 我有一个简单的扩展auth.User这样django rest框架如何定义每个ViewSet操作需要的字段

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) 

然后,我有我的基本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') 

在我的views.py,我有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 

问题是,在validate_email中,我实际上只需要pk,但是当我测试API时,它告诉我用户名和电子邮件也是必需的。

我加入以下代码,以我的UserSerializer

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

现在上面的问题没有了,但是当我试图创建一个用户,其实我想需要用户名和电子邮件。

有没有一种方法可以指定每个操作需要哪些字段? 例如,对于我的set_password(),我想要求密码字段。

谢谢,

回答

0

尝试重写序列化构造函数以基于额外参数修改字段。没有测试,但它应该工作:

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 

然后通过require_password或/和require_email参数时,您需要:

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

感谢您的回复,但我认为它不起作用。我将下面的代码添加到我的UserSerializer中,它仍然需要用户名:self.fields ['username']。require = False –

0

,我变成了实现它自己,所以我基本上让所有领域选项,但在动作中,我添加了一个装饰器来确保请求主体具有指定的键。

装饰:

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 

如何使用它:

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

我想这是不优雅,但可能足以让我现在。

相关问题