web-dev-qa-db-ja.com

Django RESTフレームワーク?

私はREST APIを Django RESTフレームワーク とコーディングしています。APIはソーシャルモバイルアプリのバックエンドになります。チュートリアルに従って、すべてのモデルをシリアル化でき、新しいリソースを作成して更新できます。

認証にAuthTokenを使用しています。

私の質問は:

/usersリソース、アプリのユーザーが登録できるようにしたい。ですから、/registerまたは匿名ユーザーにPOST to /users新しいリソース?

また、許可に関するいくつかのガイダンスは素晴らしいでしょう。

56
chaim

私のシリアライザーはパスワードの表示/取得を期待していないため、登録を処理するために独自のカスタムビューを作成しました。/usersリソースとは異なるURLを作成しました。

私のURL conf:

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)

私は間違っているかもしれませんが、認証されていないリクエストが必要なため、このビューのアクセス許可を制限する必要はないようです...

39
Cahlan Sharp

Django REST Framework 3 allow シリアライザーのcreateメソッドをオーバーライド:

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から継承されたクラスのシリアル化されたフィールドは、Django Rest Framework v3.5 および最新の場合、Metaで特許的に宣言する必要があります。

ファイル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
66
Dunaevsky Maxim

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メソッドはパスワードがクリアテキストではなくハッシュとして保存されるようにします。

34
cpury

Django 1.5からのカスタムユーザーモデルをサポートし、応答でユーザーのIDを返すように、Cahlanの回答を更新しました。

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)
26
Chris

私は通常、ビュークラスの権限セットをPOST(別名create))でオーバーライドする以外は、承認が必要な他のAPIエンドポイントと同じようにUserビューを扱います。通常、このパターンを使用します。

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

26
digitalfoo

上記の@cpuryは、write_only_fieldsオプションの使用を提案しました。ただし、これはDRF 3.3.3では機能しませんでした。

DRF 3. ではModelSerializerのwrite_only_fieldsオプションがPendingDeprecationに移動され、 DRF 3.2 ではより一般的なextra_kwargsに置き換えられました。

extra_kwargs = {'password': {'write_only': True}}

7
Tadej Krevh

これまでのすべての回答でユーザーが作成され、ユーザーのパスワードが更新されました。これにより、2つのDB書き込みが発生します。余分な不必要な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
4
yndolok

パーティーに少し遅れましたが、これ以上コードを書きたくない人を助けるかもしれません。

これを実現するために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
2
Karan Kumar

Python 3、Django 2およびDjango RESTフレームワークビューセットベースの実装:

ファイル: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

ファイルrls.py

from rest_framework.routers import DefaultRouter
from .views import CreateUserView

router = DefaultRouter()
router.register(r'createuser', CreateUserView)

urlpatterns = router.urls
0