如何仅使用 django 后端和 post 与 django-rest-framework
How to use django only a backend and post with django-rest-framework
我将只使用 Django 作为后端。前端将使用 React 完成,不使用 django 模板。我正在使用 django-rest-framework 为我的网站创建休息 api。
我为用户做了一个序列化器。
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = (
'id', 'email', 'password', 'username', 'first_name', 'last_name', 'date_of_birth', 'gender', 'mobile_number'
)
extra_kwargs = {
'password': {'write_only': True},
'id': {'read_only': True}
}
def create(self, validated_data):
user = CustomUser.objects.create(
email=validated_data['email'],
username=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
date_of_birth=validated_data['date_of_birth'],
gender=validated_data['gender'],
mobile_number=validated_data['mobile_number']
)
user.set_password(validated_data['password'])
user.save()
return user
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
在浏览器中,当我转到 /custom/users/ 时,我可以查看用户。我还可以创建新用户,在成功注册 returns 后返回用户。如果我使用 httpie/curl.
它也有效
(djangoweb) vagrant@precise32:~$ http --json POST http://55.55.55.5/custom/users/ email="ter23minal2@gmail.com" password="terminal2123" username="t223erm" first_name="te2er" last_name="mi2nal" date_of_birth=1992-12-12 gender=2 mobile_number=66222666666336
它创建并 returns 新的用户对象。
所以我做了一个表格来注册一个我不是从 django 服务器服务的用户:
<form action="http://55.55.55.5/custom/users/" method="post" id="register-form">
<input type="text" placeholder="email" name="email"/>
...
...
<button id="post">Register</button>
</form>
和ajax到post表格。
// using the javscript Cookies library
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$('#post').click(function(event) {
event.preventDefault();
var $form = $('#register-form');
var data = $form.serialize();
$.ajax({
type: "POST",
url: "http://55.55.55.5/custom/users/",
data: JSON.stringify(data),
sucess: function() { console.log("Success!"); },
contentType: "application/json; charset=utf-8",
dataType: "json",
crossDomain:false,
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
});
现在,如果我点击按钮,问题就开始了:
- 即使我给了
event.preventDefault()
页面也会自动加载到 django 服务器的 url(即 http://55.55.55.5/custom/users/)。
- 我得到一个错误:"detail":"CSRF Failed: CSRF token missing or incorrect."
如何使用 django-rest-framework 将 post 处理到 django 服务器?对于这个问题,我没有找到任何帮助 material。你能指导我怎么做吗?谢谢。
您可以使用csrf_exempt
进行注册和登录功能。例如,这里是如何创建注册和登录 APIs。看看我如何登录API returns token。参见 http://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication。
我尝试编辑我的代码以替换为您的型号名称,但我没有对其进行测试,因此您可能需要修复我的任何拼写错误(或者让我知道以便我可以修复它们)。
class AccountViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
def get_permissions(self):
if self.request.method in permissions.SAFE_METHODS:
return (permissions.IsAuthenticated(),)
if self.request.method == 'POST':
return (permissions.AllowAny(),)
return (permissions.IsAuthenticated(), IsAccountOwner(),)
@csrf_exempt
def create(self, request):
'''
When you create an object using the serializer\'s .save() method, the
object\'s attributes are set literally. This means that a user registering with
the password \'password\' will have their password stored as \'password\'. This is bad
for a couple of reasons: 1) Storing passwords in plain text is a massive security
issue. 2) Django hashes and salts passwords before comparing them, so the user
wouldn\'t be able to log in using \'password\' as their password.
We solve this problem by overriding the .create() method for this viewset and
using Account.objects.create_user() to create the Account object.
'''
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
password = serializer.validated_data['password']
confirm_password = serializer.validated_data['confirm_password']
if password and confirm_password and password == confirm_password:
user = CustomUser.objects.create_user(**serializer.validated_data)
user.set_password(serializer.validated_data['password'])
user.save()
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response({'status': 'Bad request',
'message': 'Account could not be created with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
class APILoginViewSet(APIView):
@csrf_exempt
def post(self, request, format=None):
data = JSONParser().parse(request)
serializer = LoginCustomSerializer(data=data)
if serializer.is_valid():
email = serializer.data.get('email')
password = serializer.data.get('password')
if not request.user.is_anonymous():
return Response('Already Logged-in', status=status.HTTP_403_FORBIDDEN)
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, account)
serialized = UserSerializer(user)
data = serialized.data
# Add the token to the return serialization
try:
token = Token.objects.get(user=user)
except:
token = Token.objects.create(user=user)
data['token'] = token.key
return Response(data)
else:
return Response('This account is not Active.', status=status.HTTP_401_UNAUTHORIZED)
else:
return Response('Username/password combination invalid.', status=status.HTTP_401_UNAUTHORIZED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request, format=None):
data_dic = {"Error":"GET not supported for this command"}
return Response(data_dic, status=status.HTTP_400_BAD_REQUEST)
您可以在 https://github.com/dkarchmer/django-aws-template 查看完整的工作示例(免责声明,那是我的代码)。
希望对您有所帮助
我将只使用 Django 作为后端。前端将使用 React 完成,不使用 django 模板。我正在使用 django-rest-framework 为我的网站创建休息 api。
我为用户做了一个序列化器。
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = (
'id', 'email', 'password', 'username', 'first_name', 'last_name', 'date_of_birth', 'gender', 'mobile_number'
)
extra_kwargs = {
'password': {'write_only': True},
'id': {'read_only': True}
}
def create(self, validated_data):
user = CustomUser.objects.create(
email=validated_data['email'],
username=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
date_of_birth=validated_data['date_of_birth'],
gender=validated_data['gender'],
mobile_number=validated_data['mobile_number']
)
user.set_password(validated_data['password'])
user.save()
return user
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
在浏览器中,当我转到 /custom/users/ 时,我可以查看用户。我还可以创建新用户,在成功注册 returns 后返回用户。如果我使用 httpie/curl.
它也有效(djangoweb) vagrant@precise32:~$ http --json POST http://55.55.55.5/custom/users/ email="ter23minal2@gmail.com" password="terminal2123" username="t223erm" first_name="te2er" last_name="mi2nal" date_of_birth=1992-12-12 gender=2 mobile_number=66222666666336
它创建并 returns 新的用户对象。
所以我做了一个表格来注册一个我不是从 django 服务器服务的用户:
<form action="http://55.55.55.5/custom/users/" method="post" id="register-form">
<input type="text" placeholder="email" name="email"/>
...
...
<button id="post">Register</button>
</form>
和ajax到post表格。
// using the javscript Cookies library
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$('#post').click(function(event) {
event.preventDefault();
var $form = $('#register-form');
var data = $form.serialize();
$.ajax({
type: "POST",
url: "http://55.55.55.5/custom/users/",
data: JSON.stringify(data),
sucess: function() { console.log("Success!"); },
contentType: "application/json; charset=utf-8",
dataType: "json",
crossDomain:false,
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
});
现在,如果我点击按钮,问题就开始了:
- 即使我给了
event.preventDefault()
页面也会自动加载到 django 服务器的 url(即 http://55.55.55.5/custom/users/)。 - 我得到一个错误:"detail":"CSRF Failed: CSRF token missing or incorrect."
如何使用 django-rest-framework 将 post 处理到 django 服务器?对于这个问题,我没有找到任何帮助 material。你能指导我怎么做吗?谢谢。
您可以使用csrf_exempt
进行注册和登录功能。例如,这里是如何创建注册和登录 APIs。看看我如何登录API returns token。参见 http://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication。
我尝试编辑我的代码以替换为您的型号名称,但我没有对其进行测试,因此您可能需要修复我的任何拼写错误(或者让我知道以便我可以修复它们)。
class AccountViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
def get_permissions(self):
if self.request.method in permissions.SAFE_METHODS:
return (permissions.IsAuthenticated(),)
if self.request.method == 'POST':
return (permissions.AllowAny(),)
return (permissions.IsAuthenticated(), IsAccountOwner(),)
@csrf_exempt
def create(self, request):
'''
When you create an object using the serializer\'s .save() method, the
object\'s attributes are set literally. This means that a user registering with
the password \'password\' will have their password stored as \'password\'. This is bad
for a couple of reasons: 1) Storing passwords in plain text is a massive security
issue. 2) Django hashes and salts passwords before comparing them, so the user
wouldn\'t be able to log in using \'password\' as their password.
We solve this problem by overriding the .create() method for this viewset and
using Account.objects.create_user() to create the Account object.
'''
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
password = serializer.validated_data['password']
confirm_password = serializer.validated_data['confirm_password']
if password and confirm_password and password == confirm_password:
user = CustomUser.objects.create_user(**serializer.validated_data)
user.set_password(serializer.validated_data['password'])
user.save()
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response({'status': 'Bad request',
'message': 'Account could not be created with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
class APILoginViewSet(APIView):
@csrf_exempt
def post(self, request, format=None):
data = JSONParser().parse(request)
serializer = LoginCustomSerializer(data=data)
if serializer.is_valid():
email = serializer.data.get('email')
password = serializer.data.get('password')
if not request.user.is_anonymous():
return Response('Already Logged-in', status=status.HTTP_403_FORBIDDEN)
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, account)
serialized = UserSerializer(user)
data = serialized.data
# Add the token to the return serialization
try:
token = Token.objects.get(user=user)
except:
token = Token.objects.create(user=user)
data['token'] = token.key
return Response(data)
else:
return Response('This account is not Active.', status=status.HTTP_401_UNAUTHORIZED)
else:
return Response('Username/password combination invalid.', status=status.HTTP_401_UNAUTHORIZED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request, format=None):
data_dic = {"Error":"GET not supported for this command"}
return Response(data_dic, status=status.HTTP_400_BAD_REQUEST)
您可以在 https://github.com/dkarchmer/django-aws-template 查看完整的工作示例(免责声明,那是我的代码)。
希望对您有所帮助