I'd like to know whether default values are applied at the time of instance creation, instance update, or only when attempting to read the value. I'd like to understand how this applies to queries.
For example, suppose I initially create a model w/o default values
class Foo (db.Model):
bar = db.BooleanProperty()
Then I create and put a few instances of Foo.
Then later I update the model
class Foo (db.Model):
bar = db.BooleanProperty(default=False)
And then I have a query
foos = Foo.all().filter('bar =', False)
Will the result include the instances of Foo that were created prior to adding the default value to the model definition?
And if I instead query as
foos = Foo.all().filter('bar !=', True)
Does this include the instances of Foo that were created prior to adding the default value to the model definition? Is it (in the case of a Boolean Property) and wrt default values any different to the previous query?
I looked for docs on this, but found none, sorry. Hopefully I'm just missing them. If possible, please provide links to GAE docs.
Update:
I found this in the docs
Entities lacking a property named in the query are ignored
Entities of the same kind need not have the same properties. To be eligible as a query result, an entity must possess a value (possibly null) for every property named in the query's filters and sort orders. If not, the entity is omitted from the indexes used to execute the query and consequently will not be included in the query's results.
Note: It is not possible to query for entities that are specifically lacking a given property. One alternative is to define a fixed (modeled) property with a default value of None, then filter for entities with None as the value of that property.
https://cloud.google.com/appengine/docs/python/datastore/queries
Assuming that default values are applied at time of entity creation or update, I believe that means that neither of the above queries would return entities that were last put prior to the default value being added to the model. Is that right?
thanks
It really depends. If you actually put a "bar" in your foo prior to having the default value or not.
1- In the case you never set bar and just "put" foos, then yes, anything you put prior to adding the default value will have nothing as their "bar".
2- In the case you actually programaticaly setup bars for your foos as you create them, then your query will return everything.
The way you phrased your question makes me believe you had it setup with # 1, so no, anything you put in your datastore before the default value wouldn't be returned. You will need to go through your whole datastore and update your foos.
While not in the official documentation, this has been validated in comments by Alex Martelli (a Googler)
The default values are assigned only on when left untouched on entity creation. Updates will keep the original value.
This default value doesn't affect queries in any way, indexes are written when you save the entity, so you would need to write the entity again with the proper value.
Related
I'm trying to do the same as this example does under title "Attribute-On-Relationship to Query other Fields".
I'm editing Blog application visual query.
So I have RelationshipFilter, which takes entities of type Category via Default in point. And I want to filter them by field Name. Here I can get list of names either from params or from list of posts and their categories. That's not a problem as far as I understand.
So looks like Name has to be of entity type. I'm struggling right now with this filter, since I want to filter Category by field Name of simple text type. Which means that I have nothing to specify in Relationship Attribute. EntityTitle or just empty Relationship Attribute field don't work and cause Bad Request error. So is there a way to make it work?
P.S. ValueFilter is not an option, since it doesn't support returning nothing if there are no items, that satisfy condition and also it supports only filter by item's Attribute, that contains Value and no option that Value can contain any in Attribute with separator.
The RelationshipFilter is only meant for relationships (item with item) - and you seem to want to do a string-compare.
I'm not really sure what you should do because I don't have context, but if things get really special, best use LINQ instead. Check out the tutorials for LINQ here: https://2sxc.org/dnn-tutorials/en/razor/linq/home
I'm just starting to learn about NoSQL/Document storage this morning. I am used to EntityFramework/SQLServer.
My questions is the following: If I have a bunch of "documents" stored and somewhere down the line I add a property to my class that is needed by my app, how do I back-populate the already existing records?
If you change the model after the fact then you have a few options.
If you have a default value for the additional field and can wait until the next time that entity is saved for the database then you can simply add the new property and set the value to the defaultv value in the constructor.
You can use a IDocumentConversionListener (http://ayende.com/blog/66563/ravendb-migrations-rolling-updates)
You can also use https://github.com/khalidabuhakmeh/RavenMigrations which I have never used but it seems like it would do what you want.
I'm trying to create a custom rule (using the Rules module) so that every time the cron runs, this rule checks a date field in a custom content type I created. If that date has passed then I want to set a list widget from active to ended.
This is how far I get when trying to create this rule:
Set React on event to Cron maintenance tasks are performed
Add Condition > Set Select the condition to add to Data comparison > Continue
Here is the issue: Data selectors only has site and no access to field data.
Any ideas where I'm going wrong here?
The problem with Rules condition "Cron maintenance tasks are performed" is that at that point, there is no access to the node object so any checks/manipulations on the node are not possible. As a solution, instead of Event = Cron maintenance tasks are performed, use Event = Node: Content is viewed. You can leave it open for any content type so that when someone visits the website and opens at least one page, some action will be triggered.
You need to create a rules component first:
Go to Rules > Components (admin/config/workflow/rules/components)
Then create a new component and select 'Rule' from select list
Set a name for this component and in the table below select:
Data type: Text Token
Label: A name that you want
Machine name: Use the same name of the label but set here only lower case and underscore
Usage: Parameter
In the component add the condition 'Data comparison' and select node:type
Add other conditions that you want
Set the actions that you want and save
Now go to Rules (admin/config/workflow/rules) and create the rule with action on cron maintenance (as you have already done)
Jump the conditions section and in the actions:
New action: Add a variable
Value: Text
Then write the value of this variable just like the machine name of content type that you want to cycle on (if you want you can change the name and machine name of this variable in the section below)
Now add another action 'Fetch entity by property'
Entity type value: Node
Property value: Type
Data selector: the variable created at the point 8
Now add a loop in parameter list use the variable provided by 'Fetch entity by property'
Add an action in the loop (click on the link to the right of loop row) and select the component created in the point 2 and pass the variable provided by loop
I state: I do not know if it works but at least it should direct you towards the right path
Sorry for my english, I hope you understand everything :)
Yes you should be able to get this to work using the Rules module to implement what you're looking for, but I recommend you to also combine that with the Views Rules module. Some details about this module (from its project page):
Provides Views directly as Rules actions and loops to seamlessly use view result data.
The previous quote may seem a bit cryptic (it may make you think like "so what, how can this help me?"). Therefor some more details about how to move forward using these modules:
Create a view (using Views) so that you have 1 Views result (row) with all the nodes you want to be processed (related to your custom content type and if possible filter somehow using your date field). Whereas that view has fields (columns) for whatever is needed in subsequent steps, e.g the node ID, the date field, and possibly other fields as well. You'll need these View fields later on as values to be processed by your rule, "to set a list widget from active to ended*" (as in your question). Important: use a Views display type of "Rules".
Remove that "add condition" (in the custom rule you started) and, instead, use the Views Rules module to iterate over each of these Views results in a Rules action, using the Rules technique known as a "Rules Loop".
For each iteration step in your Rules loop, perform a Rules Action to "do your thing" (= to set a list widget from active to ended). At that point you'll have all data from each column of your Views results available as so called Rules Parameters. So at that point it's a piece of cake to adapt the value of that list widget for the node you're processing in that loop.
Optionally, you may also want to add whatever extra Rules Condition(s), also up to your own imagination. Typically the things you cannot, or have not yet, expressed as a Views filter. However, if you have a choice between using a Views filter and an extra Rules Condition, I recommend to go for the Views filter, because that will reduce the number of your iterations in your Rules loop (performance!).
Easy, no?
I have a persistent class stored in a GAE datastore. I have removed one of the attributes from the class. The new records in this table show a value <none> for the removed attribute. But is there a way I can completely drop this column off the table?
Thanks.
Added the following 'migration' code according to moraes' suggestion, but it isn't achieving the desired result:
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query q = pm.newQuery(UserLogin.class);
Collection<UserLogin> list = (Collection<UserLogin>) q.execute();
Iterator<UserLogin> iter = list.iterator();
while (iter.hasNext()) {
UserLogin obj = (UserLogin) iter.next();
obj.setLoginDate(obj.getLoginDate());
}
pm.makePersistentAll(list);
} finally {
pm.close();
}
I found the answer to this problem in this Article:
http://code.google.com/appengine/articles/update_schema.html
"Removing Deleted Properties from the Datastore
If you remove a property from your model, you will find that existing entities still have the property. It will still be shown in the admin console and will still be present in the datastore. To really clean out the old data, you need to cycle through your entities and remove the data from each one.
Make sure you have removed the properties from the model definition.
If your model class inherits from db.Model, temporarily switch it to inherit from db.Expando. (db.Model instances can't be modified dynamically, which is what we need to do in the next step.)
Cycle through existing entities (like described above). For each entity, use delattr to delete the obsolete property and then save the entity.
If your model originally inherited from db.Model, don't forget to change it back after updating all the data."
And here is an example with code:
http://sandrylogan.wordpress.com/2010/12/08/delattr/
If you are using ndb (and you probably should), you can easily delete properties by deleting them from entity._properties:
for entity in MyModel.query():
if 'old_property' in entity._values:
del entity._properties['old_property']
del entity._values['old_property']
entity.put()
Or you could make it faster by using an asynchronous query map:
#ndb.tasklet
def cleanup(entity):
if 'old_property' in entity._values:
del entity._properties['old_property']
del entity._values['old_property']
yield entity.put_async()
MyModel.query().map(cleanup)
There is no concept of "table" in datastore. Each entity can have arbitrary properties that don't follow a common schema. The only "schema" is in your model code, and existing records don't change automatically when you change your models.
So, to delete the property from existing records, you need to iterate over all records and re-save them without the property.
The datastore viewer gets its list of columns from the datastore stats, which are updated on a regular basis. If you've removed that column from every entity that had it, wait a day or two and the datastore viewer will stop showing it.
I'm having a pretty hard time trying to create a write-once field in a Django model. Ideally I'd want it to work like a final variable, although I can settle for simply preventing it from being edited through the admin.
I know there is a solution for read-only fields, but it also affects the add form, and I don't want the field to be read-only there.
Use get_readonly_fields(), and return a tuple with the write-once field name if obj exists, or an empty tuple if obj is None.
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_readonly_fields