I'm trying to add extend user model. I keep getting this error: Primary key is not unique.
class UserExtended(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,parent_link=True,primary_key=True)
If I remove primary_key=True then I get the error instance.userextended.id does not exists well, of course it doesn't since now I dont have id.
How do I get around this?
In models.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserExtended(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# Then you can also add fields like these to extended model
profilepic = models.ImageField(upload_to='uploads/users/%Y/%m/%d/', null=True, blank=True)
designation = models.CharField(max_length=200,null=True, blank=True)
about = models.TextField(null=True, blank=True)
website = models.URLField(null=True,blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserExtended.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.userextended.save()
Now, whenever a new user is created, a extended record for that user will be created automatically.
Also, if a user record is saved, then it will automatically be updated in extended record.
Related
The problem:
I have a model, which is referencing the basic User model of django. Right now, if I submit the form Django updates my database by replacing the existing data with the new one. I want to be able to access both of them. (In weight and date field)
Models file:
I saw other posts here, where they solved a problem by specifying a foreign key, but that doesn't solve it for me.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
weight = models.FloatField(max_length=20, blank=True, null=True)
height = models.FloatField(max_length=20, blank=True, null=True)
date = models.DateField(auto_now_add=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
Views file:
This is where I save the data that I get from my form called WeightForm
from django.shortcuts import render
from django.contrib.auth.models import User
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from users import models
from users.models import Profile
from .forms import WeightForm
def home(request):
form = WeightForm()
if request.is_ajax():
profile = get_object_or_404(Profile, id = request.user.id)
form = WeightForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return JsonResponse({
'msg': 'Success'
})
return render(request, 'Landing/index.html',{'form':form})
What I tried:
I used to have a OneToOneField relation with this model, but as you can see I changed it to foreignkey, according to answers I saw on this site.
Thanks if you've gotten this far in my mess :D
I didn't understood exactly what you mean by "I want to be able to access both of them. (In weight and date field)" but I guess you want user to be able to see their previous data of weight and Date also, so you can try doing this:
In your models.py do try doing this,
class Profile(models.Model):
user_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
height = models.FloatField(max_length=20, blank=True, null=True)
def __str__(self):
return self.user.username
class UserData(models.Model):
Data_id = models.AutoField(primary_key=True)
user_id = models.ForeignKey(Profile, on_delete=models.CASCADE)
weight = models.FloatField(max_length=20, blank=True, null=True)
date = models.DateField(auto_now_add=True)
then u can have seperate forms for both the models and use them combined.
You can make a workaround
Create new model which would include something like "version"
Reference to version with foreign key
class ProfileChange(models.Model):
Date = models.DateField(default=datetime.datetime.today().strftime('%Y-%m-%d'))
#classmethod
def create(cls):
object = cls()
return object
class Profile(models.Model):
version = models.ForeignKey(ProfileChange,on_delete=models.CASCADE)
Unfortunately, you could see only one ProfileChange a day. If you want to see more of them, instead of models.DataField use models.IntegerField
I added a custom user profile field role with the following models.py.
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
ROLE_CHOICES = (
(792, 'Student'),
(172, 'Teacher'),
(864, 'Supervisor'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.IntegerField(choices=ROLE_CHOICES, null=True, blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
What is the best way to return the int value assigned to the role? For example if the current logged in user is assigned the role of "Teacher", I want to be able to use the 172 value elsewhere like in views.py.
Currently logged in user is request.user, so
request.user.profile.role
will return 172, and
request.user.profile.get_role_display()
will return "Teacher". Note that you should omit parentheses if you are using the latter in a template.
I'm trying to save a User and a Profile in django which are linked together using a oneToOneField but I'm getting an error saying
duplicate key value violates unique constraint
"auth_user_username_key
eventhough I dont have any duplicates.
I also get this error:
duplicate key value violates unique constraint
"api_profile_user_id_key" DETAIL: Key (user_id)=(9) already exists.
Here is my code:
model.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models import CharField, OneToOneField
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = OneToOneField(User, on_delete=models.CASCADE)
phone_number = CharField(max_length=20)
account_type = CharField(max_length=10, default='basic')
facebook_id = CharField(max_length=20, blank=True)
google_id = CharField(max_length=20, blank=True)
notification_id = CharField(max_length=40, blank=True)
# TODO add account info and watchlist
def __str__(self):
return self.user.email
#receiver(post_save, sender=User)
def user_save(sender, instance, **kwargs):
Profile.objects.create(user=instance)
view.py:
#api_view(['POST'])
def sign_up(request):
data = request.data
user = User.objects.create_user(username=data['username'],
password=data['password'],
first_name=data['first_name'],
last_name=data['last_name'],
email=data['email']
)
user.profile.phone_number = data['phone_number']
user.save()
return Response('hey')
I think the problem is in the post_save receiver however I'm not sure.
create_user is also calling save(), then you also call user.save(), the post_save signal is being called twice for one user, you get the error because two Profile objects are being created for one user
You could do:
#receiver(post_save, sender=User)
def user_save(sender, instance, **kwargs):
Profile.objects.get_or_create(user=instance)
I Have a Model that have a OnetoOne relationship with django.contrib.auth.models auth.
When I create one User Model I send a signal to the Profile Model which is related to this User. Then the Profile Object is created, but I can't figure out how to fill the others fields of Profile Object. Eg.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
Could some one help me? How can I fill these bio, location and birth_date on a form?
Edit:
I found a Solution. don't know if its the best practices. Inside forms.py override the save()
def save(self, commit=True):
# Save the provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.save()
user.profile.location= self.cleaned_data["location"]
user.profile.save()
return user
Here's my models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class Userprofile(models.Model):
user = models.OneToOneField(User, primary_key=True)
username = user.__unicode__()
path = './data/'+username+'/'
file = models.FileField(upload_to=path)
labelfile = models.FileField(upload_to=path, blank=True)
def __unicode__(self):
return u"%s" % self.user.username
def create_user_profile(sender, instance, created, **kwargs):
if created:
Userprofile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
the problem is:
AttributeError: 'OneToOneField' object has no attribute 'model'
I want a file upload function that it can save in a index related to the User's name, but I can't find a good way to do it. And I hope someone can help me. Thanks.