Hello i am doing a very small application in google appengine and i use python.
My problem is that i have two tables using de db.model ("clients" and "requests"). The table "client" has got the email and name fields and the table "requests" has got the email and issue fields. I want to do a query that returns for each request the email, issue and client name, if the email is the same in the two tables. Can anyone help, please?
The app engine datastore does not support joins, so you will not be able to solve this problem with GQL. You can use two gets, one for client and one for request, or you can use a ReferenceProperty to establish a relationship between the two entities.
If you need to model a one-to-many relationship, you can do it with a reference property. For your case, it would look something like this:
class Client(db.Model):
email = db.UserProperty()
name = db.StringProperty()
class Request(db.Model):
client = db.ReferencePrpoerty(Client, collection_name='requests')
issue = db.StringProperty()
Any Client entity that has a Request associated with it will automatically get a property called requests which is a Query object that will return all Request entities that have a client field set to the particular Client entity you are dealing with.
You might also want to make sure that the code that creates Request entities set each new entity to have the Client entity for the particular user as its ancestor. Keeping these associated items in the same entity group could be helpful for performance reasons and transactions.
using this models:
class Client(db.Model):
email = db.StringProperty()
name = db.StringProperty()
class Request(db.Model):
client = db.ReferenceProperty(Client, collection_name='requests')
issue = db.StringProperty()
With this code can query the data
from modelos import Client,Request
ctes=Client.all().filter("email =","somemail#mailbox.com.mx")
for ct in ctes:
allRequest4ThisUser=Request.all().filter("client =",ct)
for req in allRequest4ThisUser:
print req.issue
Related
i have two models
class Client(models.Model) :
Code_Client=models.CharField(max_length=200)
......
and
class Adr(models.Model) :
client = models.OneToOneField(Client,on_delete=models.CASCADE)
I created two forms: one for Client and another for Adr in order to use it in one template I could do that with no problem but when I try to save the data from both form it gives me an error
if form.is_valid() and form_Adr.is_valid():
#pdb.set_trace()
new_client=form.save()
Adr0 = form_Adr.save(commit=False)
Adr0.client= new_client
Adr0.save()
the error is
Client: this field is mandatory.
You have relation between Client and Adr.
Is similar to Foreign key.
client = models.OneToOneField(Client,on_delete=models.CASCADE)
This statement require that for every instance of Adr exists
only one Client. That's reason of Client field is mandatory.
Use something like
Adr0.client_set.all()
[<Adr0: client>]
Working with Google App Engine for Python, I am trying to create and then update an ndb entity. To update a single property, you can just access the property using a dot, e.g.
post.body = body
But I would like to know if there is a simple way to update multiple fields within an ndb entity. The following code:
class Create(Handler):
def post(self):
## code to get params
post = Post(author = author,
title = title,
body = body)
post.put()
class Update(Handler):
def post(self, post_id):
post = post.get_by_id(int(post_id))
fields = ['author', 'title', 'body']
data = get_params(self.request, fields)
for field in fields:
post[field] = data[field]
post.put()
The "Create" handler works fine, but the "Update" handler results in:
TypeError: 'Post' object does not support item assignment
So it seems I would need to access the properties using a dot, but that is not going to work when I have a list of properties I want to access.
Can someone provide an alternative way to update multiple properties of an NDB entity after it has been created?
You should use setattr.
for field in fields:
setattr(post, field, data[field])
(Note that GAE objects do actually provide a hidden way of updating them via a dict, but you should use the public interface.)
You can use the populate method:
post.populate(**data)
Let come to the point directly,
Consider here my Clients App name - ABC & XYZ with same application code.
Now let consider a db kind,
class user_details(db.Model):
user_id = db.IntegerProperty()
username = db.StringProperty()
emailid = db.StringProperty()
usertype = db.StringProperty() #Require/used only in **ABC** app
accesslevel = db.StringProperty() #Require/used only in **XYZ** app
.
.
then i realise while app serving same model structure for both ABC and XYZ few properties are meaning less or like usertype for XYZ and accesslevel for ABC
So is that way to or trick so that i can serve only these properties which are actually require for an app. like ignoring usertype for XYZ or like ignoring accesslevel for ABC. so that i could save my db space.
NOTE: i go thru db.Expando method in gae doc. but i don't wanna use that db type in existing app. i would prefer db.Model only. because these app are already running over here. & it has around 2 billion records each client db.
Please suggest me suitable solution, if any one would have implemented these scenario.
I would appreciate your response on this.
Sincerely.
Niks
I would create a base class for the common subset, and then subclass with the additions for each client. You should also consider namespaces to separate data for each client. You have to know which client you are working with (hence namespace) and then load the appropriate model.
The other possibility would be to use a PolyModel but all subclasses are a aggregate of all properties.
from google.appengine.ext import db
class UserBase(db.Model):
user_id = db.IntegerProperty()
username = db.StringProperty()
emailid = db.StringProperty()
class UserABCDetails(UserBase):
usertype = db.StringProperty()
class UserXYZDetails(UserBase):
accesslevel = db.StringProperty()
If you wanted to use a PolyModel you would just replace db.Model with db.PolyModel, but you should read up on the ramifications of that.
Basically what Im trying to make is a data structure where it has the users name, id, and datejoined. Then i want a "sub-structure" where it has the users "text" and the date it was modified. and the user will have multiple instances of this text.
class User(db.Model):
ID = db.IntegerProperty()
name = db.StringProperty()
datejoined = db.DateTimeProperty(auto_now_add=True)
class Content(db.Model):
text = db.StringProperty()
datemod= db.DateTimeProperty(auto_now_add = True)
Is the code set up correctly?
One problem you will have is that making User.ID unique will be non-trivial. The problem is that two writes to the database could occur on different shards, both check at about the same time for existing entries that match the uniqueness constraint and find none, then both create identical entries (with regard to the unique property) and then you have an invalid database state. To solve this, appengine provides a means of ensuring that certain datastore entities are always placed on the same physical machine.
To do this, you make use of the entity keys to tell google how to organize the entities. Lets assume you want the username to be unique. Change User to look like this:
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
Yes, that's really it. There's no username since that's going to be used in the key, so it doesn't need to appear separately. If you like, you can do this...
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
#property
def name(self):
return self.key().name()
To create an instance of a User, you now need to do something a little different, you need to specify a key_name in the init method.
someuser = User(key_name='john_doe')
...
someuser.save()
Well, really you want to make sure that users don't overwrite each other, so you need to wrap the user creation in a transaction. First define a function that does the neccesary check:
def create_user(username):
checkeduser = User.get_by_key_name(username)
if checkeduser is not None:
raise db.Rollback, 'User already exists!'
newuser = User(key_name=username)
# more code
newuser.put()
Then, invoke it in this way
db.run_in_transaction(create_user, 'john_doe')
To find a user, you just do this:
someuser = User.get_by_key_name('john_doe')
Next, you need some way to associate the content to its user, and visa versa. One solution is to put the content into the same entity group as the user by declaring the user as a parent of the content. To do this, you don't need to change the content at all, but you create it a little differently (much like you did with User):
somecontent = Content(parent=User.get_by_key_name('john_doe'))
So, given a content item, you can look up the user by examining its key:
someuser = User.get(somecontent.key().parent())
Going in reverse, looking up all of the content for a particular user is only a little trickier.
allcontent = Content.gql('where ancestor is :user', user=someuser).fetch(10)
Yes, and if you need more documentation, you can check here for database types and here for more info about your model classes.
An alternative solution you may see is using referenceproperty.
class User(db.Model):
name = db.StringProperty()
datejoined = db.DateTimeProperty(auto_now_add=True)
class Content(db.Model):
user = db.ReferenceProperty(User,collection_name='matched_content')
text = db.StringProperty()
datemod= db.DateTimeProperty(auto_now_add = True)
content = db.get(content_key)
user_name = content.user.name
#looking up all of the content for a particular user
user_content = content.user.matched_content
#create new content for a user
new_content = Content(reference=content.user)
If I have the following models in a Python (+ Django) App Engine app:
class Album(db.Model):
private = db.BooleanProperty()
...
class Photo(db.Model):
album = db.ReferenceProperty(Album)
title = db.StringProperty()
...how can I retrieve all Photos that belong to a public Album (that is, an Album with private == False)?
To further explain my intention, I thought it would be:
public_photos = Photos.all().filter('album.private = ', False)
and then I could do something like:
photos_for_homepage = public_photos.fetch(30)
but the query does not match anything, which tells me I'm going down the wrong path.
You can't. App engine doesn't support joins.
One approach is to implement the join manually. For example you could fetch all photos, then filter out the private ones in code. Or fetch all public albums, and then fetch each of their photos. It depends on your data as to whether this will perform okay or not.
The alternative approach is to denormalize your data. Put another field in the Photo model, eg:
class Photo(db.Model):
album = db.ReferenceProperty(Album)
album_private = db.BooleanProperty()
title = db.StringProperty()
Then you can filter for public photos with:
public_photos = Photos.all().filter('album_private = ', False)
This improves query performance, but at the expense of write performance. You will need to keep the album_private field of the photos updated whenever you change the private flag of the album. It depends on your data and read/write patterns as to whether this will be better or worse.