ModelChoiceField - get request.user.username - django

I need to choose User to form by the request.user.username and save into the database.
Here I have a code of forms.py
class Send(forms.ModelForm):
sender = forms.ModelChoiceField(queryset=User.objects.order_by('username')
Here is the models.py, where I am going to save the data about the user:
class SendM(models.Model):
sender = models.ForeignKey(User, null=True, blank=False, on_delete=models.CASCADE)
And here is views.py, where I get the data
def form_create(request):
if not request.user.is_anonymous:
form = Send(request.POST or None, initial={'sender': request.user.username})
if request.method == "POST":
if form.is_valid():
send = SendM(sender=User.objects.get(username=form.cleaned_data['sender']))
send.save()
return redirect("/")
To understand I want to pre-filled the array with the user found in database.
Thank you very much!!
it does only this:
[1]: https://i.stack.imgur.com/XY2fl.png

The initial value in the form is the user reference, not the username, because you're using a ModelChoiceField. I don't really remember now if it's the model instance (initial={'sender': request.user}) or the model primary key (initial={'sender': request.user.pk}) .
Then after form.is_valid(), there is no need to get the user from the database again. You just need to call the save method on the form. Django does the rest.
if form.is_valid():
send = form.save()

Related

Django: Integrity error UNIQUE constraint failed: user_profile.user_id

When I am trying to edit a profile to add info to a UserProfile model, I am getting this strange error:
IntegrityError at /profiles/edit/
UNIQUE constraint failed: user_profile.user_id
What is wrong here,
model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField(blank=True)
phone= models.CharField(max_length=10, blank=True)
address = models.CharField(max_length=1024)
age = models.PositiveIntegerField(blank=True,null=True)
gender = models.IntegerField(choices=GENDER_CHOICES, default=1)
form:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('phone','age','gender','address','bio')
view:
def edit_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST)
print request.POST
if form.is_valid():
new_profile = UserProfile(
user = request.user,
bio = request.POST['bio'],
address = request.POST['address'],
age = request.POST['age']
)
new_profile.save()
return HttpResponseRedirect(reverse('user_public_profile', args=(request.user.username,)))
return render(request,'users/edit_profile.html', {'form': form})
else:
form = UserProfileForm()
return render(request,'users/edit_profile.html',
{'form': form})
It's not strange. You already have a profile for that user, so adding another one breaks the unique constraint. You need to edit the existing one, not add a new one.
Also note that you're not using the cleaned form data when you save, which you should be. Either use form.cleaned_data['bio'] etc, or even better just do form.save() which is the whole point of using a model form.
Putting that together:
try:
profile = request.user.userprofile
except UserProfile.DoesNotExist:
profile = UserProfile(user=request.user)
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return redirect...
else:
form = UserProfileForm(instance=profile)
return render...
I was getting the same error multiple times and I was really disheartened but finally came over the solution.
Convert:
user = models.OneToOneField(User)
to
user = models.ForeignKey(User)
This should solve the issue.
add (instance = request.user) in UserProfileForm(request.POST)
I accidentally got this error because I forgot to specify update_fields in my call to save. I had:
modified_instance.save(video_attr)
When I should have had:
modified_instance.save(update_fields=[video_attr])
The truthy string was being interpreted as the positional force_update parameter, which obviously causes problems if the record already exists.
Consider the case: If the same user makes the post request again on URL 'profile/edit' then your code will try to create the new UserProfile using the same user instance, but since this is a one to one field and you have already created one profile using that user hence it will throw integrity error.
So you should check first if the profile associated with that user already exists or not, then if it didn't exist then create it.
Yes you are making a OneToOne relation between User and UserProfile models that's why you are facing integrity error,
for fixing this you can change it to ForeignKey
Like :
class UserProfile(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
bio = models.TextField(blank=True)
...
...

Example Needed: Pass the submitted form information to review page

I have a form using modelForm I need an example or code of the views.py and related files to create another page where users can view the information they submitted. I can think of doing it with the primary key of the database they saved to but how do i redirect them to another template with the information from the form they just entered.
I also need a permalink to that page so others can type in a url to see that information review page
Thank you very much for your help, you can also redirect me to a url with an example like above if you know of one
I think it can be done this way...
For example, you have a registration form that takes in modelform
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'User Name'))
email = forms.EmailField(label =(u'Email Address'))
password = forms.CharField(label =(u'Password'),widget=forms.PasswordInput(render_value=False))
password1 = forms.CharField(label =(u'Verify Password'),widget=forms.PasswordInput(render_value=False))
class Meta:
model = Drinker
exclude = ('user',)
Then the view:
def Registration(request):
if request.POST:
form =RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'],email=form.cleaned_data['email'])
password = form.cleaned_data['password']
user.save()
path = reverse('Review', dict(user=user,email=email,password=password)
return HttpResponseRedirect(path)
else:
return render(request,'register.html',{'form':form,})
else:
form = RegistrationForm()
return render(request,'register.html',{'form':form,})
Then just create another view:
def Review(request):
render(request,'review.html',dict(user=user,email=email,password=password))
Then display it in the review.html... Hope this helps...

Changing django form values

I have a form that gets values from a database created by a model. Say my the table has 2 columns, city and code, and I display just the city in my form using a ModelChoiceField.
When the use submits the form and I am going through the validation process, I would like to change the value of the city the user has selected with it's code.
models.py
class Location(models.Model):
city = models.CharField(max_length=200)
code = models.CharField(max_length=10)
def __unicode__(self):
return self.city
forms.py
city = forms.ModelChoiceField(queryset=Location.objects.all(),label='City')
views.py
def profile(request):
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
???????
How could I do this?
Thanks - Oli
You can do this:
def profile(request):
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
#Retrieve the city's code and add it to the profile
location = Location.objects.get(pk=form.cleaned_data['city'])
profile.city = location.code
profile.save()
However you should be able to have the form setting the code directly in the ModelChoiceField. Check here and the django docs
I would overwrite the save method of the form. And change the field there. That way you still would have a clean view where all logic related to the form stays contained within the form.

Django Form problems with UserProfile

I'd like to create a "update user's profile" page to let users modify their profiles, so I come up with the following models:
class Profile(models.Model):
user = models.OneToOneField(User)
nick_name = models.CharField(blank=True,max_length=100)
school = models.CharField(blank=True,max_length=100)
motto = models.CharField(blank=True,max_length=100)
class ProfileForm(ModelForm):
class Meta:
model = Profile
And my view is designed as:
#login_required
def update_profile_view(request):
if request.method == 'POST':
user = request.user
try:
profile = user.get_profile()
except Exception:
profile = Profile.objects.create(user=user)
form = ProfileForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
profile.nick_name = cd['nick_name']
profile.school = cd['school']
profile.motto = cd['motto']
profile.save()
return HttpResponseRedirect('/main_page/')
else:
form = ProfileForm()
return render(request, 'update_profile.html', {'form':form})
The relationship between an user and a profile is apparently 1to1, and with request I can determine the current user. So the form's user field needn't to be filled. Unfortunately, this couldn't pass "the form.is_valid()" test. And it seems hard to modify a form before "is_valid" invoked. For simplicity, I don't want to create my own Form Class, neither do I want to write customized form validation. Is there any other way to solve the problem?
Your view can be greatly simplified:
#login_required
def update_profile_view(request):
try:
profile = Profile.objects.get(user=request.user)
except Profile.DoesNotExist:
profile = None
form = ProfileForm(request.POST or None, instance=profile)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponseRedirect('/main_page/')
return render(request, 'update_profile.html', {'form':form})
There's no need to manually assign the fields like you're doing. Django ORM knows how to do an insert versus an update automatically. So if you simply pass the ProfileForm an instance of a Profile, it knows to do an update. If there's no instance of a profile, it's going to do an insert.
Now, if you want to make the assignment of the user transparent in the UI, you'll need to exclude the user field from the form and assign it yourself. There are a couple of different ways to do that.
I would also recommend leveraging reverse in your redirect so you don't have a hard-coded path.
You have basicly two choices:
1 Modification of ProfileForm:
class ProfileForm(ModelForm):
class Meta:
model = Profileclass
exclude = ('user',)
2 Change this lines as follows:
form = ProfileForm(request.POST, instance=profile)
if form.is_valid():
updated_profile = form.save()
You can either set the user field's value to not required in the init method (self.fields['user'].required = False) of the form or set the user not editable in the model (editable=False).
In your view method, call profile = form.save(commit=False), then do profile.user = your_user and profile.save()
You don't have to apply the cleaned data manually to the profile since the ModelForm does this.

Django: associating a user with model instance

Let's say that I have a model that handles recipes, and I want to allow users to input their own recipes via a form. I then want to associate that recipe entry with the user ID of the user who inputted it. My guess is that my model would look something like this:
class Recipe(models.Model):
name = models.CharField(max_length=100)
body = models.TextField()
creator = models.ManyToManyField(User)
def __unicode__(self):
return self.creator
Is that correct? And if I created a model form, it would look something like this:
class RecipeForm(ModelForm):
class Meta:
model = Recipe
But how would I go about automatically passing the user information to the Recipe model upon submission? Would this take place in my view?
My current view is like this:
def recipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST) #if POST method, bound form to POST data
if form.is_valid():
form.save()
else:
form = RecipeForm() #unbound form.
recipe_list = Recipe.objects.all()
return render_to_response('forms/recipes.html',
{'form': form, 'recipe_list': recipe_list},
context_instance = RequestContext(request))
How would I set the user to the model before saving it?
Yes, your view would need to set the user on the recipe model before saving it.
Edit:
You should accept Ignacio's answer, since he added it in the comment.
Here is how you would add your user:
from django.shortcuts import render
def recipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST) #if POST method, bound form to POST data
if form.is_valid():
obj = form.save(commit=False) # don't save to DB
obj.creator = request.user # adds the user
obj.save()
else:
form = RecipeForm() #unbound form.
recipe_list = Recipe.objects.all()
return render(request,'forms/recipes.html',
{'form': form, 'recipe_list': recipe_list})