I am using django here is my model:
class Location(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50)
altitude = models.IntegerField(max_length=10000)
area = models.ForeignKey('Area')
def __str__(self):
return str(self.area) + ':' + str(self.name)
#measurement.id value date location
class Measurement(models.Model):
id = models.IntegerField(primary_key=True)
value = models.FloatField(max_length=50)
data = models.DateTimeField()
location = models.ForeignKey('Location')
def __str__(self):
return "measurement#"+str(Location.objects.filter(id=self.id))
My HTML page is showing {'value__avg': 46.26524716693248} when it should just show 46.265.
Heres my function:
#property
def average_measurement(self):
locations = Location.objects.filter(area__name=self.name)
return Measurement.objects.filter(location__in=locations).aggregate(Avg('value'))
so how do I get the ugly part out?
aggregate() returns a dictionary where the key is combined from the grouping keys and grouping function name, you can just get the value by key:
return Measurement.objects.filter(location__in=locations).aggregate(Avg('value'))["value__avg"]
Or, if needed, you can also do that in the template using the dot-notation:
{{ obj.average_measurement.value__avg }}
You can also preset the key name with your own value:
return Measurement.objects.filter(location__in=locations).aggregate(my_average=Avg('value'))
Then, you would access it as:
{{ obj.average_measurement.my_average }}
That's not the ugly part, it's expected output and you need to understand what does the output mean. When you do django Aggregation, it returns a dictionary-like object with your aggregation criteria as keys and results as values.
What you need to do is to access it like a dictionary in template to extract the values:
{% for item in items %}
{{ item.value__avg|floatformat:3 }}
{% endfor %}
Check django doc about what is the lookup sequence for dot in template.
Also checkout django doc about aggreate function call.
Also checkout django doc about floatformat template filter.
I'm working on something like an online store. I'm making a form in which the customer buys an item, and she can choose how many of these item she would like to buy. But, on every item that she buys she needs to choose what its color would be. So there's a non-constant number of fields: If the customer buys 3 items, she should get 3 <select> boxes for choosing a color, if she buys 7 items, she should get 7 such <select> boxes.
I'll make the HTML form fields appear and disappear using JavaScript. But how do I deal with this on my Django form class? I see that form fields are class attributes, so I don't know how to deal with the fact that some form instance should have 3 color fields and some 7.
Any clue?
Jacob Kaplan-Moss has an extensive writeup on dynamic form fields:
http://jacobian.org/writing/dynamic-form-generation/
Essentially, you add more items to the form's self.fields dictionary during instantiation.
Here's another option: how about a formset?
Since your fields are all the same, that's precisely what formsets are used for.
The django admin uses FormSets + a bit of javascript to add arbitrary length inlines.
class ColorForm(forms.Form):
color = forms.ChoiceField(choices=(('blue', 'Blue'), ('red', 'Red')))
ColorFormSet = formset_factory(ColorForm, extra=0)
# we'll dynamically create the elements, no need for any forms
def myview(request):
if request.method == "POST":
formset = ColorFormSet(request.POST)
for form in formset.forms:
print "You've picked {0}".format(form.cleaned_data['color'])
else:
formset = ColorFormSet()
return render(request, 'template', {'formset': formset}))
JavaScript
<script>
$(function() {
// this is on click event just to demo.
// You would probably run this at page load or quantity change.
$("#generate_forms").click(function() {
// update total form count
quantity = $("[name=quantity]").val();
$("[name=form-TOTAL_FORMS]").val(quantity);
// copy the template and replace prefixes with the correct index
for (i=0;i<quantity;i++) {
// Note: Must use global replace here
html = $("#form_template").clone().html().replace(/__prefix_/g', i);
$("#forms").append(html);
};
})
})
</script>
Template
<form method="post">
{{ formset.management_form }}
<div style="display:none;" id="form_template">
{{ formset.empty_form.as_p }}
</div><!-- stores empty form for javascript -->
<div id="forms"></div><!-- where the generated forms go -->
</form>
<input type="text" name="quantity" value="6" />
<input type="submit" id="generate_forms" value="Generate Forms" />
you can do it like
def __init__(self, n, *args, **kwargs):
super(your_form, self).__init__(*args, **kwargs)
for i in range(0, n):
self.fields["field_name %d" % i] = forms.CharField()
and when you create form instance, you just do
forms = your_form(n)
it's just the basic idea, you can change the code to whatever your want. :D
The way I would do it is the following:
Create an "empty" class that inherits from froms.Form, like this:
class ItemsForm(forms.Form):
pass
Construct a dictionary of forms objects being the actual forms, whose composition would be dependent on the context (e.g. you can import them from an external module). For example:
new_fields = {
'milk' : forms.IntegerField(),
'butter': forms.IntegerField(),
'honey' : forms.IntegerField(),
'eggs' : forms.IntegerField()}
In views, you can use python native "type" function to dynamically generate a Form class with variable number of fields.
DynamicItemsForm = type('DynamicItemsForm', (ItemsForm,), new_fields)
Pass the content to the form and render it in the template:
Form = DynamicItemsForm(content)
context['my_form'] = Form
return render(request, "demo/dynamic.html", context)
The "content" is a dictionary of field values (e.g. even request.POST would do).
You can see my whole example explained here.
Another approach: Rather than breaking the normal field initialization flow, we can override fields with a mixin, return an OrderedDict of dynamic fields in generate_dynamic_fields which will be added whenever its set.
from collections import OrderedDict
class DynamicFormMixin:
_fields: OrderedDict = None
#property
def fields(self):
return self._fields
#fields.setter
def fields(self, value):
self._fields = value
self._fields.update(self.generate_dynamic_fields())
def generate_dynamic_fields(self):
return OrderedDict()
A simple example:
class ExampleForm(DynamicFormMixin, forms.Form):
instance = None
def __init__(self, instance = None, data=None, files=None, auto_id='id_%s', prefix=None, initial=None,
error_class=ErrorList, label_suffix=None, empty_permitted=False, field_order=None,
use_required_attribute=None, renderer=None):
self.instance = instance
super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, field_order,
use_required_attribute, renderer)
def generate_dynamic_fields(self):
dynamic_fields = OrderedDict()
instance = self.instance
dynamic_fields["dynamic_choices"] = forms.ChoiceField(label=_("Number of choices"),
choices=[(str(x), str(x)) for x in range(1, instance.number_of_choices + 1)],
initial=instance.initial_choice)
return dynamic_fields
I'am trying to display data from the database file which has the value Age : 50 but
i alway get "Age object" displayed in the html. I'm very new too Django.
Here is the code
//base.HTML displays :
Age object
//base.html code :
<body>
{{ obj }}
</body>
//views.py :
def home(request):
obj = Age.objects.all()
return render_to_response("base.html",{'obj': obj})
//models.py
class Age(models.Model):
age = models.CharField(max_length=100)
simply obj is an array of objects, you have to print the attribute of the object.
If you want to show only one age(the first) you have to do:
//views.py :
def home(request):
obj = Age.objects.all()[0]
return render_to_response("base.html",{'obj': obj})
//base.html code :
<body>
{{ obj.age }}
</body>
You need to specify what field to show.
{{ obj.age }}
You need to either do obj.age in the template, or implement str or unicode method on your object that returns the age.
I have a content that I'd like to rate on multiple criteria.
Imagine this kind of model:
class Content(models.Model):
name = models.CharField(max_length=50)
class Criterion(models.Model):
name = models.CharField(max_length=50)
content = models.ForeignKey(Content)
class ContRate(models.Model):
user = models.ForeignKey(User, help_text="Who rated ?")
crit = models.ForeignKey(Criterion)
rate = models.DecimalField()
The user has a page displaying the content.
From this page, he can also rate the content on the criteria set
The rating will be done with Ajax.
Now I'm trying to implement the view & the template
view.py
#...
def viewcont(request, content_id):
"""The user can view a content & rate it"""
content = get_object_or_404(Content, pk=content_id)
RateFormSet = modelformset_factory(ContRate)
formset = RateFormSet(queryset=ContRate.objects.filter(content=content, user=request.user))
objs = {
'content': content,
'forms': formset,
}
return render_to_response('content/content_detail.html', objs
, context_instance=RequestContext(request)
)
#...
content_detail.html
<!-- ... -->
<div id="rating">
<ul>
{% for crit in content.crit_set.all %}
<li>
{{ crit }}
<div class="rateit"
data-rateit-value="the_actual_rating_if_already_there"
data-rateit-ispreset="true"
crit-id="{{ crit.id }}"></div>
</li>
{% endfor %}
</ul>
</div>
<!-- ... -->
Now how can I use the forms formset to display the actual rates ?
And how can I draw an empty form to be posted by Ajax from any clicked star ?
(I know the javascript/jQuery part)
Not sure what the point of the formset is here. The rates are all available via the criteria object, using the reverse foreign key to ContRate in exactly the same way as you've done from Criteria to Content.
To make this as efficient as possible, you probably want to get the relevant ratings in the view and bring them together into a single datastructure:
content = get_object_or_404(Content, pk=content_id)
criteria = content.criteria_set.all()
user_ratings = ContRate.objects.filter(content=content, user=request.user)
ratings_dict = dict((c.crit_id, c.rate) for c in user_ratings)
for crit in criteria:
crit.user_rating = ratings_dict.get(crit.id)
Now you can pass criteria directly to your template, and there you can iterate through it to show the user_rating for each one.
(Final point: "criteria" is plural, the singular is "criterion". :-)
The view:
def GRID_ServerDropDownSearch(request):
if 'r' in request.GET and request.GET['r']:
r = request.GET['r']
servers = SERVERS.objects.get(name=r)
drives = servers.drives_set.all()[0:]
memory = servers.memory_set.all()[0:]
return render_to_response('GRID_ServerDropDownSearchResults.html',
{'servers':servers, 'query':r, 'drives':drives, 'memory':memory})
else:
return render_to_response('GRID_search_form.html', {'error': True})
The form:
class ServerDropDownForm(forms.Form):
r = forms.ModelChoiceField(queryset = SERVERS.objects.all(), required=False)
The template:
<div>
<form action="/ServerDropDownSearch/" method="GET">
{{ form.as_table }}
<input type = "Submit" value = "Submit">
</form>
</div>
The resulting drop-down form works flawlessly. However, immediately to the left of the drop-down list is an "R" (capital r). I know it has to do with the "r" specified in the above code. (If I replace each incidence of r with, say, z then a "Z" appears). However:
WHY does it get capitalized ? Is this just the default case specified in the engine ?
How can I hide that "R" so that, instead, it can indicate "Select A Server", or something more descriptive.
Thanks in advance.
Django derives the label for a form field from the corresponding variable name, but "humanizes" it. For example, a field called my_variable would translate to "My variable".
The simplest way to fix this would be to give a more human-readable name to the field:
server = forms.ModelChoiceField(queryset = SERVERS.objects.all(), required=False)
However, you can also pass a string to use as the label via the form field's label parameter:
r = forms.ModelChoiceField(queryset = SERVERS.objects.all(), required=False, label='Select a server')