我正在使用Django REST框架编写REST API 。该API将成为社交移动应用程序的后端。完成本教程之后,我可以序列化所有模型,并且可以创建新资源并对其进行更新。
我正在使用AuthToken进行身份验证。
我的问题是:
获得/users资源后,我希望应用程序用户能够注册。因此,拥有像这样的单独资源/register还是允许匿名用户将其发布到/users新资源更好?
另外,有关权限的一些指导也将非常有用。
我正在使用Django REST框架编写REST API 。该API将成为社交移动应用程序的后端。完成本教程之后,我可以序列化所有模型,并且可以创建新资源并对其进行更新。
我正在使用AuthToken进行身份验证。
我的问题是:
获得/users资源后,我希望应用程序用户能够注册。因此,拥有像这样的单独资源/register还是允许匿名用户将其发布到/users新资源更好?
另外,有关权限的一些指导也将非常有用。
Answers:
因为我的序列化程序不希望显示/检索密码,所以我继续进行了自己的自定义视图来处理注册。我使该URL与/ users资源不同。
我的网址配置:
url(r'^users/register', 'myapp.views.create_auth'),
我的看法:
@api_view(['POST'])
def create_auth(request):
serialized = UserSerializer(data=request.DATA)
if serialized.is_valid():
User.objects.create_user(
serialized.init_data['email'],
serialized.init_data['username'],
serialized.init_data['password']
)
return Response(serialized.data, status=status.HTTP_201_CREATED)
else:
return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
我可能是错的,但是似乎您不需要限制此视图的权限,因为您想要未经身份验证的请求...
UserSerializer它不读/写密码。致电后is_valid(),如果有人想使用就可以了serialized.data['email'],serialized.data['username']但是密码仅在中可用serialized.init_data['password']。电子邮件和用户名参数的顺序也应该切换(至少在Django 1.6中)。或者您可以始终传递命名参数,例如User.objects.create_user(email='me@example.com', username='admin', password='admin123')
Django REST Framework 3允许create序列化程序中的override方法:
from rest_framework import serializers
from django.contrib.auth import get_user_model # If used custom user model
UserModel = get_user_model()
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = UserModel.objects.create(
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = UserModel
# Tuple of serialized model fields (see link [2])
fields = ( "id", "username", "password", )
从继承的类的序列化字段ModelSerializer必须在MetaDjango Rest Framework v3.5中明确声明和最新版本中。
文件api.py:
from rest_framework import permissions
from rest_framework.generics import CreateAPIView
from django.contrib.auth import get_user_model # If used custom user model
from .serializers import UserSerializer
class CreateUserView(CreateAPIView):
model = get_user_model()
permission_classes = [
permissions.AllowAny # Or anon users can't register
]
serializer_class = UserSerializer
在DRF 3.x中工作的最简单的解决方案:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name')
write_only_fields = ('password',)
read_only_fields = ('id',)
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
)
user.set_password(validated_data['password'])
user.save()
return user
无需其他更改,只需确保未经身份验证的用户具有创建新用户对象的权限。
write_only_fields将确保不显示密码(实际上是:我们存储的哈希值),而覆盖create方法则确保密码不是以明文形式存储,而是以哈希形式存储。
create方法添加的唯一一行是Django本机set_password方法,用于为密码生成哈希。
我通常将User视图与其他需要授权的API端点一样对待,只不过我只是使用自己的POST(也称为create)覆盖了视图类的权限集。我通常使用这种模式:
from django.contrib.auth import get_user_model
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
class UserViewSet(viewsets.ModelViewSet):
queryset = get_user_model().objects
serializer_class = UserSerializer
def get_permissions(self):
if self.request.method == 'POST':
self.permission_classes = (AllowAny,)
return super(UserViewSet, self).get_permissions()
为了达到良好的效果,以下是我通常使用的序列化程序:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = (
'id',
'username',
'password',
'email',
...,
)
extra_kwargs = {
'password': {'write_only': True},
}
def create(self, validated_data):
user = get_user_model().objects.create_user(**validated_data)
return user
def update(self, instance, validated_data):
if 'password' in validated_data:
password = validated_data.pop('password')
instance.set_password(password)
return super(UserSerializer, self).update(instance, validated_data)
djangorestframework 3.3.x / Django 1.8.x
我更新了Cahlan的答案,以支持Django 1.5中的自定义用户模型,并在响应中返回用户的ID。
from django.contrib.auth import get_user_model
from rest_framework import status, serializers
from rest_framework.decorators import api_view
from rest_framework.response import Response
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
@api_view(['POST'])
def register(request):
VALID_USER_FIELDS = [f.name for f in get_user_model()._meta.fields]
DEFAULTS = {
# you can define any defaults that you would like for the user, here
}
serialized = UserSerializer(data=request.DATA)
if serialized.is_valid():
user_data = {field: data for (field, data) in request.DATA.items() if field in VALID_USER_FIELDS}
user_data.update(DEFAULTS)
user = get_user_model().objects.create_user(
**user_data
)
return Response(UserSerializer(instance=user).data, status=status.HTTP_201_CREATED)
else:
return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
is_superuser和is_staff值。如其他示例所示,应在IMO中明确指定允许的字段。
到目前为止,所有答案都将创建用户,然后更新用户密码。这导致两次DB写操作。为避免不必要的数据库写操作,请在保存之前设置用户密码:
from rest_framework.serializers import ModelSerializer
class UserSerializer(ModelSerializer):
class Meta:
model = User
def create(self, validated_data):
user = User(**validated_data)
# Hash the user's password.
user.set_password(validated_data['password'])
user.save()
return user
晚会晚了一点,但是可能对不想编写更多代码行的人有所帮助。
我们可以使用super实现此目的的方法。
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True,
)
class Meta:
model = User
fields = ('password', 'username', 'first_name', 'last_name',)
def create(self, validated_data):
user = super(UserSerializer, self).create(validated_data)
if 'password' in validated_data:
user.set_password(validated_data['password'])
user.save()
return user
一个基于Python 3,Django 2和Django REST Framework视图集的实现:
文件:serializers.py
from rest_framework.serializers import ModelSerializers
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class UserSerializer(ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = UserModel.objects.create_user(
username=validated_data['username'],
password=validated_data['password'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
)
return user
class Meta:
model = UserModel
fields = ('password', 'username', 'first_name', 'last_name',)
文件views.py:
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from django.contrib.auth import get_user_model
from .serializers import UserSerializer
class CreateUserView(CreateModelMixin, GenericViewSet):
queryset = get_user_model().objects.all()
serializer_class = UserSerializer
文件urls.py
from rest_framework.routers import DefaultRouter
from .views import CreateUserView
router = DefaultRouter()
router.register(r'createuser', CreateUserView)
urlpatterns = router.urls