So I have a python dictionary storing the size and the amount each size has, titled final_list. Then I'm passing that to the template using "sizes": final_list. In the html template, I'm trying to create a drop-down selection with all the sizes, and only display sizes that are available, or have an amount not equal to 0. The problem is, it seems as if it isn't accepting the dict or something, since the dropdown shows up empty. Below is the code I have, any help would be much appreciated.
Views.py
I'm getting the sizing info from a model called 'Size' then checking if there are 0 objects of that size. Then I'm creating the dictionary to only have sizes that are actually available.
from django.template.defaulttags import register
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
def product(request, code):
sizes = Size.objects.get(code=code)
all_size = ['small', 'medium', 'large', 'XL']
final_list = {}
for size in all_size:
if getattr(sizes, size) == 0:
pass
else:
final_list[size] = getattr(sizes, size)
return render(request, "website/listing.html", {
"sizes": final_list
})
HTML (website/listing.html)
<form method="POST">
<select name="sizes" style="width: 90px; height: 20px;">
{% csrf_token %}
{% for size in sizes %}
{% if final_list|get_item:size != 0 %}
<option>{{size}}</option>
{% endif %}
{% endfor %}
</select>
</form>
You don't pass a context variable named final_list to the template. You should use {% if sizes|get_item ... instead.
That being said, this code could be simplified as:
{% for size, value in sizes.items %}
{% if value %}
<option>{{ size }}</option>
{% endif %}
{% endfor %}
This way you don't have to use the custom filter get_item either.
Related
What am I trying to achieve will be easier to explain on lists.
e.g
list_of_blocks=[1,2,3,4,5,6,7,8,9,10,11,12]
block_first_row = list_of_blocks[:3]
block_rest_rows = [list_of_blocks[i:i+4] for i in range(3, len(list_of_blocks), 4)]
block_rows = block_rest_rows.insert(0, list_of_blocks)
I want to group blocks from StreamField and display them in template grouped by those rows.
Is there a way to do it in my model? Or should i do it somehow in template..
I've tried to do:
operate on StreamField as on list
deconstuct StreamField.. then operate as on list
The value of a StreamField is a list-like object of type StreamValue. Since it isn't a real list, it may not support slicing - if not, you can get around that by casting it to a real list with list(self.body) (where body is your StreamField). A good place to do this is the page's get_context method:
def get_context(self, request):
context = super().get_context(request)
list_of_blocks = list(self.body)
block_first_row = list_of_blocks[:3]
block_rest_rows = [list_of_blocks[i:i+4] for i in range(3, len(list_of_blocks), 4)]
block_rows = block_rest_rows.insert(0, block_first_row)
context['block_rows'] = block_rows
return context
You can then access block_rows in your template:
{% for block_row in block_rows %}
<div class="row">
{% for block in block_row %}
render block as normal, with {% include_block block %} or otherwise
{% endfor %}
</div>
{% endfor %}
I have line of code in Django template:
<h4>{{ totals.date.weekday }}</h4>
Totals is the Python list, how do i get item of this list by index stored in date.weekday?
This would look in Python like this:
totals[date.weekday]
Creating another variable, which stores date.weekday doesn't work
UPD:
I found a solution:
Just added element of totals list to template context in render
For example:
# ...
return render(request, 'template.html', context={'date_total'=totals[date.weekday()]})
You can access the array directly using
{{ totals.0.date.weekday}} where the 0 is the position that you want.
Also if you want to print all the elements in total you will need a for loop such as:
{% for d in totals %}
{{ d }}
{% endfor %}
about sorting, you can use the pipe order_by but I recommend you to pass the list already ordered from the views
You have to run the "for loop" for this.
{% with counts = 0 %}
{% while counts < totals.count %}
{% if counts == date.weekday %}
<h4>total.counts</h4>
{% endif %}
{% counts += 1 %}
{% endfor %}
I did not get your question completely but i think it might help.
Is there a way to limit the size (length/width) of a ModelView column? I am using a WYSIWYG editor and this creates really long text, therefor making the column for the ModelView very long.
Here is picture of what it looks like. Look on the right hand side the last column. It is even longer than the screenshot could handle.
Don't show the column (by exclusion):
class MyView(ModelView):
column_exclude_list = ('description')
Don't show the column (by inclusion):
class MyView(ModelView):
column_list = ('rating', 'category_id', 'year', 'stock', 'image')
Reformat the column:
class MyView(ModelView):
def _description_formatter(view, context, model, name):
# Format your string here e.g show first 20 characters
# can return any valid HTML e.g. a link to another view to show the detail or a popup window
return model.description[:20]
column_formatters = {
'description': _description_formatter,
}
A way to do this could be to override the css style of the relevant column. In the Flask-admin list.html template you find the following code for creating the columns:
{% for c, name in list_columns %}
<td class="col-{{c}}">
{% if admin_view.is_editable(c) %}
{% set form = list_forms[get_pk_value(row)] %}
{% if form.csrf_token %}
{{ form[c](pk=get_pk_value(row), display_value=get_value(row, c), csrf=form.csrf_token._value()) }}
{% else %}
{{ form[c](pk=get_pk_value(row), display_value=get_value(row, c)) }}
{% endif %}
{% else %}
{{ get_value(row, c) }}
{% endif %}
</td>
{% endfor %}
So e.g. for column 2 you could add a max-width property to the css class col-2 to limit its width.
I have an InterField, that validates if a number is between the values 0 and 99. For some reason it never validates.
I have a feeling it is related to the FieldList and ther way I iterate over it in the template, but can't seem to get it working.
The form:
class dpiaImpactAnalysisForm(Form):
severity_score = IntegerField("Severity Score"),
validators=[NumberRange(min=0, max=99, message="Please provide a valid number")]))
identifiability_score = IntegerField("Identifiability Score"),
validators=[NumberRange(min=0, max=99, message="Please provide a valid number")]))
class dpiaThreatAnalysisForm(Form):
impact = FieldList(FormField(dpiaImpactAnalysisForm), min_entries=1)
In views I append the entries dynamically as required:
#app.route('/dpia/analysis/<project_id>', methods=["GET", "POST"])
def analysis(project_id):
form = dpiaThreatAnalysisForm()
prim = Assets.query.filter_by(selected=True, primary=True).all()
primary_assets = list(map(vars, prim))
ev = Events.query.all()
events = list(map(vars, ev))
# add fields to the form...
for z in range(len(prim) * len(ev)):
form.impact.append_entry()
supp = Assets.query.filter_by(selected=True, primary=False).all()
supporting_assets = list(map(vars, supp))
ths = Threats.query.all()
threats = list(map(vars, ths))
# add fields to the form
for z in range(len(ths) * len(supp)):
form.likelihood.append_entry()
if form.is_submitted():
print "submitted"
if form.validate():
print "valid"
print form.errors
if form.validate_on_submit():
# This is never printed:
app.logger.info("success!!")
pprint(form.likelihood)
return redirect(url_for(next_step, project_id=project_id))
return render_template('analysis.html', form=form, threats=threats, supporting_assets=supporting_assets, primary_assets=primary_assets, events=events)
In the template I iterate over a list primary_assets in a list events, and add the fields per iteration:
{% for val in events %}
{% if not counter or loop.index0 == 0 %}
{% set counter = [] %} <!-- loop hack !-->
{% endif %}
<strong>Event: {{ val.name }}</strong><br />
Jeopardizes: {{ val.jeopardizes }}<br />
{% for pa in primary_assets %}
<strong>{{ pa['name'] }}</strong><br />
{{ form.impact[counter|length].identifiability_score(placeholder='') }} <br />
{{ form.impact[counter|length].severity_score(placeholder='') }}
{{ form.impact[counter|length].hidden_tag() }}
{% if counter.append('1') %}{% endif %}
{% endfor %}
{% endfor %}
The hidden_tag() doesn't work either. Normally I iterate of the forms with with something like
{% for impact in form.impact %}
{{ impact.form.hidden_tag() }}
# do cbg
{% endfor %}
and that works, that's why I believe it's my manual looping that spoils it...
EDIT 2 march, 17:26
After some testing, I found that using
severity_score = IntegerField("Severity Score", validators=[Optional(), NumberRange(
min=0, max=9999999999, message="Please provide a valid number")])
works (if I set min=50 I get an error when inserting a number below 50), however, the CSRF is still not getting passed.
{{ form.impact[counter|length].hidden_tag() }} or
{{ form.impact[counter|length].form.hidden_tag() }} both don't work :(
I'm getting: {'impact': [{'csrf_token': ['CSRF token missing']}, {'csrf_token': ['CSRF token missing']}]}
EDIT 18:22
It seems that this: Form validation fails due missing CSRF is the solution. Investigating...
This: Form validation fails due missing CSRF is the solution.
In previous versions this wasn't needed, and after an installation of a new extension pip updated flask-wtf as well...
I have a property in my model:
def _get_image(self):
return Media.objects.get_for_object(self)
image = property(_get_image)
It calls the following function on my Media model:
def get_for_object(self, obj):
ctype = ContentType.objects.get_for_model(obj)
return self.filter(items__content_type__pk=ctype.pk, items__object_id=obj.pk)
Then in my template I am iterating through the results like so:
{% if entry.image %}
<h2>Current image:</h2>
{% for m in entry.image %}
{{ m }}
{% endfor %}
{% endif %}
For some reason, my SQL readout shows these two queries, right next to each other:
0.40 SELECT
EXPLAIN
Toggle Stacktrace
SELECT `media_media`.`id`, `media_media`.`file`, `media_media`.`content_type`, `media_media`.`created` FROM `media_media` INNER JOIN `media_mediaattachment` ON (`media_media`.`id` = `media_mediaattachment`.`media_id`) WHERE (`media_mediaattachment`.`content_type_id` = 12 AND `media_mediaattachment`.`object_id` = 20 )
0.38 SELECT
EXPLAIN
Toggle Stacktrace
SELECT `media_media`.`id`, `media_media`.`file`, `media_media`.`content_type`, `media_media`.`created` FROM `media_media` INNER JOIN `media_mediaattachment` ON (`media_media`.`id` = `media_mediaattachment`.`media_id`) WHERE (`media_mediaattachment`.`content_type_id` = 12 AND `media_mediaattachment`.`object_id` = 20 )
So whenever I access entry.image, the database is getting hit. Surely it should store the results or something?
"or something"?
Why should it store the results? You've explicitly written the _get_image function so that it queries the database each time. If you want it to store the results, you need to tell it to do it.
Probably the simplest way would be to just get it once in the template:
{% with entry.image as images %}
{% if images %}
<h2>Current image:</h2>
{% for m in images %}
{{ m }}
{% endfor %}
{% endif %}
{% endwith %}
Here's how you write a caching property without explicitly setting the cache to None in the __init__ method:
def _get_image(self):
if not hasattr(self, '_image'):
self._image = Media.objects.get_for_object(self)
return self._image
image = property(_get_image)
or in more modern syntax
#property
def image(self):
if not hasattr(self, '_image'):
self._image = Media.objects.get_for_object(self)
return self._image