Filter Value Displaying Strange in Django - python

I am using a filter and .aggregate to sum up the value of a column cases in my Manifests model. When this displays in the template it gives me the correct amount, but when the page displays it shows as, for example, {'cases__sum': 1192}. The number 1192 there is indeed the sum, but I don't want the rest of the text to show to the user! How can I stop this and get just the number?
views.py
def add_manifest(request, reference_id):
form = CreateManifestForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
instance = form.save(commit=False)
try:
order = Orders.objects.get(id=reference_id)
instance.reference = order
except Orders.DoesNotExist:
pass
instance.save()
form = CreateManifestForm(initial={'reference': Orders.objects.get(reference=reference_id)})
reference = request.POST.get('reference')
manifests = Manifests.objects.all().filter(reference=reference)
total_cases = Manifests.objects.filter(reference=reference).aggregate(Sum('cases')) #totaling the cases for the readonly field
totalCNF = 0
for item in manifests:
totalCNF += item.cases * item.CNF
context = {
'form': form,
'reference_id': reference_id,
'manifests' : manifests,
'total_cases': total_cases,
'totalCNF': totalCNF,
}
return render(request, 'add_manifest.html', context)
add_manifest.html
<label for="form.reference" class="formlabels">Case Total:</label><br>
<input type="text" value="{{ total_cases }}" readonly>
I just want the number, not the whole reference to display in this HTML input box

The aggregate values are stored in dictionaries. You can use
{{ total_cases.cases__sum }}
to show the value only, or do it while constructing your context variable:
...
'total_cases': total_cases['cases__sum'],

Related

Django: Initialize date input dynamically

I'm building a simple web app where users can log new entries that have a name (CharField) and a date.
By default, the date is set to the current date:
class EntryForm(forms.Form):
entry_name = forms.CharField(label='New Entry', max_length=100)
entry_date = forms.DateField(initial=datetime.date.today, widget=forms.widgets.DateInput(attrs={'type': 'date'}))
If users select a different date and add an entry with that date, I want the selected date to persist as new initial value when the page reloads.
I know there are a lot of related questions on setting initial values dynamically, but unfortunately, I still could achieve setting an initial value dynamically.
My view with the form looks like this:
#login_required
def index(request):
if request.method == 'POST':
form = EntryForm(request.POST)
if form.is_valid():
# get the label name and strip and convert to lower before saving it
entry_name = form.cleaned_data['entry_name'].strip().lower()
entry_date = form.cleaned_data['entry_date']
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index'))
else:
form = EntryForm()
# other, unrelated stuff stuff ...
context = {
'form': form,
}
return render(request, 'app/index.html', context)
Even setting the initial value of a form field to a fixed value inside the view's else branch didn't work. I tried EntryForm(initial={'entry_name': 'test'}) (also for entry_date) without success. Also form.fields['entry_name'].initial = 'test', which didn't work either. In both cases, the from's entry_name remained empty when reloading the page.
What's the problem? How can I set the initial value in the form (neither for name nor for date)?
Is it somehow because the form is still unbounded?
If setting the initial value in the view worked, I think I could simply set it when the date is entered and it should stay when the page is reloaded since I pass the form (with the adjusted initial value) in the context dict when rerendering the page.
Edit: This is how I render my form in the template:
<div class="input-group">
<input type="text" class="form-control" id="{{ form.entry_name.id_for_label }}" name="{{ form.entry_name.html_name }}" aria-label="new entry field">
{{ form.entry_date }}
<div class="input-group-append">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
Oh, I think I didn't test correctly. In fact, setting
form = EntryForm(initial={'entry_date': '2020-12-12'})
inside my view does work fine and the date gets initialized as configured.
I guess, I just tried passing a datetime.date before or tested with initializing entry_name, but that didn't work because of how I render entry_name in the template.
To persist the previously entered date, I added an optional argument init_date to my index view, which is set according to the previously entered date:
def index(request, init_date=datetime.date.today()):
if request.method == 'POST':
form = EntryForm(request.POST)
if form.is_valid():
entry_name = form.cleaned_data['entry_name'].strip().lower()
entry_date = form.cleaned_data['entry_date']
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index_with_date', args=[entry_date]))
else:
form = EntryForm(initial={'entry_date': init_date})
For that, I added another URL pattern:
path('add/<entry_name>/<yyyymmdd:entry_date>/', views.add_entry, name='add_entry_with_date'),
With the following date converter:
class DateConverter:
regex = '\d{4}-\d{2}-\d{2}'
def to_python(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d')
def to_url(self, value):
return value
register_converter(DateConverter, 'yyyymmdd')

Retrieve variable from instance of Django form

I have a Django form NameForm. I am attempting to iterate over an array of values and, for each value, have an option to display the same form. The only thing that should change with the form submission should be the associated value to which the form is displayed next to.
This becomes much clearer with an example. For some array [1,2,3] we should display:
We can then click on any open form icon, fill out the NameForm form. The resultant information, including the form_id (in this case 1, 2, or 3) should be returned to forms.py. How can I fetch the form_id variable from an instance of NameForm in index.py?
My (hacky) attempt can be found below. The problem is I don't know how to access the form_id variable I created in the NameForm object.
forms.py
class NameForm(forms.Form):
form_id = None
your_name = forms.CharField(label='Your name', max_length=3)
views.py
def index(request):
if request.method == 'POST':
form = NameForm(request.POST)
form_id = form.form_id # The problem line, as form_id is always None
if form.is_valid():
return HttpResponse( \
' '.join((str(form.cleaned_data['your_name']),form_id ))\
) #Throws TypeError as can't join None and string
else:
forms = []
vals = [1,2,3]
for val in vals:
form = NameForm()
form.form_id = val
forms.append(form)
return render(request, 'post/index.html', {'forms': forms})
index.html
{%for form in forms%}
{{form.form_id}}
<button class="button" onclick="openForm()">Open Form</button>
<div class="myForm">
<form class="form-container" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
<button class="button" onclick="closeForm()">Cancel</button>
</form>
</div>
</br>
{%endfor%}
In Django Form or Django Model, when you set a field's value to None, it is assumed that you want to ignore said field. This is helpful when creating a model that inherits from another model and you want to remove some unnecessary fields.
If you want to set value for a field on Form creation, you should pass it into __init__ method. E.g:
class NameForm(forms.Form):
form_id = forms.IntegerField(widget=forms.HiddenInput())
your_name = forms.CharField(label='Your name', max_length=3)
def __init__(self, form_id, *args, **kwargs):
self.fields['form_id'].initial = form_id
Alternatively, instead of overriding the __init__ method, you can set an initial value for form_id when you create an instance of NameForm. For example:
vals = [1,2,3]
forms = [NameForm(initial={'form_id': val}) for val in vals]

"Didn't return an HttpResponse object. It returned None instead" on POST request

I'm trying to pass a selection from a dropdown form into views as a POST request, then using this selection to query some data from django. I'm then using these queries to try and follow this approach to map django models data to highcharts. The problem is I'm getting a "the view properties.views.property_list didn't return an HttpResponse object. It returned None instead" error when I submit the form. I've looked through similar questions on SO but none of the solutions seem to work/be applicable to my case. Perhaps my form is invalid, though I'm not sure what's causing that to be the case. Below is the code that I've written:
views.py
def property_list(request):
if request.user.is_authenticated():
current_user_groups = Group.objects.filter(id__in=request.user.groups.all())
current_user_properties = Property.objects.filter(groups__in=current_user_groups)
current_user_meters = Meter.objects.filter(meter_id__in=current_user_properties)
property_meter_data = MeterData.objects.filter(meter__in=current_user_meters)
class AccountSelectForm(forms.Form):
accounts = forms.ModelChoiceField(queryset=current_user_meters)
accounts.widget.attrs.update({'class' : 'dropdown-content'})
form = AccountSelectForm()
if request.method == "POST":
if form.is_valid():
selection = form.cleaned_data['accounts']
current_user_groups = Group.objects.filter(id__in=request.user.groups.all())
current_user_properties = Property.objects.filter(groups__in=current_user_groups)
current_user_meters = Meter.objects.filter(meter_id__in=current_user_properties)
selected_meters = Meter.objects.filter(name=selection)
selected_meter_data = MeterData.objects.filter(name=selection)
usage_data = {'usage': [], 'dates': []}
for meter in selected_meter_data:
usage_data['usage'].append(meter.usage)
usage_data['dates'].append(meter.usage)
# data passing for usage chart
usage_xAxis = {"title": {"text": 'Date'}, "categories": usage_data['dates']}
usage_yAxis = {"title": {"text": 'Usage'}, "categories": usage_data['usage']}
usage_series = [
{"data": usage_data['usage']},
]
return HttpResponseRedirect('properties/property-selected.html', {
'form': form,
'usage_xAxis': usage_xAxis,
'usage_yAxis': usage_yAxis,
'usage_series': usage_series,
'current_user_meters': current_user_meters,
'selection': selection,
'selectected_meters': selected_meters,
'selected_meter_data': selected_meter_data,
})
else:
current_user_groups = Group.objects.filter(id__in=request.user.groups.all())
current_user_properties = Property.objects.filter(groups__in=current_user_groups)
current_user_meters = Meter.objects.filter(meter_id__in=current_user_properties)
property_meter_data = MeterData.objects.filter(meter__in=current_user_meters)
return render(request, 'Properties/properties.html',{
'form': form,
'current_user_groups': current_user_groups,
'current_user_properties': current_user_properties,
'current_user_meters': current_user_meters,
'property_meter_data': property_meter_data
})
else:
# If the usre isn't authenticated, the user is redirected to the Sign-n Page
return render(request, 'SignIn/SignInPage.html')
template.html
<!-- Query based content for dropdown menu -->
<form method="POST" action="" id="property-select">
{% csrf_token %}
{{ form.accounts }}
<input type="submit" value="Submit" class="submit-button" style="margin-top:30px;"/>
</form>
If method=='POST' and your form is invalid, nothing is returned.

Django not a valid value for a primary key error in ModelMultipleChoiceField

I created a form consisting of two ModelMultipleChoiceFields of all the countries in the world.
But after a POST request, Django doesn't deem the form valid with the error:
"Algeria" is not a valid value for a primary key
(or whichever country I select). Here is my form:
class ComparisonForm(forms.Form):
country_1 = forms.ModelMultipleChoiceField(
queryset=WorldBorder.objects.values_list('name',flat=True)
)
country_2 = forms.ModelMultipleChoiceField(
queryset=WorldBorder.objects.values_list('name',flat=True)
)
The list of countries is drawn from the db, which works fine. And my views:
def lookup(request):
if request.method == "POST":
form = ComparisonForm(request.POST)
if form.is_valid():
results = form.save(commit=False)
country_1 = WorldBorder.objects.get(name=results.country_1)
country_2 = WorldBorder.objects.get(name=results.country_2)
country_1_name = country_1.name
country_2_name = country_2.name
multiplier = round(country_2.area / country_1.area, 1)
return render(
request, 'results.html', {
'country_1': dummy,
'country_1': country_1_name,
'country_2': country_2_name,
'multiplier': multiplier,
}
)
else:
return render(request, 'error.html', {'form': form})
else:
form = ComparisonForm()
return render(
request, 'lookup.html', {'form': form}
)
And finally the html belonging to the form:
{% extends "base.html" %}
{% block content %}
<h2>Compare the size of two countries here:</h2>
<form id="comparison" action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" name="compare" value="Go compare!">
</form>
{% endblock %}
I am quite new to Django and somewhat at a loss as to how to solve this.
From where I am looking at it, Django is doing exactly what i want it to do (passing the names of two countries so it can compare the size) yet it tells me the form is invalid. How do I solve this? Thanks in advance for your help, it's greatly appreciated!
My two cents (haven't tested): 1. remove .values_list('name',flat=True)
country_1 = forms.ModelMultipleChoiceField(
queryset=WorldBorder.objects.all()
)
country_2 = forms.ModelMultipleChoiceField(
queryset=WorldBorder.objects.all()
)
specify a __str__() or __unicode__() for the WorldBorder model.
Learning from the answers I got here (thank you so much all!), this is how i solved it:
There is no need to define the POST of the form again as results.
As the data in the ComparisonForm is drawn directly from the db, I can use the ids from the form in POST to pull the countries from the database. No need to use the actual country names in querying the db.
So the views.py becomes:
def lookup(request):
if request.method == "POST":
form = ComparisonForm(request.POST)
if form.is_valid():
# pull country ids from POST and then GET objects from db
country_1_id = request.POST.get('country_1')
country_2_id = request.POST.get('country_2')
country_1_db = WorldBorder.objects.filter(id=country_1_id)
country_2_db = WorldBorder.objects.filter(id=country_2_id)
# pull country names and areas
country_1_name = country_1_db.values_list('name', flat=True)[0]
country_2_name = country_2_db.values_list('name', flat=True)[0]
country_1_area = country_1_db.values_list('area', flat=True)[0]
country_2_area = country_2_db.values_list('area', flat=True)[0]
multiplier = round(country_2_area / country_1_area, 1)
And further as above.

How to access user input (POST) in different Django views

I have a view called "search" which stores POST input as "search_id" but "search_id" is only available in the scope of the view "search". I want to be able to access the variable "search_id" in my view "dispTable".
Disclaimer- if this part of my question makes no sense, plz ignore: I understand that I could add an additional parameter to dispTable which would allow me to pass the search_id into dispTable in a return statement but what if I wanted to be able to access search_id in multiple views.
def search(request):
if request.method == 'POST' :
search_id = request.POST.get('textfield', None)
try:
return dispTable(request)
except Person.DoesNotExist:
return HttpResponse("no such user")
except Person.MultipleObjectsReturned :
#return dispTable(request, search_id)
return showResults(request)
else :
return render(request, 'People/search.html')
def dispTable(request) :
table = authTable(Person.objects.filter(MAIN_AUTHOR = 'search_id'))
RequestConfig(request).configure(table)
#return render(request, 'People/tableTemp.html', {'table':table})
return render(request, 'People/tableTemp.html', {"table" : Person.objects.filter(MAIN_AUTHOR = search_id)})
I also tried using a form, but I still did not know how to access the input variable in additional views, like dispTable
from django import forms
class SearchForm(forms.Form) :
search_id = forms.CharField(max_length=100)
def process(self) :
search_id = self.cleaned_data['search_id']
def search(request) :
if request.method == 'POST' :
form = SearchForm(request.POST)
if form.is_valid() :
form.process()
return dispTable(request)
else :
form = SearchForm()
return render (request, 'People/search.html')
And here is my html file:
<form method="POST" action="send/">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>

Categories