I have a custom macro method that returns a string array of field names whose values I want to output in a Text/XML transformation. The transformation is being used as the Item Template in a Datalist. I cannot figure out though how to dynamically get the value from the current data item. It seems that DataItem does not resolve -- nothing outputs from the GetValue call below. Using CurrentDocument would obviously resolve the page instead of the data item.
<tr>
<td>{% SKUNumber %}</td>
{% foreach (spec in Util.GetSpecFieldsForPageType(CurrentDocument.NodeClass, "RelatedModelsTable")) { %}
<td class="hidden-xs">{% GetValue(DataItem, spec) %} </td>
{% } #%}
</tr>
Is there any way to access the current data item in a Text/XML transformation? Or do I need to switch to an ASCX transform?
Assuming you're using Kentico v10, you're looking for the Object macro.
Using an indexer, you can specify a column to retrieve data from:
{% Object[columnName] %}
In your case, it would be:
<tr>
<td>{% SKUNumber %}</td>
{% foreach (spec in Util.GetSpecFieldsForPageType(CurrentDocument.NodeClass, "RelatedModelsTable")) { %}
<td class="hidden-xs">{% Object[spec] %}</td>
{% } #%}
</tr>
Here's a generic example, for those who need an example without any custom macros. This will dynamically render DocumentID, DocumentName and NodeAliasPath, specifying the columns in an array, as opposed to hardcoding them.
<tr>
{% columns = "DocumentID,DocumentName,NodeAliasPath"; foreach (column in columns.Split(",")) { %}
<td>{% Object[column] %} </td>
{% } #%}
</tr>
EDIT:
As Kentico v9 does not have the Object macro for transformations, one way to dynamically resolve a value of the repeated item is to use Util.ResolveMacroExpession, and supply the column name as the parameter.
The repeated item fields are registered as named sources, so there is no way to access them with an indexer or macro method.
Here's the same example from the question author, modified to work in Kentico v9:
<tr>
<td>{% SKUNumber %}</td>
{% foreach (spec in Util.GetSpecFieldsForPageType(CurrentDocument.NodeClass, "RelatedModelsTable")) { %}
<td class="hidden-xs">{% Util.ResolveMacroExpression(spec) %}</td>
{% } #%}
</tr>
You have to give us the scenario to get the right answer
If your {% Util.GetSpecFieldsForPageType(CurrentDocument.NodeClass, "RelatedModelsTable")%} returns IEnumbrable you can use ApplyTransformation
Related
I am trying to display a portfolio of stocks. The task is to access the database and then to lookup for the current price of the stock, displaying it, the total value of the stocks, the remaining cash from 10000 and the grand total, that should be changing depending on the current stock price.
I have tried various ways to access and display data but I am constantly having errors and I need a help, please. I have also tried to create a for loop and to append data to list but again without success.
The error is:
File "/home/ubuntu/finance/application.py", line 58, in index
current_price=lookup(row["symbol"]["price"])
TypeError: 'NoneType' object is not subscriptable
My code is below:
#app.route("/")
#login_required
def index():
"""Show portfolio of stocks"""
#Access the stocks of the current user from DB
rows=db.execute("SELECT symbol, name, sum(shares) as shares FROM stocks WHERE user_id=:user_id ORDER BY symbol", user_id=session["user_id"])
#Check the current price of each stock using the helper function lookup and calculate the total cost of each stock( * number of shares by price)
#add that info to rows and render it on the index page
sum_total_cost=0
for row in rows:
#symbol=row["symbol"]
#current_price=lookup(symbol["price"])
current_price=lookup(row["symbol"]["price"])
total_cost=current_price*(row["shares"])
row["current_price"]=usd(current_price)
row["total_cost"]=usd(total_cost)
sum_total_cost+=total_cost
#Check the current cash of the user
user_id=session["user_id"]
user = db.execute("SELECT cash FROM users WHERE id=:user_id", user_id=user_id)
cash=user[0]["cash"]
grand_total = cash+sum_total_cost
return render_template("index.html", rows=rows, cash = cash, grand_total=grand_total)
And HTML
{% extends "layout.html" %}
{% block title %}
Index
{% endblock %}
{% block main %}
<h2>Portfolio</h2>
<table class="table table-striped">
<thead>
<tr>
<th>Symbol</th>
<th>Name</th>
<th>Shares</th>
<th>Price</th>
<th>Total Cost</th>
</tr>
</thead>
<tbody>
<!-- TODO: Loop through the database to display all transactions and the balance -->
{% for row in rows %}
<tr>
<td>{{row.symbol}}
<td>{{row.name}}</td>
<td>{{row.shares}}</td>
<td>{{row.current_price}}</td>
<td>{{row.total_cost}}</td>
{% endfor %}
</tr>
<tr>
<th>Cash</th>
<td></td>
<td></td>
<td></td>
<td>{{cash}}</td>
</tr>
<tr>
<th>Grand Total</th>
<td></td>
<td></td>
<td></td>
<td>{{grand_total}}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endblock %}
Lookup function
def lookup(symbol):
"""Look up quote for symbol."""
# Contact API
try:
api_key = os.environ.get("API_KEY")
url = f"https://cloud-sse.iexapis.com/stable/stock/{urllib.parse.quote_plus(symbol)}/quote?token={api_key}"
response = requests.get(url)
response.raise_for_status()
except requests.RequestException:
return None
# Parse response
try:
quote = response.json()
return {
"name": quote["companyName"],
"price": float(quote["latestPrice"]),
"symbol": quote["symbol"]
}
except (KeyError, TypeError, ValueError):
return None
The error message is self-explanatory, it should be that line that is causing the problem:
current_price=lookup(row["symbol"]["price"])
Since you are reading from a table you should very likely be using row["symbol"], possibly transformed by some operation. You are addressing the field as if it were a dict. I don't know what your lookup does though. I would guess it takes just one argument so it could simply be something like that: current_price=lookup(row["symbol"])
Perhaps post the code for the lookup function if you don't manage to fix the issue.
PS: maybe the whole calculation could be done in SQL, probably a matter of JOINing two tables or something.
For the life of me I cannot get my index page to properly display the data from my database. I have tried multiple methods and research on several sites. I'm thinking it is something right in front of my face, but right now I can't see the forest through the trees. I have included my code below.
Application:
#app.route("/")
#login_required
def index():
users = db.execute("SELECT * FROM users WHERE id = :user_id", user_id=session["user_id"])
stocks = db.execute("SELECT * FROM transactions WHERE id = :user_id", user_id=session["user_id"])
quotes = {}
for symbol in stocks:
quotes[symbol["symbol"]] = lookup(symbol["symbol"])
return render_template ("index.html", quotes=quotes,stocks=stocks, symbol=symbol)
index.html:
{% extends "layout.html" %}
{% block title %}
Portfolio
{% endblock %}
{% block main %}
<table class="table table-striped">
<tr>
<th> Symbol</th>
<th> Current Share Price</th>
<th> Shares Owned</th>
<th> Shares Owned Value</th>
</tr>
{% for stock in stocks %}
<tr>
<td>{{symbol.symbol}}</td>
<td>{{quotes[stock.symbol]["price"] | usd }}</td>
<td>{{symbol.shares}}</td>
<td>{{symbol.total_price}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Finally here is a screenshot of my index.html as it generates now:
And the data in my database table:
As you can see, the table displays the symbol, shares and total price from only one of the transactions. It shows the correct updated price for each stock, but I can't get it to pull the correct data from the table. Thank you so much for any help.
symbol has the value of the last iteration of for symbol in stocks:. Looks like the html should be creating the td elements from stock ({% for stock in stocks %}) not from symbol.
Suggestion to simplify:
In the for symbol in stocks: loop in the .py, add a key to the symbol dictionary for price. That would render the quotes object unnecessary and the stocks list would be self contained.
I'm using Jinja2 Template to change dynamically a result table for my Motor Racing webapp. It's not perfect, but I'm making my way with patience.
I have a template that is rendered by the URL 'webapp.com/driver/' that's supposed to show the results of a Race where the driver was present inside a table. To make it clear:
The user selects a Driver and goes to webapp.com/driver/someDriver
The someDriver page has a dropdown list with ALL Races the someDriver has been through
User selects someRace from dropdown list
Table is fed by someRace's results
The python flask route I wrote for it:
#app.route('/driver/<driverid>')
def driver(driverid):
driver = db.Drivers.find_one({'_id': ObjectId(driverid)})
races = db.Races.find({'finalresult.driver':driver['unique_name']}).sort([('timestamp', -1)])
racesList = []
for race in races:
raceItem = {
'filename':race['filename'],
'date':datetime.datetime.fromtimestamp(float(race['timestamp'])).strftime('%d-%m-%Y'),
'finalresult':race['finalresult'],
'id':str(race['_id'])}
racesList.append(raceItem)
return render_template('user.html', driver=driver, racesList=racesList)
Now I'm trying to make a dynamic template that changes the Result table everytime the user change the selection.
<div class="row">
<form name="racesForm">
<label for="selRace">Escolha uma corrida!</label>
<select class="form-control" id="selRace">
{% for race in racesList %}
<option value="{{race.filename}}">
{{race.filename}}
</option>
{% endfor %}
</select>
</form>
<hr>
</div>
<div class="row">
<table>
<thead>
<th>Position</th>
<th>Driver</th>
</thead>
<tbody>
<tr>
{% position, drivername in race.finalresult %}
<th>{{position}}</th>
<td>{{drivername}}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
But now I'm receiving a error:
Encountered unknown tag 'position'.
And that's it..I'm not sure of how to make this dropdown list change the table dynamically. Any insights 'd be aprecciated.
UPDATE//Giving more info:
Driver is a very simples dict/json that has two keys ['name'] and ['_id']
racesList is an array of many "raceItem"s.
Each "raceItem" has a key anmed 'finalresult' that has data of the positions each driver has finished.
this array is filled with many objects it may seem like the example below:
'finalresult': [
{'position': 1,
'drivername': 'John Doe'},
'position': 2,
'drivername': 'Foo Bazz', etc
}]
As I told before, I want this data to be displayed in a table, depending on what RACE has been selected from the "raceList" dropdown list.
As a solution, I'm thinking of creating a new routing...but I wanted this routing to be displayed in the same page. I don't want the user to be directed to a new window.
First of all, you are getting Encountered unknown tag 'position' as you are using a different data structure. As you mentioned finalresult is a list of dicts. So you need to iterate through it when populating your table.
{% for driver_stat in race.finalresult %}
<td>{{driver_stat.position}}</td>
<td>{{driver_stat.drivername}}</td>
{% endfor %}
But with your approach, this table will not be updated dynamically as you select different race from your dropdown. Instead I suggest to use jquery. So you don't have to nevigate to another page to display the driver stats. I found several useful SO question that have been already answered on this. Follow them.
Ref:
Populate table based in select
Populate HTML table based on second dropdown selection
I have a Jinja2 Template I'm working on for a database editing app, and I'm trying to make it 'extendible' - rather than hard-coding the editing page, I'm passing a list of attributes that I want in the table, and using a for loop to iterate over them. It works aside from one thing - in the hardcoded version, I use an attribute of an object that's being passed to see if that value has been set (they are all boolean), but I can't see how to get jinja2 to take the 'capability' and use that as an attribute of the 'pupil' object; i would have used 'eval' in Python, but can't see how to get this to work. Here's an idea of the code:
{% for capability in capability_list %}
<tr>
<td>{{ capability }}</td>
<td>
{% if pupil.capability %}
<img src="{{request.static_url('gdpr_permissions:static/tick.png')}}" width="25">
{% else %}
<img src="{{request.static_url('gdpr_permissions:static/cross.png')}}" width="25">
{% endif %}
</td>
<td>
<div class="onoffswitch">
<input type="checkbox" name="{{ capability }}" class="onoffswitch-checkbox" value ='No' id="{{ capability }}" checked>
<label class="onoffswitch-label" for="{{ capability }}">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
</td>
</tr>
{% endfor %}
It's the {% if pupil.capability %} part that doesn't work - I want this to become (say) pupil.web_access and pupil.database_access etc., following the capability list which is being iterated over.
Any ideas on how to get this working with jinja2, or how else it can be approached? The other idea I had was to iterate over the current settings in the python backend and then pass a list of booleans separately, but this seems to be adding an extra level of complexity.
This is because you are passing in a string instead of an attribute. Use getattr() instead. Do something like getattr(pupil, capability)
{{loop.index}} correctly dereferences the innermost loop. I'm not seeing a way to identify which loop index I'd like, however, if I have more than one loop nested.
http://jinja.pocoo.org/docs/dev/templates/
YES. This part of the documentation exactly answers my question!
The special loop variable always points to the innermost loop. If it’s
desired to have access to an outer loop it’s possible to alias it:
<table>
{% for row in table %}
<tr>
{% set rowloop = loop %}
{% for cell in row %}
<td id="cell-{{ rowloop.index }}-{{ loop.index }}">{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
http://jinja.pocoo.org/docs/dev/tricks/#accessing-the-parent-loop