Django Context isnt rendered - django

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)

Related

how to have multiple forms in a class based view

I have a simple blog app that you can post news and blog on it. I wanted to show the latest posts on the main page, so I created this class like this:
class MainListView(TemplateView):
template_name = 'Blog/Home.html'
def get_context_data(self, **kwargs):
context = super(MainListView, self).get_context_data(**kwargs)
context['news'] = NEWS.objects.order_by('-published')[:2]
context['posts'] = POSTS.objects.order_by('-published')[:3]
return context
and it works great. however, I wanted to add two additional forms to the main page too. so I added these two functions to the class:
def get(self, request, *args, **kwargs):
return self.render_to_response({'aform': HomeGholakForm(prefix='aform_pre'), 'bform':
HomeContactForm(prefix='bform_pre')})
def post(self, request, *args, **kwargs):
aform = _get_form(request, HomeGholakForm, 'aform_pre')
bform = _get_form(request, HomeContactForm, 'bform_pre')
if aform.is_bound and aform.is_valid():
aform.save()
return redirect('Home-Page')
elif bform.is_bound and bform.is_valid():
bform.save()
return redirect('Home-Page')
return self.render_to_response({'aform': aform, 'bform': bform})
and above this class I created a _get_form function in order for it to work:
def _get_form(request, formcls, prefix):
data = request.POST if prefix in request.POST else None
return formcls(data, prefix=prefix)
in the final stage I added the forms to my template like this:
<form action="">
{% csrf_token %}
{{bform.email}}
<input type="submit" name="{{bform.prefix}}" class="btn" />
</form>
<form action="">
{% csrf_token %}
{{aform.info}}
<input type="submit" name="{{aform.prefix}}" class="btn" />
</form>
After I did this, the forms both work fine, but the latest blog and news are not shown. what am I supposed to do?
get_context_data is normally called by the get or post method whichever is used (only get in TemplateView) and passed as the context while rendering. You override these methods but never call get_context_data. Change your get and post methods like so:
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
context.update({'aform': HomeGholakForm(prefix='aform_pre'), 'bform': HomeContactForm(prefix='bform_pre')})
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
aform = _get_form(request, HomeGholakForm, 'aform_pre')
bform = _get_form(request, HomeContactForm, 'bform_pre')
if aform.is_bound and aform.is_valid():
aform.save()
return redirect('Home-Page')
elif bform.is_bound and bform.is_valid():
bform.save()
return redirect('Home-Page')
context = self.get_context_data(**kwargs)
context.update({'aform': aform, 'bform': bform})
return self.render_to_response(context)
You should consider making some Mixin along the lines of FormMixin which would make your work more easier.

Django ModelForm not saving data even though form.save is executed

I have a website where user have 2 model for their profile, user_detail and user_location. I tried to serve 2 model form on one page with one submit. The problem is when the data from those model form does not save in to the database.
I confirmed that self.request.POST in the post method returns the correct data.
I tried :
Django ModelForm not saving data to database - Does not work
Django ModelForm not saving data - Does not work
The following code if for admins.
Here is my view :
class UpdateProfile(LoginRequiredMixin, UpdateView):
template_name = 'account/user_profile.html'
fields = '__all__'
model = models.UserProfile
user_detail_form_class = forms.UserDetailForm
user_location_form_class = forms.UserLocationForm
def get_context_data(self, **kwargs):
user_profile = get_object_or_404(models.UserProfile, pk=self.kwargs.get(self.pk_url_kwarg))
context = super(UpdateProfile, self).get_context_data(**kwargs)
if 'user_detail_form' not in context:
context['user_detail_form'] = self.user_detail_form_class(instance=user_profile.user_detail)
if 'user_location_form' not in context:
context['user_location_form'] = self.user_location_form_class(instance=user_profile.user_location)
return context
def get(self, request, *args, **kwargs):
super(UpdateProfile, self).get(request, *args, **kwargs)
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
user_detail_form = self.user_detail_form_class(request.POST)
user_location_form = self.user_location_form_class(request.POST)
if user_detail_form.is_valid() and user_location_form.is_valid():
user_detail_form.save()
user_location_form.save()
return redirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data())
def get_success_url(self):
return reverse('account:admin_client_list')
def dispatch(self, request, *args, **kwargs):
if not request.user.groups.filter(name__in=['Admin']).exists():
return errors.render_403(request)
return super(UpdateProfile, self).dispatch(request, *args, **kwargs)
Here is my template :
{% extends 'base.html' %}
{% block content %}
<form method='POST' action="">{% csrf_token %}
{{ user_detail_form }}
{{ user_location_form }}
<input type="submit" value="Submit">
</form>
{% endblock %}
Here is the form :
class UserDetailForm(forms.ModelForm):
class Meta:
model = models.UserDetail
fields = '__all__'
class UserLocationForm(forms.ModelForm):
class Meta:
model = models.UserLocation
fields = '__all__'
You need to pass the instance parameter when you are creating the ModelForm in the post method. Sample code:
user_profile = get_object_or_404(models.UserProfile, pk=self.kwargs.get(self.pk_url_kwarg))
user_detail_form = self.user_detail_form_class(request.POST, instance=user_profile.user_detail)
user_location_form = self.user_location_form_class(request.POST, instance=user_profile.user_location)

Django - ModelChoiceField validation

I have a simple form witch ModelChoiceField. This is a part of my view.py file:
def premium(request, id):
context = {}
try:
site = Site.objects.get(id=id)
except Site.DoesNotExist:
raise Http404("Nie ma takiej strony")
if request.method == 'POST':
premium_form = PremiumForm(request.POST)
if premium_form.is_valid():
# group = Group.objects.get(id=request.POST["kod"])
print('OK')
else:
print('NOT OK')
else:
premium_form = PremiumForm(site)
premium_form.fields['group'].queryset =
premium_form.fields['group'].queryset.exclude(group_name=site.group)
context['site'] = site
context['form'] = premium_form
context['category'] = site.category
context['subcategory'] = site.subcategory
return render(request, 'mainapp/premium.html', context)
This is my form:
class PremiumForm(forms.Form):
def __init__(self, site, *args, **kwargs):
super(PremiumForm, self).__init__(*args, **kwargs)
self.fields['group'].initial = 2
self.fields['group'].empty_label = None
group = forms.ModelChoiceField(
queryset=Group.objects.filter(is_active=True),
help_text="<div id='group'></div>",
label="Some text",
required=False)
My premium.html file:
<form method="post" action="" class="form-horizontal">
{% csrf_token %}
{% bootstrap_form form layout='horizontal'%} <br>
{% bootstrap_button "Submit" size='large' button_type="submit" button_class="btn-primary btn-main-add" %}
</form>
When I press "Submit" button I get "NOT OK". I can't resolve this problem. I don't have any idea how to validate forms.ModelChoiceField. Thanks for any help.
Form should be initialised with kwargs:
premium_form = PremiumForm(site=site)
And inside init:
def __init__(self, *args, **kwargs):
site = kwargs['site']
However, site is not used inside form initialization so you can just remove it and it will solve the issue.

Submit two forms in a single submit in 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

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.