I am trying to insert django form data inside the UserProfile model in my app. I tried using the django shell and views.py but I keep getting this error.
Models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
section = models.CharField(max_length=255, blank=True)
year = models.IntegerField(null=True, blank=True)
course = models.CharField(max_length=255, blank=True)
qrcode = models.CharField(max_length=255, blank=True)
present = models.BooleanField(default=False)
def __str__(self):
return self.user.username
views.py
#staticmethod
def generate_qr(request):
if request.method == "POST":
form = MakeAttendance(request.POST)
if form.is_valid():
course = form.cleaned_data.get('courses')
section = form.cleaned_data.get('section')
year = form.cleaned_data.get('year')
profile = UserProfile.objects.get_or_create(user=request.user)
userobj = UserProfile(qrcode=unique_id)
userobj.save().filter(course=course, section=section, year=year)
return redirect('/users/dashboard')
This question has been answered many times here, but none of the solutions worked for me. I tried Creating a user profile with get_or_create method. I tried deleting my entire database and making migrations again. I manually tried to pass the user ID but nothing.
First create a user using user=User.objects.create_user(username=request.user, password='password'), then save it using user.save() and create profile using profile=UserProfile.objects.get_or_create(user=user). The reason this error occours is because the UserProfile looks for a user instance which you did not provide.
The problem is in these two line
userobj = UserProfile(qrcode=unique_id)
userobj.save().filter(course=course, section=section, year=year)
In the first line you created an instance of UserProfile with only qr_code
and in the next line you are trying to save it which will try to insert a new row in the database without the user.
in models.py you should create user object:
from django.conf import settings
User = settings.AUTH_USER_MODEL
before class creating
Related
I'm new to Django and I've correctly created my first web app where I can register and login as an user. I'm using the standard from django.contrib.auth.models import User and UserCreationFormto manage this thing.
Now, I would like to create a new table in the database to add new fields to the user. I'm already using the standard one such as email, first name, second name, email, username, etc but I would like to extend it by adding the possibility to store the latest time the email has been changed and other info. All those info are not added via the form but are computed by the backend (for instance, every time I want to edit my email on my profile, the relative field on my new table, linked to my profile, change value)
To do that I have added on my models.py file the current code
from django.db import models
from django.contrib.auth.models import User
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed', auto_now_add=True, blank=True)
def __str__(self):
return self.user.username
And on my admin.py
from django.contrib import admin
from .models import UserAddInformation
admin.site.register(UserAddInformation)
The form to edit the email and the view can be found below
forms.py
class EditUserForm(UserChangeForm):
password = None
email = forms.EmailField(widget=forms.EmailInput(attrs={
'class': 'form-control'
}))
class Meta:
model = User
# select the fields that you want to display
fields = ('email',)
views.py
#authenticated_user
def account_user(request):
if request.method == "POST":
form = EditUserForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
user_info_obj = UserAddInformation.objects.create(user=request.user,
last_time_email_change=datetime.now())
user_info_obj.save()
messages.success(request, "Edit Succesfully")
else:
pass
else:
form = EditUserForm()
return render(request, 'authenticate/account.html', {
'form_edit': form,
})
The issue is that, once I'm going to update the email via the form, I got an error UNIQUE constraint failed: members_useraddinformation.user_id
Using ForeignKey make it works but it create a new row in the table, with the same when I just want to update the first one
The edit process for the email works tho
What am I doing wrong?
It turned out that auto_now_add=True inherit editable=False generating the error. So changing my models.py with
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed')
def save(self, *args, **kwargs):
self.last_time_email_change = timezone.now()
return super(UserAddInformation, self).save(*args, **kwargs)
def __str__(self):
return self.user.username
and checking with
user_info_obj = UserAddInformation.objects.get_or_create(user=request.user)
user_info_obj[0].save()
inside def account_user(request): worked
I'm not sure it's the best solution for my issue tho
I deleted a user, then all the associated blogs were also deleted but the associated comments are not deleted. Why comments model is indirectly related to User model using foreign key.
Can anyone give me the answer
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class blogpost(models.Model):
created_by=models.ForeignKey(User,on_delete=models.CASCADE)
topic=models.CharField(max_length=122,null=True,blank=False)
title=models.CharField(max_length=250,blank=False)
post=models.TextField()
likes=models.ManyToManyField(User, related_name='blog_posts')
date=models.DateTimeField(auto_now_add=True )
def __str__(self):
return ' (' +str(self.created_by)+') Title- '+self.title
class Meta:
ordering=['-date']
class CommentModel(models.Model):
post = models.ForeignKey(blogpost ,related_name='comments', on_delete=models.CASCADE)
name = models.CharField(max_length = 100)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' %(self.post.title, self.name)
class Meta:
ordering=['-date_added']
views.py
def comment_view(request, pk):
if request.method=='POST' and 'comment_button' in request.POST:
body=request.POST.get('comment_text')
post=blogpost.objects.get(pk=pk)
obj=CommentModel(body=body)
obj.name=request.user
obj.post=post
obj.save()
return HttpResponseRedirect(reverse('detaildata',args=[str(pk)]))
As I can see you have set on_delete=models.CASCADE in models, which is great.
You just have to delete the user, and belonging blogpost (and similarly so the comment) will get deleted on its own.
You can manually delete the user from Django Admin Panel or delete it from the shell. Here are the steps
$ python manage.py shell
...
$ User.objects.filter(id=1).delete()
Since you put on_delete on models.CASCADE, this will cause comments to be deleted if a user is removed.
You have two options:
Do this through the admin panel.
Enter into django shell using python manage.py shell and do so using User.objects.filter(id=1).delete ()
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 am working on a hard django project and I am stuck again. I have a field in the userprofile which is called troop:
class UserProfile(models.Model):
scout_username = models.OneToOneField(User, on_delete=models.CASCADE)
Group_Choice = Groups.Scout_Groups()
troop = models.SlugField(max_length=27, choices=Group_Choice, default='None', blank=False)
date_of_birth = models.DateField(default=date.today)
def __str__(self):
return '%s'% (self.scout_username)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
Then I have a form which fills in data which is sent to my stData model. Within the form the user can choose to add details about another user. Except they can only add details to another user who has the same troop details.
forms.py
from django import forms
from leaders.models import stData
from django.contrib.auth.models import User
from accounts.models import UserProfileManager, UserProfile
st_username_list=[
(None, 'Choose a user'),
(user1, 'user1'),
(i, 'no progress'),
]
class BadgeForm(forms.ModelForm):
def set_user(self, user):
global st_username_list
troop = user.userprofile.troop
userprofile = UserProfile.objects.all()
selected_st = userprofile.filter(troop=troop)
for st in selected_st:
username = str(st.st_username)
st_username_list.append((username, username))
st_username = forms.ChoiceField(choices=st_username_list)
class Meta:
model = stData
fields = ('st_username', 'Pioneer_Badge', 'Explorer_Badge', 'Adventurer_Badge', 'Proficiency_Badge', 'Other_Badge')
Please note
In the example above I used a global variable. I understand this is far from desired. I have since removed it thanks to the explanation of the proper way to do the filter (found after the line break). I'm only keeping this for education reasons for others who may find they had similar problems.
I pass through the user within my views like this:
user = request.user
user_form_setting = BadgeForm.set_user(self, user)
models.py
from django.db import models
from django.contrib.auth.models import User
from accounts.st_badge_list import st_List
class stData(models.Model):
Pioneer_Choices = st_List.Target_Badges()
Blue_Choices = st_List.Target_Badges()
Black_Choices = st_List.Target_Badges()
Proficiency_Choices = st_List.Proficiency_Badges()
Other_Choice = st_List.Other_Badges()
Pioneer_Badge = models.CharField(max_length=16, choices=Pioneer_Choices, default='None', blank=True)
Blue_Star = models.CharField(max_length=16, choices=Blue_Choices, default='None', blank=True)
Black_Star = models.CharField(max_length=16, choices=Black_Choices, default='None', blank=True)
Proficiency_Badge = models.CharField(max_length=22, choices=Proficiency_Choices, default='None', blank=True)
Other_Badge = models.CharField(max_length=27, choices=Other_Choice, default='None', blank=True)
st_username = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now=True)
print (User)
def __str__(self):
return '%s'% (self.st_username)
How would I go about having it so whatever user has the same troop details will appear within the st_username_list as a choice?
After researching and trying things with the code, I have been getting:
ValueError
Cannot assign "'user1'": "stData.st_username" must be a "User" instance.
I hope this is not too confusing.
Edit
Ok so I have found that I can filter the options for the st_username by doing
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['st_username'].queryset = UserProfile.objects.filter(troop='''user's troop''')
Problem update
My main issue now is that I am unable to pass through the user instance within the model. I have seen this question here. So I added this to my form's innit method:
self.user = kwargs.pop('user')
Yet when I try and use the user by going self.user I get the an unhelpful error KeyError saying user. The shell indicated this may be due to the self.user = kwargs.pop(user)
I believe this may be because I am not passing through the user. So when I call the form in my views, I tried form = BadgeForm(user=request.user) and got the same error.
my queryset looks like this now:
self.fields['scout_username'].queryset=UserProfile.objects.filter(troop=user.userprofile.troop)
Further Information:
To understand the problem better, I have passed through a set variable of the troop within the queryset. So in this case
self.fields['scout_username'].queryset=UserProfile.objects.filter(troop='BC')
Although now I get Error AttributeError:
'BadgeForm' object has no attribute 'name'
The shell links this with the formset from which I use the form with. The details I'm provided is:
line 435, in formset_factory
return type(form.__name__ + 'FormSet', (formset,), attrs)
I hope this makes more sense to you than to me! Any help would be greatly appreciated!
The final problem was within the use of the formset.
According to the docs, the proper way to add the kwargs is to do such:
BadgeFormsSet = formset_factory(BadgeForm)
formset = BadgeFormsSet(form_kwargs={'user': request.user})
Hope this helps any one else!
So I'm trying to automatically assign the current logged in user to a variable in my model. I think this make sense but I'm not able to migrate the models and it is going me this error.
models.py:
from django.db import models
from django.contrib.auth.models import User
from datetime import date
# Create your models here.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User)
portfolio_site = models.URLField(blank=True)
profile_pic = models.ImageField(upload_to='profile_pics',blank='True')
def __str__(self):
return self.user.username
class UserPosts(models.Model):
post_title = models.CharField(max_length=100,unique=True)
post_sub_title = models.CharField(max_length=250,unique=False)
post_author = models.ForeignKey('User',User.username)
post_date = models.DateField(default=date.today,blank=True)
post_body = models.TextField(max_length=1000,unique=False)
def __str__(self):
return str(self.post_title)
The Error:
ValueError: Cannot create form field for 'post_author' yet, because its related model 'User' has not been loaded yet
Remove the quotation from this line:
post_author = models.ForeignKey('User',User.username)
It should be like this:
post_author = models.ForeignKey(User,User.username)
I think the problem is this:
from django.contrib.auth.models import User
post_author = models.ForeignKey('User',User.username)
Your ForeignKey want's to use the attribute 'username' of the imported User. Not of your User object when related.
I think I just deleted the migrations and then migrated again from scratch...