使用Django rest框架生成自定义令牌

使用Django rest框架生成自定义令牌,django,django-rest-framework,token,python-3.6,Django,Django Rest Framework,Token,Python 3.6,我目前正在为uni项目构建API。我在以自定义方式生成身份验证令牌时遇到问题。让我解释一下:我应该在端点中接收POST请求,并具有以下内容: { "university_id": 1, "coords":{ "latitude": 0.0, "longitude": 0.0 } } 其思想是,给定大学id和坐标,后端将对其进行验证(检查坐标是否在有效区域内),然后返回如下标记: { "token": asdfsagag23214,

我目前正在为uni项目构建API。我在以自定义方式生成身份验证令牌时遇到问题。让我解释一下:我应该在端点中接收POST请求,并具有以下内容:

{
   "university_id": 1,
    "coords":{
        "latitude": 0.0,
        "longitude": 0.0
    }
}
其思想是,给定
大学id
坐标
,后端将对其进行验证(检查坐标是否在有效区域内),然后返回如下标记:

{
    "token": asdfsagag23214,
}
如您所见,没有涉及登录凭据(也没有客户端应用程序的用户模型),因此我猜测我需要创建一个自定义令牌。我查阅了Django REST框架文档,为我的令牌模型找到了类似的内容:

class AuthToken(models.Model):
    key = models.CharField(verbose_name='Key', max_length=40, primary_key=True)
    created = models.DateTimeField(
        verbose_name='Creation date', auto_now_add=True)

    class Meta:
        verbose_name = 'Token'
        verbose_name_plural = 'Tokens'

    def save(self, *args, **kwargs):
        if not self.key:
            self.key = self.generate_key()
        return super().save(*args, **kwargs)

    def generate_key(self):
        return binascii.hexlify(os.urandom(20)).decode()

    def __str__(self):
        return self.key
然后,它是序列化程序:

class AuthTokenSerializer(serializers.Serializer):
    class Meta:
        model = AuthToken
        fields = ('key', 'created', )

    def to_internal_value(self, data):
        university = data.get('university')
        coords = data.get('coords')

        if not university:
            raise serializers.ValidationError({
                'university': 'This field is required.'
            })
        if not coords:
            raise serializers.ValidationError({
                'coords': 'This field is required.'
            })

        # coordinate validation goes here

        return {
            'university': int(university),
            'coords': coords
        }

    def create(self, validated_data):
        return AuthToken.objects.create(**validated_data)
最后,
视图.py

@api_view(['POST'])
def generate_token(request):
    if request.method == 'POST':
        serializer = AuthTokenSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
我不确定我遗漏了什么,但我无法确定我需要做什么才能使它正常工作。现在我正在使用swagger来测试它,它在任何方式、形状或形式下都不起作用,没有参数可输入,甚至使用cURL via terminal似乎也不能给我预期的结果

对于记录,我使用的是
Django 2.1
Django Rest框架3.8.2


我将非常感谢任何帮助,以及对这段代码的进一步评论(毕竟我还在学习)。我猜我遗漏了一些方法,但不确定在哪里。

我将一步一步地进行

首先,您需要为coords定义一个序列化程序,因为获取和验证用户输入的标准方法是通过序列化程序。因此:

class Coordinates(serializers.Serializer):
    latitude = serializers.FloatField(min_value=-90, max_value=90)
    longitude = serializers.FloatField(min_value=-180, max_value=180)
因此,我想,为字段设置最小值和最大值可以进行足够的验证。如果您想对该字段进行更多验证,可以使用

其次,将
serializer.ModelSerializer
用于
AuthTokenSerializer
,然后将此字段添加到其中:

    coords = Coordinates(write_only=True)
并使其只写

您还可以使用以下方法获得大学:

    university = serializers.PrimaryKeyRelatedField(queryset=University.objects.all(), write_only=True)
到目前为止,您的序列化程序应该如下所示:

class AuthTokenSerializer(serializers.ModelSerializer):
    university = serializers.PrimaryKeyRelatedField(queryset=University.objects.all(), write_only=True)
    coords = Coordinates(write_only=True)

    class Meta:
        model = AuthToken
        fields = ('key', 'created', 'coords', 'university')
在下一步中,您应该使
创建的
只读,因为您不想从用户输入中获取它们的值,您只想在创建
AuthToken
实例后向用户显示它们的值。因此,将它们添加到Meta类中的
只读字段中

在下一步中,您应该重写序列化程序
validate
方法,并基于多个字段进行验证(

检查坐标是否在有效区域内

)

最后,您将看到序列化程序如下所示:

class AuthTokenSerializer(serializers.ModelSerializer):
    university = serializers.PrimaryKeyRelatedField(queryset=University.objects.all(), write_only=True)
    coords = Coordinates(write_only=True)

    class Meta:
        model = AuthToken
        fields = ('key', 'created', 'coords', 'university')
        read_only_fields = ('key', 'created')


    def validate(self, attrs):
        ### the the validation here, something like this
        ### you can access the selected university instance: attrs['university']

        if attrs['coords']['latitude'] < attrs['university']:# blah blah blah, anyway you want to validate
            raise serializers.ValidationError({'coords': ['invalid coords']})

        return super().validate(attrs)


    def create(self, validated_data):
        ###  your AuthToken does not have this field, you should pop university and coords
        ###  out before createing an instance of Authtoken
        validated_data.pop('university')
        validated_data.pop('coords')

        return super().create(validated_data)
类AuthTokenSerializer(serializers.ModelSerializer):
university=serializers.PrimaryKeyRelatedField(queryset=university.objects.all(),write_only=True)
坐标=坐标(仅写=真)
类元:
model=AuthToken
字段=('key','created','coords','university')
只读字段=('key','created')
def验证(自身、属性):
###这里的验证是这样的
###您可以访问所选大学实例:attrs['university']
如果attrs['coords']['latitude']
这就成功了。我试图准确地找到如何插入所需的验证,但我不知道我需要为坐标创建一个单独的序列化程序。谢谢。
    def create(self, validated_data):
        ###  your AuthToken does not have this field, you should pop university and coords
        ###  out before creating an instance of Authtoken
        validated_data.pop('university')
        validated_data.pop('coords')

        return super().create(validated_data)
class AuthTokenSerializer(serializers.ModelSerializer):
    university = serializers.PrimaryKeyRelatedField(queryset=University.objects.all(), write_only=True)
    coords = Coordinates(write_only=True)

    class Meta:
        model = AuthToken
        fields = ('key', 'created', 'coords', 'university')
        read_only_fields = ('key', 'created')


    def validate(self, attrs):
        ### the the validation here, something like this
        ### you can access the selected university instance: attrs['university']

        if attrs['coords']['latitude'] < attrs['university']:# blah blah blah, anyway you want to validate
            raise serializers.ValidationError({'coords': ['invalid coords']})

        return super().validate(attrs)


    def create(self, validated_data):
        ###  your AuthToken does not have this field, you should pop university and coords
        ###  out before createing an instance of Authtoken
        validated_data.pop('university')
        validated_data.pop('coords')

        return super().create(validated_data)