JWT generated token is invalid - flask

Here is the Flask app
import jwt
from datetime import datetime, timedelta
from flask import Flask, request, jsonify, make_response
from flask_socketio import SocketIO, send
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'myrandomsecretkey'
print(app.config['SECRET_KEY'])
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
def token_required(f):
#wraps(f)
def decorated(*args, **kwargs):
token = None
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
if not token:
return jsonify({'message': 'Token is missing!'}), 401
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
current_user = User.query.filter_by(public_id=data['public_id']).first()
except:
return jsonify({'message': 'Token is invalid!'}), 401
return f(current_user, *args, **kwargs)
return decorated
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
first_name = db.Column(db.String(30))
last_name = db.Column(db.String(40))
first_name = db.Column(db.String(30), nullable=False)
date_joined = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
password = db.Column(db.String(80))
def __repr__(self):
return f"User('{self.first_name}', '{self.last_name}')"
#app.route('/user_registration', methods=['POST'])
def create_user():
data = request.get_json()
hashed_password = generate_password_hash(data['password'], method='sha256')
new_user = User(first_name=data['first_name'],
last_name=data['last_name'], password=hashed_password, username=data['username'])
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'new_user_created'})
#app.route('/login', methods=['POST'])
def login():
auth = request.authorization
if not auth.password:
return make_response('Authentication credentials were not provided', 418)
user = User.query.filter_by(username=auth.username).first()
if not user:
return jsonify({'message': 'No user found'})
if check_password_hash(user.password, auth.password):
token = jwt.encode({'username': user.username, 'exp': datetime.utcnow() +
timedelta(minutes=30)}, app.config['SECRET_KEY'])
print(token)
return jsonify({'token': token})
return jsonify({'message': 'No user found'})
#app.route('/user', methods=['GET'])
#token_required
def get_all_users(current_user):
print(current_user)
if not current_user.admin:
return jsonify({'message': 'Cannot perform that function!'})
users = User.query.all()
output = []
for user in users:
user_data = {}
user_data['username'] = user.username
user_data['first_name'] = user.first_name
user_data['last_name'] = user.last_name
output.append(user_data)
return jsonify({'users': output})
After logging in I get the token and when I use in request in Postamn I put it in headers, the key is x-access-token and put the generated token as value but every this I get this error message
"message": "Token is invalid!"
I copied the the authorization part from a tutorial and they were decoding the token before returning it like this
return jsonify({'token' : token.decode('UTF-8')})
when I decode it it returns error saying that I can't decode a string.
This is the tutorial from which I got most parts
https://www.youtube.com/watch?v=WxGBoY5iNXY
So what's the poblem here?

Related

Upon email verification endpoint I'm getting an Invalid token error while trying to activate a user with tokens sent to the mail?

from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from rest_framework_simplejwt.tokens import RefreshToken
class UserManager(BaseUserManager):
def create_user(self,username,email, password=None ):
if username is None:
raise TypeError("Users should have a username")
if email is None:
raise TypeError("Users should have an Email")
user =self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError("Password should not be none")
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=100, unique=True, db_index=True)
email = models.EmailField(max_length=100, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
objects = UserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
"refresh":str(refresh),
"access": str(refresh.access_token)
}
Below is the serializers.py file
from .models import User
from rest_framework import serializers
from django.contrib import auth
from rest_framework.exceptions import AuthenticationFailed
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=50, min_length=6, write_only =True)
class Meta:
model = User
fields = ["email", "username", "password"]
def validate(self, attrs):
email = attrs.get("email", '')
username = attrs.get("username", '')
if not username.isalnum():
raise serializers.ValidationError("The username should contain only alphanumeric characters")
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class EmailVerificationSerializer(serializers.ModelSerializer):
token = serializers.CharField(max_length=555)
class Meta:
model = User
fields = ["token"]
class LoginSerializer(serializers.ModelSerializer):
email = serializers.EmailField(max_length=255,min_length=3)
password = serializers.CharField(max_length=68, min_length=6, write_only=True)
username = serializers.CharField(max_length=255,min_length=3, read_only=True)
tokens = serializers.CharField(max_length=68, min_length=6,read_only=True)
class Meta:
model = User
fields = ["email", "password","username","tokens"]
def validate(self,attrs):
email = attrs.get("email", "")
password = attrs.get("password", "")
user = auth.authenticate(email=email, password=password)
if not user:
raise AuthenticationFailed("Invalid Credentials, try again")
if not user.is_active:
raise AuthenticationFailed("Account disabled, contact admin")
if not user.is_verified:
raise AuthenticationFailed("Email is not verified")
return super().validate(attrs,{
"email":user.email,
"username": user.username,
"tokens":user.tokens
})
Below is the views.py file
**from django.shortcuts import render
from rest_framework import generics, status, views
from .serializers import EmailVerificationSerializer, RegisterSerializer, LoginSerializer
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken, AccessToken
from .models import User
from .utils import Util
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
from django.conf import settings
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import jwt**
# Create your views here.
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data= serializer.data
user = User.objects.get(email=user_data["email"])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse("email-verify")
absurl= "http://" + current_site + relativeLink + "?token="+ str(token)
email_body ="Hi "+ user.username + " Use link below to verify your email \n" + absurl
data = {"email_body":email_body,"to_email":user.email, "email_subject":"Verify your email"}
Util.send_email(data)
return Response(user_data, status=status.HTTP_201_CREATED)
class VerifyEmail(views.APIView):
serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
#swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY)
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Below is the utils.py for sending a mail
from django.core.mail import EmailMessage
class Util:
#staticmethod #We'll use the class method without instantiating it
def send_email(data):
email =EmailMessage(
subject=data["email_subject"], body=data["email_body"], to=[data["to_email"]])
email.send()
Below is the urls.py
from django.urls import path
from .views import RegisterView, VerifyEmail, LoginAPIView
urlpatterns = [
path("register/", RegisterView.as_view(), name="register"),
path("email-verify/", VerifyEmail.as_view(), name="email-verify"),
path("login/", LoginAPIView.as_view(), name="login")
]
Below is the verification mail sent
A verification mail sent
Below are the error gotten while trying to verify the token
A screenshot image description
at VerifyEmailView class the payload needs the algorithm with which you decode your token.`class VerifyEmail(views.APIView):
serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
#swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms='HS256')
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)`

Drf how to: simple-jwt authenticating without the USERNAME_FIELD

I have extended the TokenObtainPairSerializer, my user model has the email as the USERNAME_FIELD but this type of user does not have an email instead I want to use an auto-generated unique id to authenticate in place of the email.
class MyTokenStudentSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
user = authenticate()(
student_id=attrs['student_id'], password=attrs['password'])
if user is not None:
if user.is_active:
data = super().validate(attrs)
refresh = self.get_token(self.user)
refresh['student_id'] = self.user.student_id
try:
data["refresh"] = str(refresh)
data["access"] = str(refresh.access_token)
data['student_id'] = self.user.student_id
data['firstname'] = self.user.firstname
data['middlename'] = self.user.middlename
data['lastname'] = self.user.lastname
data['phone'] = self.user.phone
data['last_login'] = self.user.last_login
data['joined_date'] = self.user.joined_date
except Exception as e:
raise serializers.ValidationError(
{'error': 'Something Wrong!'})
return data
else:
raise serializers.ValidationError(
{'error': 'Account is not activated'})
else:
raise serializers.ValidationError({
'error': 'Incorrect student id and password combination!'})
even tho i don't pass an email field this takes email and password, how do i get it to take the student_id instead of the email.
You can override the username_field as follows:
Also be careful of using PasswordField, which trims whitespace by default. You definitely do not want password to be valid.
from rest_framework import serializers
rest_framework_simplejwt.serializers import PasswordField
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenStudentSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['student_id'] = serializers.CharField(required=False)
self.fields['password'] = PasswordField(trim_whitespace=False)
username_field = 'student_id'
auth_fields = ['student_id']

DJANGO + JWT TOKEN AUTHENTICATION

So I was trying to build a backend for my Android application. I was trying to apply a login procedure that works with JWT Token
This is what I have done :
I have made a custom User model.
Customize my superuser to take phone number and password, instead of username and password
I have successfully created superuser and store it in my database (using postgreSQL).
I have also customize my token claims and response as seen in my serializers.py of class LoginSerializer.
However, I encounter some problem after what I did :
Right now, after customizing my user model, I was not able to login to Django administration with my new custom made User model, even though I have succesfully created a superuser.
I still can't get the token even after I have made a customization for my token claims, with the success superuser account I just created.
Here are some of the error message :
Here are the some of the files attatched below :
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager
from django.utils.translation import ugettext_lazy as _
from phone_field import PhoneField
class RegisterUserManager(BaseUserManager):
def create_user(self, phone_number,password):
if not phone_number:
raise ValueError('The phone number must be set')
user = self.model(
phone_number=phone_number,
password = password,)
user.save(using = self._db)
return user
def create_superuser(self,phone_number,password, **extra_fields):
user = self.create_user(
phone_number,
password = password
)
user.is_admin = True
user.save(using= self._db)
return user
class RegisterUser(AbstractBaseUser):
first_name = models.CharField(name = 'first_name',max_length=255,default = '')
last_name = models.CharField(name='last_name', max_length=255,default = '')
email = models.EmailField(name='email', max_length = 255)
phone_number = PhoneField(name='phone_number',unique=True)
birthday = models.DateField(name ='birthday',null= True)
nickname = models.CharField(max_length=100,name = 'nickname')
is_active = models.BooleanField(default = True)
is_admin = models.BooleanField(default= False)
last_login = models.DateTimeField(auto_now= True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELDS = []
objects = RegisterUserManager()
def __str__(self):
return self.phone_number
def has_perm(self, perm, obj = None):
return True
def has_module_perms(self,perm,obj = None):
return True
#property
def is_staff(self):
return self.is_admin
views.py
from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from rest_framework.parsers import JSONParser
from restaccount.models import RegisterUser
# Login
from restaccount.serializers import RegisterSerializers,LoginSerializer
# LoginSerializers
from django.views.decorators.csrf import csrf_exempt
from rest_framework.generics import CreateAPIView
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.permissions import (AllowAny,IsAuthenticated)
# from rest_framework.generics import CreateAPIView
class RegisterView(CreateAPIView):
permission_classes = (AllowAny,)
serializer_class = RegisterSerializers
queryset = RegisterUser.objects.all()
class LoginView(TokenObtainPairView):
serializer_class = LoginSerializer
serializers.py
from rest_framework.serializers import (ModelSerializer,ValidationError)
from restaccount.models import RegisterUser
# Login
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
class RegisterSerializers(ModelSerializer):
class Meta:
model = RegisterUser
fields =['id',
'first_name',
'last_name',
'email',
'password',
'phone_number',
'nickname',
'birthday',
]
def create(self,validated_data):
first_name = validated_data['first_name']
last_name = validated_data['last_name']
email = validated_data['email']
password = validated_data['password']
phone_number = validated_data['phone_number']
nickname = validated_data['nickname']
birthday = validated_data['birthday']
user_obj = RegisterUser(
first_name = first_name,
last_name = last_name,
email = email,
password = password,
phone_number = phone_number,
nickname = nickname,
birthday = birthday,
)
user_obj.save()
return user_obj
def update(self, instance,validated_data):
instance.first_name = validated_data.get('first_name',instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.email = validated_data.get('email', instance.email)
instance.password = validated_data.get('password', instance.password)
instance.phone_number = validated_data.get('phone_number', instance.phone_number)
instance.nickname = validated_data.get('nickname', instance.nicknames)
instance.birthday = validated_data.get('birthday',instance.birthday)
instance.save()
return instance
def validate(self,data):
return data
def validate_phone_number(self,value):
phone_number = value
user_qs = RegisterUser.objects.filter(phone_number = phone_number)
if user_qs.exists():
raise ValidationError("This phone number is registered")
return value
class LoginSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls,user):
token = super().get_token(user)
token['phone_number'] = user.phone_number
token['password'] = user.password
return token
def validate(self,attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data['refresh'] = str(refresh)
data['access'] = str(refresh.access_token)
data['phone_number'] = self.user.phone_number
return data
Turns out that the password field in the model have to be hashed such that
user.set_password(password). This is also the same case, if you want to create a user from the API endpoint. You have to store the hashed password in your database.
However, I don't know why this is the behaviour.

This problem "duplicate key value violates unique constraint" has been real pain on my ass for nearly a week

I am trying to create a video blog where users will be able to create their own account and profile. I have also added email verification for registration. But the problem is when I try to register a new user using Django 2.2.5 development server I get this error ( "duplicate key value violates unique constraint" "account_profile_mobile_number_key" DETAIL: Key (mobile_number)=() already exists. ) repeatedly. I thought if I delete the database this might solve the problem. I deleted the database and create another one. Then I have been able to create one user but again that problem occurred. I deleted the database again. This way, I have tried so many times but couldn't able to solve the problem. I googled for the solution and got lot of answers but they are very tough for me to understand as I am just in the learning process. I am using Python 3.6, Django 2.2.5, Postgresql 11 on Ubuntu 18.04. Guys could you please see my codes and show me the easiest way to solve the problem? Thanks in advance!
Here is the Traceback
IntegrityError at /account/register/
duplicate key value violates unique constraint
"account_profile_mobile_number_key"
DETAIL: Key (mobile_number)=() already exists.
Request Method: POST
Request URL: http://127.0.0.1:8000/account/register/
Django Version: 2.2.5
Exception Type: IntegrityError
Exception Value:
duplicate key value violates unique constraint "account_profile_mobile_number_key"
DETAIL: Key (mobile_number)=() already exists.
Exception Location: /media/coduser/2NDTB/ProgramingPROJ/WebDevelopment/DjangoProject/MY-PROJECT/alternative/ex1/myvenv/lib/python3.6/site-packages/django/db/backends/utils.py in _execute, line 84
Python Executable: /media/coduser/2NDTB/ProgramingPROJ/WebDevelopment/DjangoProject/MY-PROJECT/alternative/ex1/myvenv/bin/python
Python Version: 3.6.8
Python Path:
['/media/coduser/2NDTB/ProgramingPROJ/WebDevelopment/DjangoProject/MY-PROJECT/alternative/ex1',
'/usr/lib/python36.zip',
'/usr/lib/python3.6',
'/usr/lib/python3.6/lib-dynload',
'/media/coduser/2NDTB/ProgramingPROJ/WebDevelopment/DjangoProject/MY-PROJECT/alternative/ex1/myvenv/lib/python3.6/site-packages']
Server time: Wed, 11 Sep 2019 01:11:15 +0000
Here is the account model
from django.db import models
from django.conf import settings
from PIL import Image
class Profile(models.Model):
GENDER_CHOICES = (
('male', 'Male'),
('female', 'Female'),
('other', 'Other'),
('tell you later', 'Tell you later')
)
MARITAL_CHOICES = (
('married', 'Married'),
('unmarried', 'Unmarried'),
('single', 'Single'),
('divorced', 'Divorced'),
('tell you later', 'Tell you later')
)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
date_of_birth = models.DateField(blank=True, null=True)
gender = models.CharField(
max_length = 14,
choices = GENDER_CHOICES,
default = 'tell you later'
)
marital_status = models.CharField(
max_length = 14,
choices = MARITAL_CHOICES,
default = 'tell you later'
)
name_of_father = models.CharField(max_length = 30)
name_of_mother = models.CharField(max_length = 30)
present_address = models.CharField(max_length = 200)
permanent_address = models.CharField(max_length = 200)
mobile_number = models.CharField(max_length = 14, unique = True, db_index=True)
emergency_contact_number = models.CharField(max_length = 14)
smart_nid = models.CharField(max_length = 14, unique = True, db_index=True)
nationality = models.CharField(max_length = 20)
profile_picture = models.ImageField(default = 'default_profile.jpg', upload_to='users/%Y/%m/%d/')
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.profile_picture.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.profile_picture.path)
Here is the forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Profile
class BaseForm(forms.Form):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(BaseForm, self).__init__(*args, **kwargs)
class BaseModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(BaseModelForm, self).__init__(*args, **kwargs)
class LoginForm(forms.Form):
username = forms.CharField(label_suffix='')
password = forms.CharField(widget=forms.PasswordInput, label_suffix='')
# BaseModelForm has been used instead of forms.ModelForm to remove the colon
class UserRegistrationForm(BaseModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email')
help_texts = {
'username': 'Letters, digits and #/./+/-/_ only',
}
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError(
'Please use another Email, that is already taken')
return email
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
# This will let user to edit their profile
class UserEditForm(BaseModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
# This will let user to edit their profile
class ProfileEditForm(BaseModelForm):
class Meta:
model = Profile
fields = ('date_of_birth', 'gender', 'marital_status', 'profile_picture',
'name_of_father', 'name_of_mother', 'present_address',
'permanent_address', 'mobile_number', 'emergency_contact_number',
'smart_nid', 'nationality')
Here is the views.py of account app
from django.http import HttpResponse
from django.shortcuts import render , redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
from .forms import LoginForm, UserRegistrationForm, \
UserEditForm, ProfileEditForm
# For email verification
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from .token_generator import account_activation_token
from django.contrib.auth.models import User
from django.core.mail import EmailMessage
# end of email verification
# User Profile
from .models import Profile
# For flash message
from django.contrib import messages
def user_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(request,
username=cd['username'],
password=cd['password'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse('Authenticated '\
'successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
form = LoginForm()
return render(request, 'account/login.html', {'form': form})
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
new_user.is_active = False # line for email verification
# Set the chosen password
new_user.set_password(
user_form.cleaned_data['password']
)
# Save the User object
new_user.save()
# Create the user profile
Profile.objects.create(user = new_user)
current_site = get_current_site(request)
email_subject = ' Activate Your Account'
message = render_to_string('account/activate_account.html', {
'user': new_user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(new_user.pk)),
'token': account_activation_token.make_token(new_user),
})
to_email = user_form.cleaned_data.get('email')
email = EmailMessage(email_subject, message, to=[to_email])
email.send()
return redirect('account_activation_sent')
else:
user_form = UserRegistrationForm()
return render(request,
'account/register.html',
{'user_form': user_form})
def account_activation_sent(request):
return render(request, 'account/account_activation_sent.html')
def account_activation_invalid(request):
return render(request, 'account/account_activation_invalid.html')
def activate_account(request, uidb64, token):
try:
uid = force_bytes(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
return redirect('blog-home')
else:
return render(request, 'account_activation_invalid.html')
#login_required
def edit(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = ProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=request.user.profile)
return render(request,
'account/profile.html',
{'user_form': user_form,
'profile_form': profile_form})
This is the token generator
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()
It was my mistake to use empty string without converting them to null. In fact, I don't know that much about Django, but I am learning it. As per the solution provided in the comment section by -mu is too short I have been able to solve the problem. So credit goes to -mu is too short
For solution I have just added an extra parameter- null = True in the mobile_number field. That's it. It solved my problem.
Here is the solution
mobile_number = models.CharField(max_length = 14, unique = True, db_index=True, null = True)

sqlalchemy.orm.exc.UnmappedInstanceError: Class '__main__.User' is not mapped on Flask-SQLAlchemy

I just got a problem when implementing Flask-SQLAlchemy to my Flask-Restplus. It consistently show an error:
sqlalchemy.orm.exc.UnmappedInstanceError: Class '__main__.User' is not mapped
The code I've written below is the simplified version (1 file) of the Flask-Restplus example project on github: https://github.com/postrational/rest_api_demo
I've checked again and again, but have no idea why the error still appears.
Here is my code:
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_restplus import Resource, Api, fields
app = Flask(__name__)
api = Api(app, version='v0.1')
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
ns = api.namespace('users', description='User API')
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(80))
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
def __repr__(self):
return '<User %s>' % self.email
user = api.model('user', {
"id": fields.Integer(readOnly=True),
"email": fields.String(required=True),
"password": fields.String(required=True),
})
def create_user(data):
email = data.get('email')
password = data.get('password')
user = User(email, password)
db.session.add(user)
db.session.commit()
def update_user(user_id, data):
user = User.query.filter(User.id == user_id).first()
user.email = data.get('email')
user.password = data.get('password')
db.session.add(user)
db.session.commit()
def delete_user(user_id):
user = User.query.filter(User.id == user_id).first()
db.session.delete(user)
db.session.commit()
#ns.route('/')
class UserList(Resource):
#ns.marshal_list_with(user)
def get(self):
users = User.query.all()
return users
#ns.marshal_with(user)
#ns.expect(user)
def post(self):
data = request.json
create_user(data)
return None, 201
#ns.route('/<int:id>')
class User(Resource):
#ns.marshal_with(user)
def get(self, id):
user = User.query.filter(User.id == id).first()
return user
#ns.expect(user)
#ns.marshal_with(user)
def put(self, id):
data = request.json
user = update_user(id, data)
return None, 204
def delete(self, id):
delete_user(id)
return None, 204
db.create_all()
user = User(email= 'saffsds#gmail.com', password= '4324dsfdsfa')
db.session.add(user)
db.session.commit()
user = User(email= 'sdfsdf#gmail.com', password= '5435rs')
db.session.add(user)
db.session.commit()
users = User.query.all()
print users
if __name__ == "__main__":
app.run(debug=True)
Is there anything I missed on the code? I use python2.7 anyway..
im pretty sure its because you are overloading User.__init__, but you didnt call super, so do this and see if it maps:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(80))
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
super(User,self).__init__()
def __repr__(self):
return '<User %s>' % self.email