How to define the foreign key relationship? - python

I'm new to django and the database concepts.
I'm getting the 1042 error code when I'm trying to register student via frontend and don't know where my mistake is
if anyone can help that'd be great.
I tried different ways but none was beneficial.
I can add the student via the admin panel of django but cannot do the same via frontend.
models.py
class Session(models.Model):
session = models.CharField(max_length=150, default=" ")
def __str__(self):
return self.session
def get_absolute_url(self):
return reverse('datapage')
class Student(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key = True)
phone_number = models.CharField(max_length=20, blank = True)
semester = models.CharField(max_length=20, blank = True)
session_year = models.ForeignKey(Session, on_delete = models.CASCADE)
def __str__(self):
return str(self.user)
forms.py
session_years = Session.objects.all()
session_year_list = []
for session_year in session_years:
single_session_year = (session_year.id, session_year.session)
session_year_list.append(single_session_year)
class StudentSignUpForm(UserCreationForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
email = forms.EmailField(required=True)
username = forms.CharField(required=True)
phone_number = forms.CharField(required=True)
semester = forms.CharField(required=True)
def clean_email(self):
email = self.cleaned_data.get('email')
email = email.lower()
if User.objects.filter(email__iexact=email).exists():
raise forms.ValidationError('A user has already registered using this email')
return email
def clean_username(self):
username = self.cleaned_data.get('username')
if User.objects.filter(email__iexact=username).exists():
raise forms.ValidationError('A user has already registered using this username')
return username
class Meta(UserCreationForm.Meta):
model = User
fields = ['first_name', 'last_name', 'email', 'username']
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_student = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.email = self.cleaned_data.get('email')
user.username = self.cleaned_data.get('username')
user.save()
student = Student.objects.create(user=user)
student.phone_number=self.cleaned_data.get('phone_number')
student.semester=self.cleaned_data.get('semester')
student.session_year=self.cleaned_data.get('session_year')
student.save()
return user
views.py
class StudentRegister(LoggedInRedirectMixin, CreateView):
model = User
form_class = StudentSignUpForm
template_name = 'registration/user_register.html'
def form_valid(self, form_class):
user = form_class.save()
return redirect('datapage')

#Vatsai Vohera - Correct me if I am wrong.
session = Session.objects.get(session=self.cleaned_data.get('session_year')
student.session_year = session

You are adding your requested data into session_year field which is not working rather you have to save your requested data to your model Session field session. I hope this will work for you.

You can use related_name='...' field in your ForeignKey attribute
and also add this:
session_year = models.ForeignKey(Session,related_name='some thing', on_delete = models.CASCADE, null = True)
then you have to call session_year by related name

Related

How do i add custom fields to UserManager in Django

I am trying to create a user profile, i followed through a tutorial which has registration for only username, email and password but i want to be able to add other custom fields.
What i did:
Models.py:
class UserManager(BaseUserManager):
def create_user(self, username, email, password=None,):
if username is None:
raise TypeError('User should have a userame')
if email is None:
raise TypeError('Users should have a 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('User should have a password')
user=self.create_user(username,email,password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(models.Model):
dso = models.ForeignKey(Dso,related_name='dso',default=NULL,blank=False,on_delete=models.CASCADE)
name = models.CharField(max_length=70, blank=False, default='')
email = models.EmailField(max_length=70, blank=False, default='')
password = models.CharField(max_length=70, blank=False, default='')
address = models.CharField(max_length=70, blank=False, default='')
roleId = models.IntegerField(blank=False, default='1')
isActive = models.BooleanField(blank=False, default=True)
customerId = models.CharField(max_length=70, blank=False, default='')
dateJoined = models.DateTimeField(auto_now_add=False, blank=False, default=NULL)
#property
def energy_data(self):
energydata = EnergyData.objects.filter(customerId=self.customerId).first()
return energydata
Serializers.py:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length = 68, min_length=6, write_only = True)
class Meta:
model=User
fields=['email','username','password','name','address','customerId',
'dso', 'roleId']
def validate(self, attrs):
email = attrs.get('email', '')
username = attrs.get('username', '')
if not len(username) >= 4:
raise serializers.ValidationError('Username must be morethan 4 letters or characters')
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
Views.py:
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')
absolute_url = 'http://'+current_site+relativeLink+"?token="+str(token)
email_body= 'Hi '+ user.username + ' Use this link below to verify your email \n'+ absolute_url
data = {'email_subject': 'Verify Your Email', 'email_body': email_body , 'to_email': user.email}
Util.send_email(data)
return Response(user_data, status = status.HTTP_201_CREATED)
URL Path:
path('register/', RegisterView.as_view(), name="register" )
When i do this and try to test i get the error, 'UserManager.create_user() got an unexpected keyword argument 'name''
Please kindly help as i am new to django rest frameworrk.
In your serializers.py you have the fields list that includes the variable 'name', but it is never defined in the models.py
Try to change serializers.py
fields=['email','username','password','address','customerId',
'dso', 'roleId']
And modify the variable name in models.py to be username instead of name
username = models.CharField(max_length=70, blank=False, default='')
Based on my experience with Django having a Model called "user" is going to create problems at some point since Django already have a User model pre-installed in the backend.
I know this is not the exact answer you were looking for, this will probably spare you a headache in the future.
To create a user profile I created the following model linking the User model with a OneToOneField.
class Profile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
bio = models.TextField()
profile_pic = models.ImageField(null=True, blank=True,upload_to="images/")
def __str__(self):
return str(self.user)
and obvioulsy imported
from django.contrib.auth.models import User
As a result,
I would remove your User model
Import "from django.contrib.auth.models import User"
add to the first line of your
UserManager Model, I would add
"user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)

Registration data "lost" somewhere in python django 4

I have my super basic authentication app, and I tried to write a simple Registration with email, first name, last name and (logically) password, but it seems that when I enter my request data it is "lost" somewhere. When I press the "POST" button, all the fields are blank and it says: "This field is required". I've been trying to figure it out for quite a long time, but I am new to django. I hope you can spot the problem.
Here is my models.py:
class UserManager(BaseUserManager):
def create_user(self, first_name, last_name, email, password=None):
if first_name is None:
raise TypeError('Users must have a first name')
if last_name is None:
raise TypeError('Users must have a last name')
if email is None:
raise TypeError('Users must have an email')
user = self.model(email=self.normalize_email(email), first_name=first_name, last_name=last_name)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(db_index=True, unique=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = UserManager
My serializers.py:
class RegistrationSerializer(serializers.ModelSerializer):
token = serializers.CharField(max_length=255, read_only=True)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password', 'token']
def create(self, validated_data):
return User.objects.create_user(**validated_data)
And my views.py:
class RegistrationAPIView(APIView):
permission_classes = (AllowAny,)
serializer_class = RegistrationSerializer
def post(self, request):
user = request.data.get('user', {})
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)

Django - TypeError: unhashable type: 'SQLDecodeErrorDjango '

I had everything running perfectly but I had to reinstall windows and when I tried to run the code again, it started giving me errors on user registration.
I followed Vitor Freitas guide to make implement multiple user types but only differed in views as he was using class based views and I had no idea what those were at that time.
I have narrowed down the problem where I am creating User table
(This line: user = User.objects.create(user=account) in forms.py).
Models.py
class MyAccountManager(BaseUserManager):
def create_user(self , email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email)
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, first_name,last_name, password):
user = self.create_user(
email=self.normalize_email(email),
password=password,
first_name=first_name,
last_name=last_name,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email',max_length=50,unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
is_user = models.BooleanField(default=False)
is_Manager = models.BooleanField(default=False)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = MyAccountManager()
def __str__(self):
return self.email
# For checking permissions. to keep it simple all admin have ALL permissons
def has_perm(self, perm, obj=None):
return self.is_admin
# Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
def has_module_perms(self, app_label):
return True
def upload_location(instance, filename):
file_path = 'resume/{user_id}/{filename}'.format(
user_id=str(instance.user.id), filename=filename)
return file_pathenter code here
class User(models.Model):
user = models.OneToOneField(Account, on_delete=models.CASCADE, primary_key=True)
city = models.CharField(max_length=40)
CV = models.FileField(upload_to=upload_location,validators=[FileExtensionValidator(allowed_extensions=['pdf'])])
dream_Job_Title = models.CharField(max_length=200)
industries = models.CharField(max_length=150)
speciality = models.CharField(max_length=200)
current_Profession = models.CharField(max_length=50)
target_Job_Title = models.CharField(max_length=100)
feedback = models.CharField(max_length=200)
rating = models.IntegerField()
phone = PhoneNumberField(null=False, blank=False, unique=True)
university = models.CharField(max_length=70,default="")
GPA = models.CharField(max_length=20,default="")
Major = models.CharField(max_length=30,default="")
Minor = models.CharField(max_length=30,default="")
Certification = JSONField()
Accomplishment = JSONField()
WorkExperience = JSONField()
Skills = JSONField()
REQUIRED_FIELDS=['CV','dream_Job_Title','industries','speciality']
# Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
def has_module_perms(self, app_label):
return True
forms.py
class UserRegister(UserCreationForm):
email = forms.EmailField(max_length=50,help_text='Enter a valid Email')
city = forms.CharField(max_length=40)
class Meta:
model = Account
fields = ['first_name','last_name', 'email', 'city', 'password1','password2']
#transaction.atomic
def save(self):
account = super().save(commit=False)
account.is_user = True
account.save()
user = User.objects.create(user=account)
#user.city.add(form.cleaned_data.get('city'))
user.city = self.cleaned_data.get('city')
user.save()
return account
def clean_email(self):
return self.cleaned_data['email'].lower()
views.py
def UserRegister_view(request):
context = {}
user = request.user
if user.is_authenticated and user.is_user:
return redirect("UserDashboard")
if request.POST:
form = UserRegister(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
context['registration_form'] = form
else:
form = UserRegister()
context['registration_form'] = form
return render(request, 'UserRegister.html', context)
I have also tried upgrading/downgrading dependencies.

Django Rest - Serializer: must be a instance on create

I'm trying to create create a nested serializer using the Django Rest framework. The relationship is Profile X User but when i use Profile.objects.create(user=profile, **user_data) i get ValueError: Cannot assign "<Profile: Profile object (7)>": "Profile.user" must be a "User" instance..
This should be some rookie misunderstanding of models relationship definitions or the serializer declaration itself but I can't find anything around the docs. If someone can point me a direction I'll be gracefull.
models.py
class User(models.Model):
name = models.CharField(max_length=100, blank=False)
email = models.CharField(max_length=100, blank=True, default='')
password = models.CharField(max_length=100, blank=True, default='')
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
class Profile(models.Model):
# choices [...]
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
profile_type = models.CharField(max_length=2,choices=PROFILE_CHOICES,default=TEAMMEMBER)
authentication_token = models.CharField(max_length=100, null=True)
avatar_url = models.CharField(max_length=100, default='')
permissions = models.CharField(max_length=100, null=True)
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
serializer.py
class UserSerlializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['name', 'email', 'password']
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
Profile.objects.create(user=profile, **user_data)
return Profile
POST
{
"profile_type" : "ST",
"user": {
"name" : "test",
"email" : "test#test.com",
"password" : "123456"
}
}
You are creating instances in wrong way. Change your create(...) method as,
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
user_instance = User.objects.create(**user_data)
profile_instance = Profile.objects.create(user=user_instance, **validated_data)
return profile_instance
Profile.user should beUser instance, but you are assigning Profile instance.
Change your create method to this:
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
user = User.objects.create(**user_data) # 1. creating user
profile.user = user # 2. assigning user
profile.save() # 3. saving profile after adding user
return profile # returning Profile instance.
inherit your user model from django contrib auth module also, and make a one to one relation with profile
from django.contrib.auth.models import User

Django-rest: How to implement authentication and permissions for custom User models?

views.py
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
model = User
serializer_class = UserSerializer
paginate_by = 10
def get_queryset(self):
queryset = User.objects.all()
search_query = self.request.query_params.get('user', None)
if search_query is not None:
queryset = queryset.filter(name__istartswith=search_query)
queryset = queryset.order_by('name')
return queryset
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
model = User
serializer_class = UserSerializer
models.py
class UserRole(models.Model):
class Meta:
ordering = ["name"]
db_table = 'userrole'
name = models.CharField(max_length=50)
status = models.CharField(max_length=100)
class User(models.Model):
class Meta:
ordering = ["name"]
db_table = 'user'
name = models.CharField(max_length=100)
email = models.EmailField(unique=True, max_length=100)
password = models.CharField(max_length=100)
status = models.CharField(max_length=100, default='active')
roleid = models.ForeignKey(UserRole, on_delete=models.CASCADE,
default=None, blank=True, db_column='roleid')
createdby = models.CharField(max_length=100, blank=True, default="")
createdon = models.DateTimeField(blank=True, auto_now_add=True)
updatedon = models.DateTimeField(blank=True, auto_now=True)
Serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
class UserRoleSerializer(serializers.ModelSerializer):
class Meta:
model = UserRole
I've gone through with Django-rest documentation but not able to find a reference for implementing authentication and permission for custom created Users.
Please advise.
Check Django Document for User authentication in Django and Permissions in Django Rest Framework.
Below is the sample models structure for custom BaseUser and BaseUserManager.
from django.conf import settings
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.template.defaultfilters import slugify
User = settings.AUTH_USER_MODEL
class BaseUserManager(BaseUserManager):
def create_user(self, useremail, display_name, password=None):
if not useremail:
raise ValueError('Users must have an email address')
now = timezone.now()
user = self.model(useremail=BaseUserManager.normalize_email(useremail))
user.display_name = display_name
user.email = useremail
user.profile_slug = getUniqueValue(BaseUser,slugify(useremail.split("#")[0]),field_name="profile_slug")
user.set_password(password)
user.status='A'
user.last_login = user.date_joined = now
user.save(using=self._db)
return user
def create_superuser(self, useremail, display_name, password):
user = self.create_user(useremail=useremail,
display_name=display_name, password=password)
user.email = useremail
user.display_name = display_name
user.is_superuser = True
user.is_staff = True
user.status='A'
user.save(using=self._db)
return user
class BaseUser(AbstractBaseUser, PermissionsMixin):
display_name = models.CharField(max_length=25)
profile_slug = models.CharField(max_length=25,null=True)
gender = models.CharField(max_length=1, blank=True, choices=Gender)
useremail = models.EmailField(unique=True)
is_staff = models.BooleanField(default=False)
user_status = models.CharField(max_length=1, default='A')
USERNAME_FIELD = 'useremail'
REQUIRED_FIELDS = ['display_name']
objects = BaseUserManager()
def __unicode__(self):
return self.display_name
In your permission.py, you may define permissions as:
from rest_framework import permissions
class CheckPermission(permissions.BasePermission):
def has_permission(self, request, view):
try:
# some code
return True
except:
return False

Categories

Resources