I'm writing a simple web app in web2py that stores and retrieves some data from a database. To keep the entries in chronological order, my table has an attribute which stores a date time. Like so:
db.define_table('tablename',
Field( ....
....
....
Field('created_on','datetime', default=request.now, writable=False),
Field('last_modified','datetime', default=request.now, update=request.now),
)
Then when I request the data, I set the orderby attribute to last_modified:
rows = db().select(db.tablename.ALL, orderby=db.tablename.last_modified)
Then, I pass the results onto a Json dictionary object. Like so:
I'm passing them into a JSON dictionary object.Like so:
d = { r.index_id : {'index_id':r.index_id,
....
....
'comments':r.comments,
'created_on':r.created_on,
'last_modified':r.last_modified}
for r in rows}
return response.json(dict(entry_dict=d))
When I get the response from the server, I return the dict to my ractive object.
MAIN.set('data_entries', data['entry_dict']);
Then, I render the results in ractive:
{% #data_entries:index_id%}
<tr class = "datarow" onclick="window.document.location='{% url+ '/'+ index_id %}';">
<td>{% index_id %}</td>
....
<td>{% last_modified %}</td>
</tr>
{% /data_entries %}
However, when the data is returned to the webapp, I get to following:
Am I doing this right?
In Python, dictionaries do not preserve order, so when you convert the d dictionary to JSON, you will not necessarily get the keys in the order of the original Rows object. You could instead use an OrderedDict, but it doesn't appear you really need a dictionary anyway -- just create a list (using the as_list method):
return response.json(dict(entry_dict=rows.as_list()))
Then in Ractive, change:
{% #data_entries:index_id %}
to:
{% #data_entries %}
It doesn't appear you need the index value within each loop. Instead, you will be able to access the index_id field of each record as part of the data context of the section.
Related
In my django project I have a lot of tables which return models. The last column is mostly an Action-Column where users may edit or delete an instance. How do I proceed if I want to pass additional arguments to TemplateColumn if in some tables I want an edit and delete button and in other tables I only need an edit and info button? I want to use the same template.html but with conditions in it. Here what I have in Table:
import django_tables2 as tables
from select_tool.models import DefactoCapability
class DefactoCapabilityTable(tables.Table):
my_column = tables.TemplateColumn(verbose_name='Actions', template_name='core/actionColumnTable.html')
class Meta:
model = DefactoCapability
template_name = 'django_tables2/bootstrap-responsive.html'
attrs = {'class': 'table table-xss table-hover'}
exclude = ( 'body', )
orderable = False
And how do I check perms on the actions in order to display the button or not?
Quoting the TemplateColumn docs
A Template object is created [...] and rendered with a context containing:
record – data record for the current row
value – value from record that corresponds to the current column
default – appropriate default value to use as fallback
row_counter – The number of the row this cell is being rendered in.
any context variables passed using the extra_context argument to TemplateColumn.
So you could do something like this:
my_column = tables.TemplateColumn(
template_name='core/actionColumnTable.html',
extra_context={
'edit_button': True,
}
)
The context also contains the complete context of the template from where {% render_table %} is called. So if you have 'django.template.context_processors.request' in your context_processors, you can access the current user using {{ request.user }}.
I used vue-resource to fetch data from firebase. basically when I loop through each object under the orders directory, I match the userId of that object, find the object under the users directory, and save it on my local array as a nested object (userData) along with the retrieved orders objects. here's my code:
//retrieve objects from orders
this.$http.get('https://nots-76611.firebaseio.com/Orders.json').then(function(data){
return data.json();
}).then(function(data){
var ordersArray = [];
for (let key in data){
data[key].id = key;
data[key].measurementsArray = Object.entries(data[key].measurements).sort();
//retrieve a specific user based on the userId of each orders object
this.$http.get('https://nots-76611.firebaseio.com/Users/' + data[key].userId + '.json').then(function(userdata){
return userdata.json();
}).then(function(userdata){
data[key].userData = userdata; //store the object
});
ordersArray.push(data[key]); //pass the object along the userData
}
this.orders = ordersArray;
console.log(this.orders);
});
the object structured shown in the console is perfectly fine:
but when I try to, access the nested object in the dom via {{ order.userData.Address }}:
<tr v-for="order in orders"
<dialog class="mdl-dialog" ref="userDialog">
<h4 class="mdl-dialog__title">Customer's Information</h4>
<div class="mdl-dialog__content">
{{ order.userData.Address }}
</div>
<div class="mdl-dialog__actions">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" v-on:click="closeUser(ndx)">
OK
</button>
</div>
</dialog>
</tr>
it says Error in render function: "TypeError: Cannot read property 'Address' of undefined". I don't understand it because I can easily retrieve the properties in the measurements object (which is also a nested object)
did I messed up in the retrieval process? or in the DOM rendering?
EDIT:
I tried using {{ order }} instead of {{ order.userData.Address }} and it seems like the userData object was not stored in each of the orders object
Also, I noticed something strange about how the userData object is shown differently from the measurements object which is originally stored there along with the parent object:
There are two primary issues here.
First, the data is retrieved asynchronously which means, it does not exist when the component is first rendered. In the template you use
order.userData.Address
There is a point in time when there are orders but there is no userData, because the data has not been retrieved yet. That being the case, Vue attempts to render the orders, and tries to render order.userData.Address, but there is no userData. That's why you get the error, "Cannot read property 'Address' of undefined". In order to fix that, you should use a guard to make sure to only try to render Address when it is available.
{{orders.userData && orders.userData.Address}}
That will prevent the error.
There is a secondary error that you probably have not yet noticed. userData is not reactive. The reason for this is because Vue cannot detect when properties are added to an object after that object has been added to data. The code is setting userData like so:
data[key].userData = userdata;
and this occurs after the orders array has been added to the Vue because it is performed in an asynchronous call. Instead, you should use,
this.$set(data[key], 'userData', userdata)
this is a question that continues another topic :
QueryBuilder/Doctrine Select join groupby
Please open it so you can see there the database schema.
My problem is:
I have a goal and a goal has many savings.
That means that if you want to save money for a goal you will add some savings, so the savings are linked to the goal by id.
In that topic someone talked about a unidirectional link between savings and goals, ( I have goal_id in the savings table, but no saving_id in the goal table).
What I want to do is show a table with a Goal information and append to it a collected value(which is not in the database) this value is the sum of all saving values linked to a goal:
ex :
Goals:
id: 1
goal name: Goal1
....
Savings:
id: 1
amount:10
goal_id: 1
id:2
amount:20
goal_id: 1
When I query the database I will get a table with the goal information and a field Amount Collected: 30 in this case.
I initially managed to make the query to get me this:
select
admin_goals.created,
admin_goals.description,
admin_goals.goal_date,
admin_goals.value,
admin_goals.budget_categ,
sum(admin_savings.value)
from admin_goals
inner join admin_savings on admin_savings.goal_id=admin_goals.id
where admin_goals.user_id=1
group by admin_goals.id
But I wanted to do the symfony way so I used query builder, made a repository and didn't have the same result.
The only link between Goals and Savings is the goal_id from the Savings table, that means that using query builder I have to start from the Savings table.. because from the Goals table I have no foreign_key for savings.
But now the problem is that because I start from the Savings table, when displaying the Goals I get a empty result, thats because initially there are no Savings for a Goal.
First you create the Goal and then the Savings. But because there is no record in the Savings table(i start from) I don't get nothing from the Goals table because I have a join on these two tables.
$qb = $this->createQueryBuilder('admin_savings');
$qb->select('SUM(admin_savings.value) AS savingValue')
->addSelect('admin_goals.id AS id')
->addSelect('admin_goals.created')
->addSelect('admin_goals.description')
->addSelect('admin_goals.goal_date')
->addSelect('admin_goals.value')
->addSelect('admin_budget.name') // daca vrei id atunci pune identity(admin_goals.categ_id) admin_budget.name, x.name
->join('admin_savings.goal_id', 'admin_goals', Join::WITH)
->join('admin_goals.budget_categ', 'admin_budget', Join::WITH) //parametru 2 e numele de referinta in selectul mare ex: admin_budget, putea fi x
->where($qb->expr()->eq('admin_goals.user_id', ':user'))
->groupBy('admin_goals.id')
->setParameter('user', $user);
I understand that this is not possible so i tried another approach, why not I query normally the Goals entity because that is what I want to see..
$repository = $this->getDoctrine()->getRepository('AppBundle:Goal');
$goals = $repository->findBy(array('user_id' => $userId));
and I made a function in my SavingsRepository :
public function getSavingSumByGoal($goalId){
$qb = $this->createQueryBuilder('saving');
$qb->select('SUM(saving.value) AS savingValue')
->where($qb->expr()->eq('saving.goal_id', ':goal'))
->setParameter('goal', $goalId);
return $qb->getQuery()->getScalarResult();
}
So now I have the Goals entity with all its information, but not the Amount Sum Collected from the Savings, I need to add that somehow to my $goals object. This is in my controller
foreach($goals as $goal_item){
$savingSum=$SavingRepository->getSavingSumByGoal($goal_item->getId());
if($savingSum){
$goal_item->savingSum=$savingSum;
}else{
$goal_item->savingSum=0.00;
}
}
$goal_item->savingSum is a fictional property, he doesnt exists in the $goal object, I made this as an example that I want to insert that savingSum somehow in the $goal object.
I don't want to create another field in the entity and set that, because then I would have a empty collumn in the database, and I don't want that.. I want to keep the structure of my tables and entities, and only add that sum of all savings amount for a goal in the goals table.
But it doens't work.
I was thinking in the foreach in my twig to execute somehow my function, but I don't think that is a good idea.
{% for goal in goals %}
<tr style="">
<td>{{ goal.created|date('Y/m/d') }}</td>
<td>{{ goal.description|e }}</td>
<td>{{ goal.value|e }}</td>
<td>{{ goal.goal_date|date('Y/m/d') }}</td>
<td>{{ goal.name|e }}</td>
<td>{{ savingRepo->getSavingSumByGoal(goal.id)|e }} </td>
</td>
</tr>
{% endfor %}
This is a bad practice and it doesn`t work in twig, but I know people used approach in Zend and other frameworks (after you made the foreach() you run a function of your on the current objects(from foreach) id and show something based on that)
If you have better ideas on how to do this the symfony way .. I can always run the rawquery and it would work, but that is not that I want to do.. there must be a way to do this in a OOP way..please help.
Thank you!
I don't want to create another field in the entity and set that, because then I would have a empty collumn in the database
You don't have to map a field to database, it can be normal class field
I want to create a “last visited pages” list with Symfony and Twig.
For that purpose I wrote a history service which saves the last visited routes in the session.
But I just have the route name no alias for the user experience.
So the route country_info should hold a string like “Country Information”.
Is it possible to define a alias in the routing.yml?
No, it's not possible to define route aliases in routing.yml. The routing system is not meant to do that.
If you have a fixed number of pages you could just read the session values in your Controller and translate each route name in order to print it with Twig later.
Supposing you are storing last visited pages routes in an array, you can try the following:
In your Controller action:
// Read session
$page_routes = $session->get('last_visited_routes_array');
$output_array=array();
foreach ($page_routes as $route){
// Translate route to name
switch($route){
case "country_info":
$output_array['country_info'] = "Country Information";
break;
// ... Add more Cases here ...
}
}
// Return generated array so it can be used by Twig
return array('output_array' => $output_array);
In your Twig template:
{% for page_route, page_name in output_array %}
{{page_name}}
{% endfor %}
Hope it helps.
Meteor has a Session that provides a global object on the client that you can use to store an arbitrary set of key-value pairs. Use it to store things like the currently selected item in a list.
It supports Session.set, Session.get and Session.equals.
How do I delete a Session name, value pair? I can't find a Session.delete(name) ?
[note: this answer is for Meteor 0.6.6.2 through at least 1.1.0.2]
[edit: updated to also explain how to do this while not breaking reactivity. Thanks to #DeanRadcliffe, #AdnanY, #TomWijsman, and #MikeGraf !]
The data is stored inside Session.keys, which is simply an object, so you can manually delete keys:
Session.set('foo', 'bar')
delete Session.keys['foo']
console.log(Session.get('foo')) // will be `undefined`
To delete all the keys, you can simply assign an empty object to Session.keys:
Session.set('foo', 'bar')
Session.set('baz', 'ooka!')
Session.keys = {}
console.log(Session.get('foo')) // will be `undefined`
console.log(Session.get('baz')) // will be `undefined`
That's the simplest way. If you want to make sure that any reactive dependencies are processed correctly, make sure you also do something like what #dean-radcliffe suggests in the first comment. Use Session.set() to set keys to undefined first, then manually delete them. Like this:
// Reset one value
Session.set('foo', undefined)
delete Session.keys.foo
// Clear all keys
Object.keys(Session.keys).forEach(function(key){ Session.set(key, undefined); })
Session.keys = {}
There will still be some remnants of the thing in Session.keyDeps.foo and Session.keyValueDeps.foo, but that shouldn't get in the way.
Session.set('name', undefined) or Session.set('name', null) should work.
The disadvantage with using delete Session.keys['foo'] is that your template will not hot reload if the session key holds an array. For instance, if you are doing
Template.mytempl.helpers({
categories: function() {
return Session.get('srch-categories')
}
})
and in your template
{{#if categories}}
{{#each categories}}
{{this}}
{{/each}}
{{/if}}
And categories is an array, if you delete the session key, your template will continue to display the last value of categories.