在我的Django API中,我能够成功地创建管理员用户和普通用户。这是我的模型的代码。
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
class CustomUserManager(BaseUserManager):
def create_user(self, phone, password=None, **extra_fields):
if not phone:
raise ValueError('The phone field must be set')
user = self.model(phone=phone, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, phone, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(phone, password, **extra_fields)
class Users(AbstractBaseUser, PermissionsMixin):
unique_code = models.TextField()
fname = models.TextField()
lname = models.TextField()
email = models.EmailField(unique=True)
phone = models.TextField(unique=True)
sex = models.TextField()
country = models.TextField()
date_of_birth = models.TextField()
image = models.TextField(default=None, blank=True, null=True)
district = models.TextField()
subCounty = models.TextField()
village = models.TextField()
number_of_dependents = models.TextField()
family_information = models.TextField()
next_of_kin_name = models.TextField()
next_of_kin_has_phone_number = models.IntegerField(default=None, blank=True, null=True)
next_of_kin_phone_number = models.TextField(default=None, blank=True, null=True)
pwd_type = models.TextField(default=None, blank=True, null=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
REQUIRED_FIELDS = ['unique_code', 'fname', 'lname', 'phone']
USERNAME_FIELD = 'email'
objects = CustomUserManager()
def __str__(self):
return self.phone
字符串
我使用令牌身份验证,这是我的验证代码
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.response import Response
from rest_framework import status
from digi_save_vsla_api.auth import PhoneCodeBackend
from digi_save_vsla_api.serializers import LoginSerializer
from rest_framework.authtoken.models import Token
from django.contrib.auth import get_user_model
from rest_framework.authtoken.models import Token
@csrf_exempt
def login_with_phone_unique_code(request):
if request.method == 'POST':
print('Received POST request data:', request.POST)
serializer = LoginSerializer(data=request.POST)
if serializer.is_valid():
phone = serializer.validated_data["phone"]
code = serializer.validated_data["unique_code"]
backend = PhoneCodeBackend()
user = backend.authenticate(request=request, phone=phone, unique_code=code)
print('User object: ', user)
print('User phone:', phone)
print('User code:', code)
if user is not None:
# user = get_user_model().objects.get(id=user.id)
token, created = Token.objects.get_or_create(user=user)
response_data = {
"status": status.HTTP_200_OK,
'success': True,
"Token": token.key if token else None,
'user': {
'fname': user.fname,
'lname': user.lname,
'email': user.email,
'image': user.image,
'unique_code':user.unique_code,
'phone': user.phone,
'sex': user.sex,
'country': user.country,
'date_of_birth': user.date_of_birth,
'district': user.district,
'subCounty': user.subCounty,
'village': user.village,
'number_of_dependents': user.number_of_dependents,
'family_information': user.family_information,
'next_of_kin_name': user.next_of_kin_name,
'next_of_kin_has_phone_number': user.next_of_kin_has_phone_number,
'next_of_kin_phone_number': user.next_of_kin_phone_number,
'pwd_type': user.pwd_type,
},
}
return JsonResponse(response_data, status=status.HTTP_200_OK)
else:
response = {
"status": status.HTTP_401_UNAUTHORIZED,
"message": "Invalid Email or Password",
}
return JsonResponse(response, status=status.HTTP_401_UNAUTHORIZED)
else:
response = {
"status": status.HTTP_400_BAD_REQUEST,
"message": "Bad request",
"data": serializer.errors
}
return JsonResponse(response, status=status.HTTP_400_BAD_REQUEST)
else:
response = {
"status": status.HTTP_405_METHOD_NOT_ALLOWED,
"message": "Method Not Allowed",
}
return JsonResponse(response, status=status.HTTP_405_METHOD_NOT_ALLOWED)
型
和
from django.contrib.auth import get_user_model
from rest_framework.exceptions import AuthenticationFailed
from digi_save_vsla_api.models import Users
class PhoneCodeBackend:
def authenticate(self, request, phone=None, unique_code=None):
try:
user = Users.objects.get(unique_code=unique_code)
except Users.DoesNotExist:
raise AuthenticationFailed('User not found')
# Assuming your User model has a field 'unique_code'
if user.phone != phone:
raise AuthenticationFailed('Invalid phonr number')
return user
def get_user(self, user_id):
try:
return Users.objects.get(pk=user_id)
except Users.DoesNotExist:
return None
型
当我使用管理员凭据登录时,我能够成功登录并生成令牌。但是当作为普通注册用户登录时出现问题,它引发了下面的错误。
Received POST request data: <QueryDict: {'phone': ['+256701391158'], 'unique_code': ['LGZYBL']}>
User object: +256701391158
User phone: +256701391158
User code: LGZYBL
Internal Server Error: /login-with-phone-code/
Traceback (most recent call last):
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/models/query.py", line 916, in get_or_create
return self.get(**kwargs), False
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/models/query.py", line 637, in get
raise self.model.DoesNotExist(
rest_framework.authtoken.models.Token.DoesNotExist: Token matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/backends/base/base.py", line 313, in _commit
return self.connection.commit()
sqlite3.IntegrityError: FOREIGN KEY constraint failed
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
File "/home/mcrops/Documents/digi_save_api/digi_save_vsla_api/views/auth_view.py", line 28, in login_with_phone_unique_code
token, created = Token.objects.get_or_create(user=user)
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/models/query.py", line 923, in get_or_create
return self.create(**params), True
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/transaction.py", line 263, in __exit__
connection.commit()
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
return func(*args, **kwargs)
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/backends/base/base.py", line 337, in commit
self._commit()
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/backends/base/base.py", line 313, in _commit
return self.connection.commit()
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/mcrops/Documents/digi_save_api/env/lib/python3.9/site-packages/django/db/backends/base/base.py", line 313, in _commit
return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed
[15/Nov/2023 10:05:02] "POST /login-with-phone-code/ HTTP/1.1" 500 120682
型
这是我的客户端代码
import 'package:flutter/material.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';
import 'package:omulimisa_digi_save_v2/database/constants.dart';
import 'package:omulimisa_digi_save_v2/database/getData.dart';
import 'package:omulimisa_digi_save_v2/database/getMeetings.dart';
import 'package:omulimisa_digi_save_v2/database/userData.dart';
import '/src/view/screens/start_screen.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../database/localStorage.dart';
import '../widgets/start_card.dart';
import '../widgets/user_class.dart';
import 'package:connectivity/connectivity.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class PhoneForm extends StatefulWidget {
const PhoneForm({Key? key}) : super(key: key);
@override
_PhoneFormState createState() => _PhoneFormState();
}
class _PhoneFormState extends State<PhoneForm> {
final _formKey = GlobalKey<FormState>();
final _controller = TextEditingController();
final String _initialCountry = 'UG';
final PhoneNumber _number = PhoneNumber(isoCode: 'UG');
final _passwordController = TextEditingController();
final controller = TextEditingController();
String? _country;
String? _phone;
String? _test;
Future<void> saveLoginStatus(bool isLoggedIn) async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('isLoggedIn', isLoggedIn);
}
DatabaseHelper dbHelper = DatabaseHelper.instance;
Future<List<Map<String, dynamic>>?> checkData() async {
final data = dbHelper.getUnsyncedUser();
return data;
}
Future<void> checkLoginStatus() async {
final prefs = await SharedPreferences.getInstance();
final isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
if (isLoggedIn) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const StartScreen(),
),
);
}
}
Future<void> saveUserData(User user) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString('token', user.token);
prefs.setString('userFirstName', user.firstName);
prefs.setString('userLastName', user.lastName);
// prefs.setString('token', user.token!);
}
// Retrieve user data from shared preferences
Future<void> printUserData() async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('token');
final userFirstName = prefs.getString('userFirstName');
final userLastName = prefs.getString('userLastName');
if (token != null && userFirstName != null && userLastName != null) {
print('User ID: $token');
print('User First Name: $userFirstName');
print('User Last Name: $userLastName');
} else {
print('User data not found in shared preferences.');
}
}
void showNoInternetSnackBar(BuildContext context) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text('No internet connection. Please check your network settings.'),
duration: Duration(seconds: 5), // You can adjust the duration as needed
),
);
}
@override
void initState() {
super.initState();
checkData();
checkLoginStatus();
}
Future<void> loginUser(String phoneNumber, String pinCode) async {
DatabaseHelper dbHelper = DatabaseHelper.instance;
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
showNoInternetSnackBar(context); // Show the SnackBar
return;
}
// Perform the login process if internet is available
final apiUrl = Uri.parse('${ApiConstants.baseUrl}/login-with-phone-code/');
final headers = {'Content-Type': 'application/json'};
final body = json.encode({'phone': phoneNumber, 'unique_code': pinCode});
final Map<String, String> data = {
'phone': phoneNumber,
'unique_code': pinCode,
};
print('JSON: :$body');
print('Here');
final response = await http.post(apiUrl, body: data);
if (response.statusCode == 200) {
// Parse the response data
final Map<String, dynamic> responseData = json.decode(response.body);
print('Response: $responseData');
// // Access user data and token from responseData
// String token = responseData['token'];
Map<String, dynamic> userData = responseData['user'];
// getDataGroupWithApi();
// getDataMeetingWithApi();
String token = responseData['Token'];
String code = userData['unique_code'];
await saveUserData(User(
token: token,
firstName: userData['fname'],
lastName: userData['lname'],
));
syncUserDataWithApi();
int? userId = await dbHelper.getUserIdFromUniqueCode(code);
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Welcome, ${userData['fname']} ${userData['lname']} your token is $token!'),
),
);
// print('User ID: ${userData['id']}');
print('First Name: ${userData['fname']}');
print('Last Name: ${userData['lname']}');
// String idString = userData['id'].toString();
// int userId = int.parse(idString);
print('User token: $token');
// Store the token securely
// await storage.write(key: 'token', value: token);
await saveLoginStatus(true);
await saveUserData(User(
id: userId,
token: token,
firstName: userData['fname'],
lastName: userData['lname'],
));
printUserData();
// Now you can use the token and user information as needed
// print('Token: $token');
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const StartScreen(),
),
);
} else {
// Handle errors or display appropriate messages
print('Failed to log in. Status code: ${response.statusCode}');
print('Response body: ${response.body}');
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: [
const Align(
alignment: Alignment.center,
child: StartCard(
theWidth: 500.0,
theHeight: 200.0,
borderRadius: 0,
theChild: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(
'DigiSave VSLA Mobile App',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Enter your phone number and pin to login',
style: TextStyle(
fontSize: 14,
color: Color.fromARGB(255, 0, 20, 1),
fontWeight: FontWeight.w500,
),
),
),
],
),
),
),
),
Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
elevation: 4,
margin: const EdgeInsets.symmetric(horizontal: 16),
child: Padding(
padding: const EdgeInsets.all(16),
child: InternationalPhoneNumberInput(
textStyle: const TextStyle(
color: Colors.black,
),
onInputChanged: (PhoneNumber number) {
setState(() {
_phone = number.phoneNumber;
_country = number.isoCode!;
});
},
onSaved: (PhoneNumber? number) {
if (number != null) {
print('Phone Number Saved: ${number.phoneNumber}');
_test = number.phoneNumber;
}
},
selectorConfig: const SelectorConfig(
selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
),
ignoreBlank: false,
autoValidateMode: AutovalidateMode.disabled,
selectorTextStyle: const TextStyle(color: Colors.black),
initialValue: _number,
textFieldController: controller,
formatInput: true,
keyboardType: const TextInputType.numberWithOptions(
signed: true,
decimal: true,
),
inputDecoration: const InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.black, width: 2.0),
),
),
),
),
),
const SizedBox(
height: 15,
),
Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3),
),
],
),
child: TextFormField(
controller: _passwordController,
decoration: const InputDecoration(
labelText: 'Enter Pin',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
filled: true,
fillColor: Colors.white,
labelStyle: TextStyle(
color: Color.fromARGB(255, 82, 80, 80),
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your pin';
}
return null;
},
),
),
),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
print('Phone number: $_test');
String uniqueCode = _passwordController.text;
print('Full Typed phone is: $_test');
if (_test != null) {
loginUser(_test!, uniqueCode);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Phone number is required.'),
),
);
}
}
},
style: TextButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: const Color.fromARGB(255, 1, 67, 3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0))),
child: const Padding(
padding: EdgeInsets.symmetric(
horizontal: 20.0, vertical: 12.0),
child: Text(
'Login',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
color: Colors.white),
),
),
),
),
],
),
),
],
),
);
}
}
型
请帮帮我,我不知道我做错了什么,尝试了互联网上的所有解决方案,但我不能解决它。
2条答案
按热度按时间wswtfjt71#
您遇到的错误似乎与Django API中的Token对象创建有关。具体来说,它提到了FOREIGN KEY约束失败。这通常发生在您尝试为用户创建Token对象时,但外键引用的用户不存在。
这是你的Django PhoneCodeBackend中的一个潜在问题:
字符串
问题是,您试图使用unique_code字段查找用户,但没有检查电话号码是否匹配。这可能导致具有正确unique_code的用户不是发出请求的用户的情况。
以下是更新版本:
型
这样可以确保在检索用户时同时检查电话号码和唯一代码。
此外,确保Users模型具有str方法的有效实现,因为它正在您的print语句中使用。如果没有,您可以像这样更新它:
型
进行这些更改后,请再次尝试使用普通注册用户登录,看看问题是否仍然存在。
xmjla07d2#
对于那些可能会遇到类似的错误在未来。我能够解决这个问题,手动删除我的sqlite数据库,并运行迁移