Submit two forms in a single submit in Django - django

I have two forms in template. At the moment I have two submit buttons.
Would like to combine those to a single submit button.
Below code is now updating only one form, that's AnswerForm.
How i can update AnswerReplyForm along with that?
class AnswerView(ObjectEditView):
form_class = forms.AnswerReplyForm
answer_form = forms.AnswerForm
model = AnswerReply
def get(self, request, pk):
answer = get_object_or_404(Answer, pk = pk)
answer_reply = AnswerReply.objects.filter(answer_id = pk).order_by('-id')
self.answer_form = self.answer_form(instance=answer)
return render(request, 'helpdesk/answer.html', {
'answer': answer,
"answer_reply" : answer_reply,
'obj_type': 'answer reply',
'form': self.form_class,
"form2":self.answer_form,
"pre_reply_from" : self.predefined_reply_form
})
def post(self, request, pk, *args, **kwargs):
answer = get_object_or_404(Answer, id=pk)
answer_reply = AnswerReply.objects.filter(answer_id = pk).order_by('-id')
self.answer_form = self.answer_form(instance=answer)
obj = self.model()
obj = self.alter_obj(obj, request, args, kwargs)
form = self.form_class(request.POST, request.FILES, instance=obj)
if form.is_valid():
form.instance.answer_id = pk
obj_created = not form.instance.pk
obj = form.save()
return render(request, 'helpdesk/answer.html', {
'answer': answer,
"answer_reply" : answer_reply,
'obj_type': 'answer reply',
'form': self.form_class,
"form2":self.answer_form,
})

In general:
if request.method == 'POST':
form_1 = FormOne(request.POST)
form_2 = FormTwo(request.POST)
if form_1.is_valid() and form_2.is_valid():
form_1.save()
form_2.save()
return #Write your return here, something like HttpResposeRedirect or whatever you need to do after saving both form successfully
else:
form_1 = FormOne()
form_2 = FormTwo()
context = {
'form1': form_1,
'form2': form_2
}
return render(request, 'template.html', context)
In your template file
<form>
{{ form1 }}
{{ form2 }}
<input type="submit" value= "submit">
</form>
It will work.

It's better to define a structure for each one (View, route and template)
Then, based on desired condition, display one of the structures (redirect to one of them):
for example decision view:
def decisionView(request):
route = '/route/1'
if condition:
route = '/route/2'
return redirect(route)
i hope this could help you

Related

Django Context isnt rendered

I want to render a view with some content. I don't get why the context isn't rendered.
The render_recall_details() function causes problems --> ctx is not None, In my opinion there is no reason why it is not rendered in the html file
views.py
class RecallDetail(View):
template_name = "recall_detail.html"
def get(self, request, *args, **kwargs):
if request.GET:
q = request.GET
q = q.dict()
recall = find_recall_by_querystring(q)
if recall:
self.render_recall_details(request, recall)
else:
return render(request, self.template_name)
return render(request, self.template_name)
def render_recall_details(self, request, obj, *args, **kwargs):
ctx = {
'head': 'Hallo',
'rec': RecallForm(),
'docs': find_docs(obj),
}
print(ctx)
return render(request, self.template_name, context=ctx)
forms.py
class RecallForm(forms.ModelForm):
class Meta:
model = Recall
fields = ('Recall_CODE', 'Recall_NAME', 'Recall_DESCRIPTION', 'Recall_START_DATE', 'Recall_PLANNED_COMPLETATION_DATE', 'Recall_STATUS', 'Recall_DATE_COMPLETED')
my html_template:
{% extends 'base.html' %}
{% block content %}
<div class="content-wrapper">
<h1>{{ head }}</h1>
...
</div>
{% endblock content %}
It seems like a typo in your code-base. In Django, every view must return a response. So, in your case, you are not returning anything if the variable recall has some value. So, change your view as,
class RecallDetail(View):
template_name = "recall_detail.html"
def get(self, request, *args, **kwargs):
if request.GET:
q = request.GET
q = q.dict()
recall = find_recall_by_querystring(q)
if recall:
# you need to put the `return` statement here
return self.render_recall_details(request, recall)
else:
return render(request, self.template_name)
return render(request, self.template_name)
def render_recall_details(self, request, obj, *args, **kwargs):
ctx = {
'head': 'Hallo',
'rec': RecallForm(),
'docs': find_docs(obj),
}
print(ctx)
return render(request, self.template_name, context=ctx)

how to receive modelform_instance.cleaned_data['ManyToMany field'] in view when form field is ModelMultipleChoiceField?

Here is the situation:
I have a model as below:
class School(Model):
name = CharField(...)
Permit model has three objects:
School.objects.create(name='school1') # id=1
School.objects.create(name='school2') # id=2
I have another model:
Interest(Model):
school_interest = ManyToManyField(School, blank=True,)
I then build a ModelForm using Interest:
class InterestForm(ModelForm):
school_interest = ModelMultipleChoiceField(queryset=School.objects.all(), widget=CheckboxSelectMultiple, required=False)
class Meta:
model = Interest
fields = '__all__'
I have a view:
def interest(request):
template_name = 'interest_template.html'
context = {}
if request.POST:
interest_form = InterestForm(request.POST)
if interest_form.is_valid():
if interest_form.cleaned_data['school_interest'] is None:
return HttpResponse('None')
else:
return HttpResponse('Not None')
else:
interest_form = InterestForm()
context.update({interest_form': interest_form, })
return render(request, template_name, context)
and in interest_template.html I have:
<form method="post">
{% csrf_token %}
{{ interest_form.as_p }}
<button type="submit">Submit</button>
</form>
I expect to see None when I check no one of the form fields and submit it.
I expect to see 'Not None' when I check any or all of the form fields and submit the form.
However, I do not see what I expect to happen.
I changed my view to this and it worked:
def interest(request):
template_name = 'interest_template.html'
context = {}
if request.POST:
interest_form = InterestForm(request.POST)
if interest_form.is_valid():
if not interest_form.cleaned_data['school_interest']:
return HttpResponse('None')
else:
return HttpResponse('Not None')
else:
interest_form = InterestForm()
context.update({interest_form': interest_form, })
return render(request, template_name, context)

Django, how to include pre-existing data in update form view

I am unable to see pre-existing form data when updating. The forms work fine, after submitting the database is updated, but in order to submit the user must enter all form data (including data that will not be updated). While reentering, the previous data is not visible. Is there a way to display the current data of the model instance being updated in the form fields?
Forms:
UpdateSomethingForm(forms.ModelForm):
class Meta:
model = Something
fields = ['field1', 'field2', 'field3']
Views:
def update_something(request, object_pk):
form = UpdateSomethingForm()
context_dict = {}
try:
instance = Something.objects.get(pk=object_pk)
context_dict['instance'] = instance
except Something.DoesNotExist:
context_dict['instance'] = None
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('/home')
else:
print(form.errors)
context_dict['form'] = form
return render(request, 'form.html', context=context_dict)
Html:
<form role="form" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
You passed the instance argument on POST, but not on GET.
form = UpdateSomethingForm(instance=instance)
in full:
def update_something(request, object_pk):
try:
instance = Something.objects.get(pk=object_pk)
except Something.DoesNotExist:
instance = None
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return HttpResponseRedirect('/home')
else:
form = UpdateSomethingForm(instance=instance)
context_dict = {'form': form, 'instance': instance}
return render(request, 'form.html', context_dict)
The main problem is that you construct an empty Form, even if the instance can be found. But you make the view rather "chaotic" in the first place.
Probably a more readable view is:
def update_something(request, object_pk):
context_dict = {}
try:
instance = Something.objects.get(pk=object_pk)
except Something.DoesNotExist:
instance = None
context_dict['instance'] = instance
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save(commit=True)
return redirect('view_name')
else:
form = UpdateSomethingForm(instance=instance)
context_dict['form'] = form
return render(request, 'form.html', context=context_dict)
Here we ensure that the instance variable is always defined, also in the case the except body is "firing".
Furthermore it is probably better to use a redirect(..) and pass the name of the view over an URL, since if you change the URL of that view, this will still work.

FormView with get method doesn't show the form

Thanks for read :/
When I remove the "get" from the view, the form works, but when I put it back, it doesn't render.
URL at the browser:
http://127.0.0.1:8000/activate?tpr=1140277&idpr=42
URLs:
url(r'^activate', Activation_vw.as_view(), name='activate')
VIEW:
class Activation_vw(FormView):
template_name = 'activate.html'
form_class = Activation_Form
success_url = '/dashboard/'
def get(self, request, *args, **kwargs):
tokenProspect_v = request.GET.get('tpr')
idProspect_v = request.GET.get('idpr')
USER = USERS.objects.filter(
id=idProspect_v).values('id', 'email', 'token')
if int(tokenProspect_v) != int(USER[0]['token']):
message = "Check the URL"
else:
message = USER[0]['email']
context = {'msg': message}
return self.render_to_response(context)
def form_valid(self, form):
# No code yet
return super(Activation, self).form_valid(form)
FORM:
class Activation_Form(forms.Form):
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput())
TEMPLATE:
Hello, {{ msg }}
<form action="" method="POST">
{%csrf_token%}
{{ form.as_p }}
<button type="submit">Activate</button>
</form>
All of them have the imports at the top of each file.
The get function works perfectly, I receive the tpr and the idpr but the form doesn't and because of that the form form_valid and the success_url doesn't work neither.
I suspect something is wrong in the return of my get, but can't figured out.
It is because your form is not being passed in the context:
context = {'msg': message}
return self.render_to_response(context)
You can use get_context_data to get the context and update it as you go:
context = self.get_context_data(msg=message)
return self.render_to_response(context)
This will call the get_context_data from the super class and include the form to the context along with adding the message.

Django Crud Operations in Single View

My online marketing department tracks thousands of rows of email and analytic marketing data and I am building a tool that we can use in-house to manage the data so we can run multiple queries to produce reports.
The CRUD operations are working normally, but with so much data to enter, its inefficient to have ticket_form.html, ticket_list.html and a ticket_confirm_delete.html views and templates. My list data is in table format, so what I would like to do is combine the operations under a single view so I can add a column at the end of my table with icons to add, update and delete the row. Thank you for your help.
My current views, I'd like to combine:
class TrafficForm(ModelForm):
class Meta:
model = Traffic
fields = ['sessions', 'new_users', 'reminder', 'campaigns', 'new_sales', 'sales_renewals']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['sessions'].widget.attrs.update({
'placeholder': 'Sessions',
...
})
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control placeholder-no-fix'
})
def traffic_create(request, template_name='traffic_form.html'):
form = TrafficForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('traffic_list')
return render(request, template_name, {'form': form})
def traffic_list(request, template_name='traffic_list.html'):
traffic = Traffic.objects.all()
data = {}
data['object_list'] = traffic
return render(request, template_name, data)
def traffic_update(request, pk, template_name='traffic_form.html'):
traffic = get_object_or_404(Traffic, pk=pk)
form = TrafficForm(request.POST or None, instance=traffic)
if form.is_valid():
form.save()
return redirect('traffic_list')
return render(request, template_name, {'form': form})
def traffic_delete(request, pk, template_name='traffic_confirm_delete.html'):
traffic = get_object_or_404(Traffic, pk=pk)
if request.method == 'POST':
traffic.delete()
return redirect('traffic_list')
return render(request, template_name, {'object': traffic})
Use the following code for reference
class TrafficForm(ModelForm):
def get_absolute_url(self):
#return edit url
def get_delete_url(self):
#return delete url
View function
def crud_traffic_view(request, template_name= "crud_traffic.html"):
all_objects = Traffic.objects.all()
form = TrafficForm()
context_dict = {"form" : form, "all_objects" : all_objects}
return render(request, template_name, {'all_objects' : all_objects})
Template
<table>
{% for traffic in all_objects %}
<tr>
<td>{{traffic.details}} </td>
<td>Edit</td>
<td> Delete</td>
</tr>
{% endfor %}
</table>
<form action="{% url 'add_traffic' %}" method="POST">
{% csrf %} {{form}}
...
</form>
This would let you manage all things from one page (only going to another page for edit/delete confirmation).
You can add ajax calls to update the template if you wish to make it even faster.