How to get UserProfile to reference the fields from UserModel? - python

Just an fyi, I'm pretty new to programming & Django in general. I've been teaching myself.
Before I get into the problem, I'll share my Django code:
models.py :
class User(AbstractUser):
# DATABASE FIELDS
email = models.EmailField(("email address"), unique=True)
REQUIRED_FIELDS = ['username']
USERNAME_FIELD = 'email'
# META
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
# TO STRING METHOD
def __str__(self):
return "User " + str(self.id) + " - " + self.email
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.CharField(max_length=100, verbose_name="First Name")
last_name = models.CharField(max_length=100, verbose_name="Last Name")
date_created = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Profile Created On")
role = models.CharField(max_length=255, verbose_name="User Demographic")
# META
class Meta:
verbose_name = "User Profile"
verbose_name_plural = "User Profiles"
# TO STRING METHOD
def __str__(self):
return self.first_name
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User
class AbstractUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email')
class AbstractUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = UserChangeForm.Meta.fields
serializers.py
from rest_framework import serializers
from djoser.serializers import UserCreateSerializer, UserSerializer
from . import models
from .models import User, UserProfile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('id', 'email', 'username', 'password')
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('id', 'email', 'username', 'password')
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ("id", "user", "first_name", "last_name", "date_created", "role")
The User(AbstractUser) model comes with some default fields. Two of those default fields I'm trying to reference are :
first_name & last_name
What I'm trying to do is, get those two default fields to connect with my UserProfile Model so that, when I create my User and fill out those fields, it will also show up in my UserProfile without having to fill it out there and connect it with a user.
Does anyone have any advice on how to achieve this connection/reference of two models?
(Just as an addition, I'm also using React for my frontend framework and have the requests working. It was just now that I realized I needed those two fields/models to connect after creating my SignUp component.)

By default, ForeignKey refers to the primary key for relation. But we can also point to other fields using to_field parameter.
I haven't tried the below code yet. But you can do something like this in your models.py:
models.py
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.ForeignKey(User, to_field="firstname_field", verbose_name="First Name")
last_name = models.ForeignKey(User, to_field="lastname_field", verbose_name="Last Name")
You can refer the document here.

You need just to declare in Userprofile as OnetoOneField without declaring the first_name and last_name because User model has been declaring those field
models.py
from django.contrib.auth import get_user_model()
class UserProfile(models.model):
user = models.OnetoOneField(get_user_model(), on_delete=models.CASCADE)

Related

How to set user type in a customuser model when a new user registers

I have two models CustomUser and Manager_profile given below. There are 2 types of users a manager and a customer. There is a form to register as a manager. How can I set the is_manager field to True when a manager registers?
I also have another question. How can I store the data from department field to the Manager_profile model?
#Models
class CustomUser(AbstractUser):
is_manager = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
def __str__(self):
return self.first_name
class Manager_profile(models.Model):
user = models.OneToOneField(CustomUser,on_delete=models.CASCADE)
department = models.CharField(max_length=100)
def __str__(self):
return self.department
#Form
from django.contrib.auth.forms import UserCreationForm
from account.models import CustomUser
from django import forms
class ManagerCreateForm(UserCreationForm):
department = forms.CharField()
class Meta:
model = CustomUser
fields = ['username','first_name','last_name','department']

django model creates extra table for same relation

I am having an issue with django model that creates multiple tables for same class, it creates two table for same relation, it should create 3 table i.e users, groups, and user_groups but I having an extra table with name users_groups (note: an extra 's').
Seems an issue with verbose_name, db_meta or related_name
Full Code:
from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.utils.translation import ugettext_lazy as _
class UserManager(BaseUserManager):
"""Define a model manager for User model with no username field."""
pass
class CustomUser(AbstractUser):
"""Model representing a User with some extended fields and email as username field"""
username = None
email = models.EmailField(max_length=100, unique=True)
is_admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
ordering = ['email']
db_table = 'users'
objects = UserManager()
def __str__(self):
"""String for representing the Model object."""
return self.email
class Group(models.Model):
"""Model representing a Group"""
name = models.CharField(max_length=200)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, through='UserGroup', related_name='user_groups')
class Meta:
ordering = ['name']
db_table = 'groups'
def __str__(self):
return self.name
class UserGroup(models.Model):
"""Model representing a User's Group"""
group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name = 'group')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name = 'user')
class Meta:
db_table = 'user_groups'
django.contrib.auth, provide a Group model which is not an abstract model.
When you create your CustomUser, it's inherit AbstractUser which contain a groups field, creating a many to many relation to the django.contrib.auth.Group model. So the user_groups table is created to handle the relation between CustomUser and django.contrib.auth.Group models. By default, the table name for a many to many relation concatenate table names of relation parts (_get_m2m_db_table).
In order the customize the Group model, take a look at How do I extend the Django Group model?

DRF: Username still required after customizing Abstract User

I'm trying to write a REST API using Django and DRF. I'm trying to create a user model and use it in my application. But the problem is that it returns a 400 error status code which says:
{"username":["This field is required."]}
This is my code for models:
import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
from django.dispatch import receiver
from django.utils.encoding import python_2_unicode_compatible
from django.db.models.signals import post_save
from rest_framework.authtoken.models import Token
from api.fileupload.models import File
#python_2_unicode_compatible
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField('Email address', unique=True)
name = models.CharField('Name', default='', max_length=255)
phone_no = models.CharField('Phone Number', max_length=255, unique=True)
address = models.CharField('Address', default='', max_length=255)
country = models.CharField('Country', default='', max_length=255)
pincode = models.CharField('Pincode', default='', max_length=255)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
The Serializer:
class CreateUserSerializer(serializers.ModelSerializer):
username = None
def create(self, validated_data):
validated_data['username'] = uuid.uuid4()
user = User.objects.create_user(**validated_data)
return user
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.address = validated_data.get('address', instance.address)
instance.country = validated_data.get('country', instance.country)
instance.pincode = validated_data.get('pincode', instance.pincode)
instance.phone_no = validated_data.get('phone_no', instance.phone_no)
instance.email = validated_data.get('email', instance.email)
instance.save()
return instance
class Meta:
unique_together = ('email',)
model = User
fields = (
'id', 'password', 'email', 'name', 'phone_no', 'address', 'country', 'pincode',
)
extra_kwargs = {'password': {'write_only': True}}
Admin.py file:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
#admin.register(User)
class UserAdmin(UserAdmin):
pass
class User(AbstractUser):
As your User model inherits from AbstractUser, it will inherit
the username field.
Just remove the username field from your User model by setting username = None like this:
class User(AbstractUser):
# ...
username = None
# ...
class UserAdmin(UserAdmin):
As your UserAdmin model inherits from django.contrib.auth.admin.UserAdmin, you will need to update fieldsets, list_display, search_fields, and ordering fields in your UserAdmin model because they use username which you have removed from your User model.
Abstract User always has the username field. Removing it will cause problems. I will suggest you store the email address of the user in username field as well and use that. Please make sure its always updated in both fields which is not very hard.

How to save data from form field in Model with One to One reltionship with a Model inheriting from AbstractUser

I have a field called org model called ScrummyUser with a one to one field with a model called User which inherits from AbstractUser model, how do I save data from the form field into the scrummyuser model
This is the Organization Model
class Organization(models.Model):
organization = models.CharField(max_length=255, null=True)
def __str__(self):
return self.organization
This is the ScrummyUser model
class ScrummyUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='scrummy_profile')
role= models.CharField(max_length=100, choices=role, blank=True, null=True, default='DEV')
org = models.ForeignKey(Organization, max_length=255, on_delete=models.CASCADE, default=1)
This is the ScrummySignup form
class ScrummySignUpForm(UserCreationForm):
role = forms.ChoiceField(choices=role, required=False)
org = forms.ModelChoiceField(
queryset=Organization.objects.all(),
widget=forms.Select
)
class Meta(UserCreationForm.Meta):
model = User
fields = ['first_name', 'last_name','username' ,'email']
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_user = True
user.save()
scrummy = ScrummyUser.objects.create(user=user, role=role)
return user
It throws me this errormessage
scrummy = ScrummyUser.objects.create(user=user, role=role, org=org)
NameError: name 'org' is not defined
which is obvious but I am looking for another approach to save the data
for access CutomUser with Abstract you should get User of settings:
from django.conf import settings
class ScrummyUser(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,
primary_key=True, related_name='scrummy_profile')
AbstractUser link
ok so I figured this out, after defining a variable org as a modelchoicefield, i passed it unto the fields for user model as a user form field before saving it into the scrummyuser model.

Django REST framework:Use OneToOneField can't GET

when i use Django REST framework ,and use Use OneToOneField and RetrieveUpdateDestroyAPIView can't GET by pk;
my code are as follows:
models.py
class UserAccount(models.Model):
username = models.CharField(null=False, max_length=45)
password = models.CharField(null=False, max_length=16)
class UserContactInfo(models.Model):
userAccount = models.OneToOneField(UserAccount, primary_key=True)
phone_number = models.CharField(null=True, blank=True)
email = models.CharField(null=True, blank=True, max_length=45)
serializers.py
class UserAccountSerializer(serializers.ModelSerializer):
class Meta:
model = UserAccount
fields = ('id', 'username', 'password')
class UserContactInfoSerializer(serializers.ModelSerializer):
class Meta:
model = UserContactInfo
fields = ('userAccount', 'phone_number', 'email')
views.py
class UserContactInfoDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UserAccount.objects.all()
serializer_class = UserContactInfoSerializer
urls.py
urlpatterns = [
...
url(r'^ContactInfo/(?P<pk>[0-9]+)/$', views.UserContactInfoDetail.as_view()),
]
Ok , when i try to GET UserContactInfo data:
GET http://127.0.0.1:8000/ContactInfo/1/
and go wrong:
AttributeError at /ContactInfo/1/
'UserAccount' object has no attribute 'userAccount_id'
Request Method: GET
Request URL: http://127.0.0.1:8000/ContactInfo/1/
.....
Who can help me to fix it . Thanks!
I think you have typo in a view, in a queryset:
queryset = UserAccount.objects.all() instead of UserContactInfo.objects.all()

Categories