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'})
Related
I'm creating a questionnaire / survey, and have two forms (Model Form) built on the same model. These forms are called on separate views, but when saved they appear as separate users in the database. I'm not sure how to get them so save as the same user, I am already using the ' post = form.save(commit=False), post.user = request.user, post.save()' method to save the forms.
EDIT: Added in an attempt to save to the same instance
Model:
class QuizTakers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
industry_choices = (
(1, 'Service'),
(2, 'Hospitality'),
(3, 'Wholesale/Retail'),
(4, 'Manufacturing'),
(5, 'Agriculture')
)
industry = MultiSelectField(choices=industry_choices, max_length=1, max_choices=1)
company_name = models.CharField( max_length=100)
email = models.EmailField(blank=True)
score = models.FloatField(default=0)
completed = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.company_name
Forms:
# Form for getting company name
class QuizTakerForm(forms.ModelForm):
class Meta:
model = QuizTakers
fields = ['company_name']
# Form for getting company industry
class QTIndustryForm(forms.ModelForm):
class Meta:
model = QuizTakers
fields = ['industry']
Views:
# view for getting company name
def start(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuizTakerForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
request.session['company_name'] = form.cleaned_data['company_name']
post = form.save(commit=False)
post.user = request.user
post.save()
# redirect to a new URL:
return HttpResponseRedirect('industry/')
# if a GET (or any other method) we'll create a blank form
else:
form = QuizTakerForm()
return render(request, 'ImpactCheck/start.html', {'form': form})
# view for getting industry
class IndustryView(FormView):
template_name = 'ImpactCheck/industry.html'
form_class = QTIndustryForm
success_url = '1/'
def get(self, request):
company_name = request.session['company_name']
this_user=QuizTakers.objects.filter(company_name=company_name).order_by('-timestamp').first()
form=self.form_class(instance=this_user)
company_name = request.session['company_name']
return render(request, 'ImpactCheck/industry.html', {'form': form, 'company_name': company_name})
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
post = form.save(commit=False)
post.user = self.request.user
post.save()
return HttpResponseRedirect('/1')
Firstly, in your def start(request) function, you should consider adding the ID to request.session instead of the company name. Something along the lines of
def start(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuizTakerForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
form.instance.user=request.user
form.save()
request.session['obj_id'] = post.id
# redirect to a new URL:
return HttpResponseRedirect('industry/')
Now you can use that id to get both the name of your company, as well as the object.
In your IndustryView(FormView), if you're having trouble with the form instances, it's better to use UpdateView instead of the FormView (Be sure to import UpdateView first)
class IndustryView(UpdateView):
template_name = 'ImpactCheck/industry.html'
model = QuizTakers
fields = ['industry']
success_url = '/1'
def get_object(self):
return QuizTakers.objects.get(pk=self.request.session.get('obj_id'))
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['company_name'] = QuizTakers.objects.get(pk=self.request.session.get('obj_id'))
return ctx
We use the get_context_data method since you need the company_name in your template. The get_object method in this view, tells django which object is to be updated. By default, it grabs the pk from the url (as a url parameter). But since we store our id in the session, we need to explicitly define this function.
Also, since we switched to UpdateView, you no longer need the QTIndustryForm either.
I'm trying to limit number of "categories" that user have available when entering new "feed" only to categories that he owns and he created. The way it works now is that user can add "feed" to other users' "categories" as this is what the form displays. How can I fix it ?
thanks!
-M
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)
class Feed(models.Model):
url = models.URLField()
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
forms.py
class FeedForm(forms.ModelForm):
class Meta:
model = Feed
exclude = ['user']
views.py
def addfeed(request, user):
user = request.user
page_title = "Add feed"
instance = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST, instance=instance)
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,
})
Set the queryset attribute of the field somewhere. Because it depends on your user, it's something you have to set during or after instantiating the form. For instance, here's how to do it in the view:
def addfeed(request, user):
user = request.user # why does this view take user as an arg and then reassign?
page_title = "Add feed"
categories = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
form.fields['category'].queryset = categories
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,})
I removed the instance argument to your POST case's form construction because that's meant for passing in an existing Feed instance, not a categories queryset.
You could also do this in the form's __init__ if you pass in the correct categories queryset.
I use javascript to do this. For example, you could pass a list of the relevant categories as extra context in your view then use javascript in your template to empty the pre-populated option field in the form and replace it with your extra context.
I got this form working Ok but i can't figure out how to save it to the database via the model i know this is a semantic question that i can't figure out Please Help. I'm using django The error is
D = Donation(user=request.user,name=form.cleaned_data['name'],description=cd['description']) D.save()
views.py
def donate(request):
if request.method == 'POST':
form = DonationForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
D = Donation(user=request.user,name=form.cleaned_data['name'],description=cd['description'])
D.save()
return HttpResponseRedirect('/test/')
else:
form =DonationForm()
return render_to_response('addaDonation.html',{'form': form},context_instance=RequestContext(request))
`
Donation is my Model and i need to get the information from my form into the Donation Model so i can D.save
class DonationForm(forms.Form):
name = forms.CharField(max_length=50)
description = forms.CharField(max_length=3000)
towards = forms.CharField()
#image = forms.ImageField()
class Donation (models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=50)
description = models.CharField(max_length=3000)
towards = models.ForeignKey(NonProfit)
image = models.ImageField(upload_to='photos/%Y/%m/%d')
The error I get is
(1054, "Unknown column 'name' in 'field list'")
Request information
GET
No GET data
POST
Variable Value
csrfmiddlewaretoken u'nXGN4gdZwk2qxNpP9YIXzvNQI7lKQe5r'
towards u'this'
name u'this'
description u'that'
change your form class to the following;
from django.forms import ModelForm
class DonationForm(ModelForm):
class Meta:
class = Donation
exclude = ("user", )
def save(self, user):
donation = super(DonationForm, self).save(commit=False)
donation.user = user
donation.save()
return donation
Then you should be able to change the view.py to the following;
def donate(request):
if request.method == 'POST':
form = DonationForm(request.POST, request.FILES)
if form.is_valid():
form.save(request.user)
return HttpResponseRedirect('/test/')
else:
form = DonationForm()
return render_to_response('addaDonation.html',{'form': form},context_instance=RequestContext(request))
See official documentation Creating forms from Models
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})
im django beginner (django 1.2.5)
I have that model:
class Document(models.Model):
file = models.FileField(upload_to='documents/%Y/%m/%d', null=True, blank=True)
title = models.CharField(max_length=30)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User)
#other fields
#other fields
and model form to this:
class DocumentForm(ModelForm):
file = forms.FileField(required=True, error_messages={'required' : 'required!','empty': "empty!"})
title = forms.CharField(widget = forms.TextInput(attrs={'size': 93,}), error_messages={'required': 'required!'})
#other fields
#other fields
class Meta:
model = Document
exclude = ('author',)
def save(self, author, commit=True):
document=ModelForm.save(self,commit=False)
document.author = author
if commit:
document.save()
return document
I uploading new documents in using DocumentForm above and it works pretty but when i trying edit some document i cannot put new file in place previous. I may change every field except FileField.
def document_edit(request, document_id):
doc = get_object_or_404(Document, id=document_id)
form = DocumentForm(instance=doc)
if doc.author == request.user:
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES, instance=doc)
if form.is_valid():
if request.POST.get('cancel'):
return HttpResponseRedirect('/')
elif request.POST.get('delete'):
document = Document.objects.get(id=document_id)
document.file.delete()
document.delete()
return HttpResponseRedirect('/')
else:
form.save(author=request.user)
return HttpResponseRedirect('/')
else:
# return again form with errors
else:
# return form with doc instance
else:
# return "you can't edit this doc!"
I research django documentation and i only know i should write some custom save method in some class but i completely have no idea how can i do this. It should be save() method in Document() or in DocumentForm()?
Generally i want this: When i put path to new file in form i want override this new file in his place and automatically delete previous file.
Can you help me? Thanks in advance!
You are on the right track, you just want to use the instance keyword, so your form reflects the object being edited. Simplified version:
def edit_upload(request, document_id):
doc = get_object_or_404(Document, id=document_id)
if request.method == 'POST': # If the form has been submitted...
form = DocumentForm(request.POST, request.FILES, instance=doc)
if form.is_valid(): # All validation rules pass
if doc.file: # If document has file already...
doc.file.delete() # delete it
form.save() # Saves object, uses new uploaded file
return redirect('/thanks/') # Redirect after success
else:
form = DocumentForm(instance=doc) # Show form to edit
return render(request, 'edit.html', {
'form': form,
})