I'm basically new to the Django and got such ValueError.
I have a basic user model inheriting from AbstractUser class.
Also I have Profile model (in separate app), which also contain OneToOneField refering to my User model.
First of all, lets take a look on my Profile model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
country = models.ForeignKey('Country', on_delete=models.SET_DEFAULT, default='-')
full_name = models.CharField(max_length=32, default='-')
about = models.TextField(max_length=1000, default="User don't set any information about")
register_date = models.DateField(auto_now=True)
image = models.ImageField(upload_to='images/', default='images/no_avatar.png')
active = models.BooleanField(default=False)
website = models.URLField(default='-')
github = models.URLField(default='-')
twitter = models.URLField(default='-')
instagram = models.URLField(default='-')
facebook = models.URLField(default='-')
Secondly when I create a new User I have to also create his own profile (model instance refering to the user instance).
Let's look on my view.py where I creating a new user.
class SignupView(View):
def get(self, request):
"""
:param request:
:return: Register page
"""
return render(request, "login/register.html", {
'form': SignupForm()
})
def post(self, request):
"""
Tests data validity,creating user if everything is ok.
:param request:
:return: Particular user page if data is valid, otherwise it will return couple of mistake messages
"""
form = SignupForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password1 = form.cleaned_data['password']
password2 = form.cleaned_data['confirm_password']
if password1 == password2:
try:
user = User.objects.create_user(username=username, email=email, password=password1)
profile = Profile.objects.create(user=user)
user.save()
profile.save()
return HttpResponseRedirect(reverse('myprofile:index', args=(user.id, )))
except IntegrityError:
return render(request, 'login/register.html', {
'message': 'Username is already taken',
'form': form
})
else:
return render(request, 'login/register.html', {
'message': 'Passwords must match',
'form': form
})
return render(request, 'login/register.html', {
'form': form
})
I left the whole class based view but you likely need to check post function out.
And this is where the problem begins.
I getting an error on "profile = Profile.objects.create(user=user)" line. On this moment Django stopping an execution and raising an ValueError with "Field 'id' expected a number but got '-'.
".
What I already have tried?
Remove a database and also remove migrations by "python3 manage.py migrate app zero --fake" and then reapplying migrations to a new database.
So I don't probably think this is a problem with migration (not sure).
But what did I miss?
I will be very grateful for any help.
Related
I am working on a project in Django where I have a Profile Model with a Foreign Key field (OneToOne Relationship with User Model) called applicant and a status field which is set to 'Update' at default. Other fields like surname and othernames are also included in the Profile Model.
class Profile(models.Model):
applicant = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
surname = models.CharField(max_length=10, null=True)
othernames = models.CharField(max_length=30, null=True)
status = models.CharField(max_length=30, default='Update', null=True)
def save(self, *args, **kwargs):
self.profilestatus = 'Updated'
super().save(*args, **kwargs)
def __str__(self):
return f'{self.applicant.username}-Profile'
I want the system to check every logged in user if their profile information are not Updated, they should be redirected to the Profile Update page to update their profile first else they should be redirected to view their updated profile.
def index(request):
user = request.user.is_authenticated
if request.user.is_authenticated and Profile.objects.get(applicant=user, status= 'Update'):
return redirect('user-profile-update')
else:
return redirect('user-profile')
context = {
'check_profile_update':check_profile_update,
}
return render(request, 'dashboard/index.html', context)
I have ModelForm with a save method with automatically updates the satus field in Profile Model to Updated any time a user updates his or her profile information.
The issue is anytime I run the app error says 'Profile matching query does not exist.'
Someone should kindly help me on the best way of solving this issue.
In fact, how can I create an instance of the logged in user so I can check the user profile update status in model?
Thanks
The Problem:
user = request.user.is_authenticated makes the variable user = True, so when you use it in
if request.user.is_authenticated and Profile.objects.get(applicant=user, status= 'Update'):,
you are really doing the following:
if request.user.is_authenticated and Profile.objects.get(applicant=True, status= 'Update'):
So of course there will be no matches since no applicant equals True.
The Solution
Change the two lines to:
user = request.user # Now user equals the actual user
if user.is_authenticated and Profile.objects.get(applicant=user, status= 'Update'):
On another note:
I hesitate to use a get query without putting it in a try/except statement so that you can handle what should happen if a Profile is not found:
user = request.user # Now user equals the actual user
if user.is_authenticated:
try:
profile = Profile.objects.get(applicant=user, status= 'Update')
except Profile.DoesNotExist:
# Code to handle what happens if a Profile is NOT found
# Maybe redirect to a page not found
# or maybe redirect to a page to create an applicant?
EDIT
def index(request):
user = request.user
if user.is_authenticated:
try:
profile = Profile.objects.get(applicant=user)
except Profile.DoesNotExist:
print("Profile Does Not Exist")
# Redirect to a Profile creating page?
else:
if profile.status == 'Update':
return redirect('user-profile-update')
else:
return redirect('user-profile')
context = {
'check_profile_update':check_profile_update,
}
return render(request, 'dashboard/index.html', context)
Edit 2
As per your comment, the final working version is then:
def index(request):
user = request.user
if user.is_authenticated:
try:
profile = Profile.objects.get(applicant=user)
except Profile.DoesNotExist:
print("Profile Does Not Exist")
# Redirect to a Profile creating page?
else:
if profile.surname == None:
return redirect('user-profile-update')
else:
return redirect('user-profile')
context = {
'check_profile_update':check_profile_update,
}
return render(request, 'dashboard/index.html', context)
I am starting with Django, and I have a question about the connection between a post and the user who created it. For now, I managed to create the link, however, whenever I create a new post, the user id is always the default one, thus one. I want to make it in a way that the user id is the id of the person creating the post, and for some reason, it never works. The other option I tried is to put "user" into the form but the problem is that then the user can choose which user he is, which is risky. So is there any way to make it automatic? That when the post is created, the right user id is directly connected to it? Thank you for any help!!
model.py
"""
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, default=1)
image = models.ImageField(default="man.jpg")
titre = models.CharField(max_length=50)
slug = models.SlugField(max_length=100)
date_publication = models.DateTimeField(auto_now_add=True)
"""
view.py
"""
#login_required
def post_create(request):
if request.method == "POST":
post_form = PostForm(request.POST)
if post_form.is_valid():
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm(request.POST)
return render(request, "post/create.html", context={"post_form": post_form})
"""
forms.py
"""
class PostForm(ModelForm):
class Meta:
model = Post
fields = ["user", "image", "titre", "slug"]
"""
You remove the user field from the fields in the form:
class PostForm(ModelForm):
class Meta:
model = Post
# no user ↓
fields = ['image', 'titre', 'slug']
and in the view you add the logged in user to the instance wrapped in the form:
#login_required
def post_create(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
# add user to the instance ↓
post_form.instance.user = request.user
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm()
return render(request, "post/create.html", context={"post_form": post_form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I have created a Edit Profile form in my Django app but it doesn't save in the database.
This is the profile model:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', primary_key=True) #Each User is related to only one User Profile
city_search_text = models.CharField(blank=True, max_length=300)#user picks a city from autocomplete and in the view I get or create a City object
city = models.ForeignKey(City, blank=True, null=True, related_name='city') #Each User Profile must be related to one city.
prof_pic = models.ImageField(blank=True, upload_to='profile_pictures')
dob = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.first_name
This is the form:
class EditProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('dob',)#I'm testing to update this field only
def save(self, commit=True):
profile = super(EditProfileForm, self).save(commit=False)
if commit:
profile.save()
return profile
This is the view:
def editprofile(request):
if request.method == 'POST':
edit_profile_form = EditProfileForm(request.POST, instance=request.user)
if edit_profile_form.is_valid():
profile = edit_profile_form.save(commit=False)
profile.save()
if 'next' in request.GET:
return redirect(request.GET['next'])
else:
print (profile_form.errors)
else:
edit_profile_form = EditProfileForm(instance=request.user.profile)
return render(request, 'excurj/editprofile.html', {'edit_profile_form':edit_profile_form,})
After I submit the form it forwards me to index page okay but the values remain the same in the user's profile.
Seems like
if edit_profile_form.is_valid():
isn't getting called at all, and your data is not saved. That means your form has invalid data, and you should check for form errors to detect those.
Also, you are trying to print form errors if the request isn't POST, which makes no sense and won't help you printing form errors. Try using this way;
if edit_profile_form.is_valid():
profile = edit_profile_form.save(commit=False)
profile.save()
else:
print (profile_form.errors)
And check your form for errors.
I figured it out eventually. In the view I should have passed an instance of the profile not the User object. So it needs to be like this:
edit_profile_form = EditProfileForm(request.POST, instance=request.user.*profile*)
Hello i have UserSettings and the user as the possibility to use a ProfilePicture. The Problem is the User cannot change any of his profile Settings. since i get the Error Unique Constraint failed or (thats what i get right now) 'int' object has no attribute '_committed'
I think the problem is in the view but i dont know how to change it.
My model:
class UserSettings(models.Model):
profileimage = models.ImageField(verbose_name=_(u"Change Your Profilepicture"),upload_to=upload_location,
default=1,
blank=True,
)
Info = models.CharField(verbose_name=_(u"Tell us about yourself"),max_length=500,default="I'm a Human")
status =
City = models.CharField(verbose_name=_(u"Where are you from"),max_length=500,default='Earth')
user = models.OneToOneField(User, default=1)
objects = models.Manager()
class Meta:
ordering =['-user']
def __unicode__(self):
return self.user.username
My View:
#login_required
def userprofiletwo(request):
user = request.user
form = UserSettingsForm(request.POST or None, request.FILES or None)
if form.is_valid():
user = request.user
form.save()
messages.success(request, 'Your personal Settings are Updated')
return redirect('userprofiletwo')
context = {
'form':form,
}
return render(request, 'userprofile/userprofiletwo.html', context)
I tried to change the OnetoOne field on the model to FeoreignKey or ManytoMany but this made new userprofiles instead of replacing the old information with new information.
Thanks in advise.
You need to pass in the current profile into the form.
form = UserSettingsForm(request.POST or None, request.FILES or None, instance=request.user.profile)
How can I use Django sessions to have a user be able to start a form on one page, and move to the next page and have them complete the form?
I have looked into pagination and wizard forms, but I don't get them at all.
When I have one page with a small portion of a model I'm using - in forms - and another page with the rest of the model - forms.py with the rest of the model info - I can use the first form perfectly.
But when I move to the next page, I get an error saying (1048, "Column 'user_id' cannot be null").
My best guess is to use Django sessions to fix this issue. I don't want the user to have to put in their username and password a second time to get this to work. Any ideas?
my models/forms.py:
class Contact(models.Model):
user = models.OneToOneField(User)
subject = models.CharField(max_length=100, blank=True)
sender = models.EmailField(max_length=100, blank=True)
message = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.user.username
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = Contact
fields = ('username', 'password', 'email')
class ContactForm1(forms.Form):
class Meta:
model = Contact
fields = ('subject', 'sender')
class ContactForm2(forms.Form):
message = forms.CharField(widget=forms.Textarea)
class Meta:
model = Contact
fields = ('message',)
views:
def contact(request):
registered = False
if request.method =='POST':
user = UserForm(request.POST)
contact = ContactForm1(request.POST)
if user.is_valid() and contact.is_valid():
user = user.save()
user.set_password(user.password)
user.save()
contact = contact.save(commit=False)
contact.user = user
registered = True
return render(request, 'mysite/contact.html', {'user': user, 'contact': contact, 'registered': registered})
def contact_second(request):
if request.method =='POST':
contact = ContactForm2(request.POST)
if contact.is_valid():
contact = contact.save(commit=False)
contact.save()
return render(request, 'mysite/contact_two.html', {'contact': contact}
I think it's a good idea to use sessions to store the forms because you don't want on each page to store the user input into the database because what if s/he change mind in the 3rd page and s/he wants to discard the registration or whatever it is?
I think is better to store the forms in session until you get in the last page, you ensure that everything is valid and then save the data in the database.
So let's say that the bellow code is in one of the view that will serve the first form/page. You retrieve the data from the POST request and you check if the given data are valid using the form.is_valid(), you then store the form.cleaned_data (which contains the user's validated data) to a session variable.
form = CustomForm(request.POST)
...
if form.is_valid():
request.session['form_data_page_1'] = form.cleaned_data
Note here that you may need to add code to redirect the user to the next page if form.is_valid() is true, something like this:
if form.is_valid():
request.session['form_data_page_1'] = form.cleaned_data
return HttpResponseRedirect(reverse('url-name-of-second-page'))
Then in any other view let's say in the view that is going to serve the second page you can retreive the from data from the first page like this:
first_page_data = request.session['form_data_page_1']
And you can do whatever you want with them as if it was after you executed the form.is_valid() in the first view.