I would like to be able to present a form to users with a dropdown list of existing records and a delete action for the selected record. So far all I can find are examples that pass the id of record to the form (such as below) and I can get this to work if I hard code the id in the function, but that's obviously not a solution. What am I missing? Thanks.
def DeleteRecord(request, id):
to_delete = get_object_or_404(MyModel, id=id)
#+some code to check if this object belongs to the logged in user
if request.method == 'POST':
form = DeleteRecordForm(request.POST, instance=to_delete)
if form.is_valid(): # checks CSRF
to_delete.delete()
return HttpResponseRedirect("/")
else:
form = DeleteRecordForm(instance=to_delete)
data = {'form': form}
return render(request, 'deleteprimerpair.html', data)
Related
Can I make my page return with the information previously entered when the form is invalid?
Views.py
def MyView(request):
[...code...]
if request.method == 'POST':
form = MyForm(request.POST or None)
if form.is_valid()
//do something and redirect to success page
else:
//back to the page with the information filled in by the user (HERE IS MY PROBLEM)
the line form = MyForm(request.POST or None) creates a MyForm object called form with request data assigned to it - its kinda like filled out form. The is_valid() method checks for errors in your form and adds particular errors to your form so this is now a filled out form with errors assigned. If you want to return this form to user you should add it to context so considering its a standard django function based view it should look like this:
def MyView(request):
[...code...]
if request.method == 'POST':
form = MyForm(request.POST or None)
if form.is_valid()
form.save()
return render(request, 'succes_page_template.html')
else:
return render(request, 'current_template.html', context = {'form': form})
if the form is invalid the next thing the user sees is same page where he filled out the form ('current_template.html') but with all the fields filled with data he/she already put it also form will have erros assigned to particular fields so you can print them. If you are new to Django I suggest getting into class based views from the start - they do the heavy lifting for you and refactoring + debugging becomes much easier. here is the link cheers!
Ive got a large questionnaire for users to complete. Because its so big I decided to break it into three separate forms on three consecutive pages.
The urls are: questionnaire/section_1, questionnaire/section_2, questionnaire/section_3.
After submitting each form, the form data is saved to the database, and after the final (3rd) form, the three forms are saved as a single pdf for that user. Its important that users complete each of the three questionnaires.
My problem is that users will be able to use the address bar to type www.website/questionnaire/section_3 and complete just the third section, skipping the first two and submitting an incomplete questionnaire.
I cant think of any way to restrict users from accessing later parts of the form until prior parts have been successfully validated and saved.
PS - I have thought about setting permission for each of the three forms, adding permissions to the user once they have submitted one form, but I feel this is hacky??
Thank you.
This is the way I ended up dealing with this.
#allowed_users(allowed_roles=['admin', 'registered_user'])
def page_two(request):
if request.method == 'POST':
form = FormTwoForm(request.POST, request.FILES, instance=request.user.formtwo)
if form.is_valid():
form.save()
return redirect('page_three')
else:
# redirect if user didnt access the page from personal_information
if(request.META.get('HTTP_REFERER') != request.build_absolute_uri(reverse('form_one'))):
return redirect('form_one')
else:
form = FormTwoForm(instance=request.user.formtwo)
context = {
'form' : form
}
return render(request, 'example/form_two.html', context)
#allowed_users(allowed_roles=['admin', 'registered_user'])
def form_three(request):
if request.method == 'POST':
form = FormThreeForm(request.POST, request.FILES, instance=request.user.formthree)
if form.is_valid():
form.save()
return redirect('form_four')
else:
# redirect if user didnt access the page from needs_analysis
if(request.META.get('HTTP_REFERER') != request.build_absolute_uri(reverse('form_two'))):
return redirect('form_two')
form = FormThreeForm(instance=request.user.formthree)
context = {
'form' : form
}
return render(request, 'example/form_four.html', context)
I am trying to use same view for creating form and updating any object.
My code is as below, I tried in many ways nothing is working, since I am excluding the shof from form and adding it after form.is_valid() it makes lot of confusion. If I update it creates new object. I have two urls one without ql (create new) and one with ql (update existing), I have a class vdview which provides v.shof which needs to applied in the f.shop in form. please help fix this,
#csrf_protect
#login_required
def addmenu(request, qs, ql=None):
v = vdview(request, qs)
ctgobj = get_object_or_404(v.shopcategs, pk=ql) if ql else None # ctgobj = ShopCtg(shop=v.shof)
if ql:
form = ShopCtgForm(instance=ctgobj) # Tried ShopCtgForm(instance=ctgobj, data=request.POST)
else:
form = ShopCtgForm(data= request.POST)
if request.method == 'POST':
if form.is_valid():
f=form.save(commit=False)
f.shop = v.shof
f.save()
#form.save_m2m()
return redirect('vendor-shop', qs) #thing='%s added' %f.name)
else:
pass
#else:
# form = ShopCtgForm()
return render(request,'vendorshop.html', {'shop':v.shof, 'shopcategs':v.shopcategs, 'form': form,
'heading':'Create New Category', 'createcateg': 'createcateg', 'pkaddmenupk':'y' } )
Use try blocks to handle both scenarios. The simplified example below will look for a given model instance pk and if it doesn't find it, will assume you want to create it. try will prevent django from throwing an error if the model instance doesn't exist. Rather, it will just return the empty model form.
It does this first to render the correct form in the template (the first try block) then again in the second try block after request.method == 'POST': to submit new data or update existing data.
Views.py
from .models import Books
from .forms import BookForm
def create_and_update_book_view(request, pk):
books = Books.objects.get(id=pk)
try: # get pre-populated form with model instance data (for update)
form = BookForm(instance=books.id)
except: # If it doesn't exist, show an empty form (for create)
form = BookForm(request.POST or None)
if request.method == 'POST':
try: # Do the same as above
form = BookForm(instance=books.id)
except: # Same as above
form = BookForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "create_and_update_book_page.html", {'form':form})
After form.is_valid(), we get form.cleaned_data. How can i use this cleaned data on the next page.
For example, after the form page is processed we redirect the customer to next page, where I want to use the cleaned_data's info like name, contact, address..etc fields to be shown in next page.
def ind(request):
if request.method == 'POST':
form = form_name(request.POST)
if form.is_valid():
print(form.cleaned_data)
return render(request, 'app_one/abc.html', {'data': form.cleaned_data})
# form.save(commit=True)
# return render(request,'app_one/index.html')
else:
form=form_name()
return render(request,'app_one/index.html',{'form':form)
We will have a validated data after calling the form.is_valid() method. Once we have a validated data then we can use as we like.
For your case
customer details which are filled on the first page need show those details on the second page as receipt.
You can create a model named Reciept and save the details in the model for future reference. If you want these details in the other page views then simply pass the model object in context to render the details.
You can use the cleaned data like below
def ind(request):
if request.method == 'POST':
form = form_name(request.POST)
if form.is_valid():
context = {}.update(form.cleaned_data)
return render(request, 'app_one/abc.html', context)
# form.save(commit=True)
# return render(request,'app_one/index.html')
else:
form=form_name()
return render(request,'app_one/index.html',{'form':form)
Example Form:
class MyForm(forms.Form):
reciept_num = forms.CharField()
consider above form as an example
You can access the reciept_num data in template using the name reciept_num.
You can assign the cleaned_data to variables as usual for forms
e.g. your_data=form.cleaned_data['your_data']
After that, pass those variables to context.
e.g. context = {
'your_data':your_data
}
Lastly return the template.
e.g. return(request,'template.html',context=context)
At the 'template.html', use the variables as {{your_data}}.
I have a model with a ManyToManyField and in my view I want to be able to add new options to the generated selectbox
How can I handle those new items with get_or_create function?
I want to check for form validity before saving it, but it will never be valid because I have to create all the new ManyToMany items.
In the meantime, I don't want to add new items if the form is not valid...
So I'm stuck with this not-working-code:
def add_entry(request):
if request.method == 'POST':
form = EntryForm(data=request.POST)
model_instance = form.save(commit=False)
for tag in model_instance.tags.all():
t, created = Tag.objects.get_or_create(author=request.user, title=tag.title)
model_instance.tags.add(t)
if form.is_valid():
model_instance.save()
return HttpResponseRedirect("/")
else:
form = EntryForm()
return render_to_response(
'add_entry.html',
{'form' : form },
context_instance=RequestContext(request))
EDIT:
my code is now
def add_entry(request):
if request.method == 'POST':
form = EntryForm(data=request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.save()
form.save_m2m()
return HttpResponseRedirect("/")
else:
print form.errors
else:
form = EntryForm()
return render_to_response(
'add_entry.html',
{'form' : form },
context_instance=RequestContext(request)
)
and i can save existing tags, but i can't dinamically add new ones...
I guess you are using some sort of JS to add the tags dynamically. I suggest you to go further and create an API endpoint where you can actually save the created tags so they can became a valid options of the selectbox.