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.
Related
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()
I have the following models
class Make(models.Model):
make_name = models.CharField(max_length=32)
def __unicode__(self):
return self.book_title
class MakeModel(models.Model):
model_number = models.IntegerField()
model_capacity = models.IntegerField()
model_capacity_unit = models.CharField(max_length=4)
Make = models.ForeignKey(Make)
def __unicode__(self):
return self.model_number
Basically, I want my form to have all the Make details at the top, and all the MakeModel details in a grid below, and to be able to add more MakeModels with ease. Such as in this mockup
https://www.dropbox.com/s/e7rg3zxe6y8q9fi/invoicedetails.gif
Any ideas what needs doing? People mention things like inlineformset_factory, but I'm not convinced either how to use it, or if it will do the thing I expect.
Any help would be appreciated
You need a form and a formset.
A form: one form
A formset: multiple copies of one form
Your view would look something like this in the POST cycle:
Update: oh right, foreignkey. The easiest way to be honest is just to commit=False the formset and manually assign the FK. You can use an inlineformset as well. https://docs.djangoproject.com/en/dev/ref/forms/models/#django.forms.models.inlineformset_factory
FormSet = modelformset_factory(MakeModel)
Form = modelform_factory(Make)
def myview(request):
formset = FormSet(request.POST or None)
form = Form(request.POST or None)
if request.method == 'POST':
if formset.is_valid() and form.is_valid():
main_instance = form.save()
formset.save(commit=False)
for instance in formset:
instance.fk = main_instance
instance.save()
https://docs.djangoproject.com/en/dev/topics/forms/formsets/
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.
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})
I would like to modify a user submitted form to automatically insert the project_id, but I keep getting the error that project_id in the Employee model cannot be null;
My model:
class Project(models.Model):
name = models.CharField(max_length=100)
date_started = models.DateTimeField()
class Employee(models.Model):
name = models.CharField(max_length=200)
project = models.ForeignKey(Project)
class AddEmployeeForm(ModelForm):
class Meta:
model = Employee
exclude = ('project',)
My view:
def emp_add(request, project_id):
if request.method == 'POST':
post = request.POST.copy() # make the POST QueryDict mutable
post('project', project_id)
form = AddEmployeeForm(post)
if form.is_valid():
saved = form.save()
Like this?
if form.is_valid():
employee = form.save(commit=False)
employee.project = Project.objects.get(pk=project_id)
employee.save()
#maciag.artur's answer, to save with commit=False will work. Another way is to instantiate an Employee with the required project_id, and use it to construct the form.
This is useful if your model form's custom clean method relies on the Employee.project field.
def emp_add(request, project_id)
if request.method == 'POST':
# create a new employee with the given project id
employee = Employee(project_id) = project_id
form = AddEmployeeForm(request.POST, instance=employee)
if form.is_valid():
saved = form.save()
<snip>
For reference, see the note box below Using a subset of fields on the form in the Django docs.
Add the project ID to the form as a hidden input. When the request comes back as a POST, it will exist in the POST object, from the form.
def emp_add(request, project_id):
if request.method == 'POST':
post = request.POST.copy() # make the POST QueryDict mutable
post('project', project_id)
form = AddEmployeeForm(post)
if form.is_valid():
saved = form.save()
else:
form = AddEmployeeForm(initial={'project_id':'my_id_value'})