My site will have news with possibility to rate them and leave comments. Each user will be able to rate one news only once and leave only one comment. At the same time, I should know which user rated the news and who left the comment.
How to organize such database?
I think about the following structure:
class News(db.Model):
news = db.TextProperty()
added = db.DateTimeProperty(auto_now_add=True)
rating = db.ReferenceProperty(NewsRatings)
comments = db.ReferenceProperty(NewsComments)
added = db.DateTimeProperty(auto_now_add=True)
class NewsRatings(db.Model):
user = db.ReferenceProperty(Users)
rating = db.IntegerProperty()
added = db.DateTimeProperty(auto_now_add=True)
class NewsComments(db.Model):
user = db.ReferenceProperty(Users)
comment = db.TextProperty()
added = db.DateTimeProperty(auto_now_add=True)
class Users(db.Model):
user = db.IntegerProperty()
Is it correct approach? Will I know who left particular comment for particular news?
Your current model only allows for each news item to have a single rating and a single comment (each of which could belong to an arbitrary number of news items). Instead, put the ReferenceProperty on NewsRatings and NewsComments, referencing the News item to which they belong.
Related
I'm writing an application for a factory where I need to provide a way for the user to retrieve the next (or previous) entity of a kind in NDB and can't figure out how to do this. Any help /tips will be appreciated!
Assume I have the following simplified model:
from google.appengine.ext import ndb
class Product(ndb.Model):
prod_id = ndb.StringProperty(required = True)
prod_desc = ndb.StringProperty(required = True)
prod_units = ndb.StringProperty(required = True)
... other properties
To allow the user to find a particular product I use the query below ('find' comes from a form filled in by the user).
Products_Str = 'Products' # The string ID for the common products ancestor
...
def get_products_key(products_key_str = Products_Str):
return ndb.Key('Products', Products_Str)
class DisplayProduct(BaseHandler): # Displays a product found on exact prod_id property
def post(self):
search_key = self.request.get('find')
find_query = Product.query(Product.prod_id == search_key, ancestor = get_products_key()).get()
... here I display the one result of the query, i.e. the requested product
So far so good: I provide the user with a way to find a specific product based on code (or description).
Now I need to place two buttons on the display page named "previous" and "next" and I can't figure out how to retrieve the next and previous products.
I would welcome any suggestions.
Supposing a large number of users and a large number of videos, what would be a better way to structure the database of the following two options:
Option one --
class UserProfile(models.Model)
user = models.ForeignKey(User, unique=True)
videos = models.ManyToManyField(Video, blank=True)
class Video(models.Model)
title = models.CharField(max_length=256)
file = models.FileField(...)
Option two --
class UserProfile(models.Model)
user = models.ForeignKey(User, unique=True)
class Video(models.Model)
uploaded_by = models.ForeignKey(User)
title = models.CharField(max_length=256)
file = models.FileField(...)
Videos have nothing to do with user profiles, so the first relation is fallacious. It will also require spanning another table in order to find a user's videos. Use the second.
I want to be able to, given the key to a model in the datastore, simply set the referenceproperty without loading the model itself (as I don't need that information).
For example:
class Book(db.Model):
author = db.StringProperty()
title = db.StringProperty()
class Review(db.Model):
book = db.ReferenceProperty(Book)
description = db.StringProperty()
Assuming that I already have the key to a Book (call it bookKey), but I don't have the corresponding Book object itself, is there a way to do the equivalent of
review = Review()
review.description = "It was ok, but I would recommend it for insomniacs."
review.book = bookKey
or do I need to
book = Book.get(bookKey) #I don't want this datastore access
#as I don't need the book object.
review = Review()
review.description = "It was ok, but I would recommend it for insomniacs."
review.book = book
I've found the way to extract the key and ID from the ReferenceProperty using get_value_for_datastore, but I'm after a "set".
review.book = bookKey will work just fine, and set the referenceproperty without fetching the model.
I'm designing a model for a posting system where an entry contains an image with or without a comment. An user can reply to it as either a comment or as an image entry as well.
As there can be more properties for ImageEntry, I came up with this design with Polymodel. Not sure if this is the best way to do this. Storage-wise, is CommentEntry less than ImageEntry?
Any suggestions would be great.
class Entry(polymodel.PolyModel):
comment = db.TextProperty()
reply_to = db.SelfReferenceProperty() # reference to the entry
created_at = properties.DateTimeProperty(auto_now_add=True)
updated_at = properties.DateTimeProperty(auto_now=True)
class CommentEntry(Entry):
created_by = db.ReferenceProperty(User, collection_name='comment_entries')
class ImageEntry(Entry):
created_by = db.ReferenceProperty(User, collection_name='image_entries')
image_url = db.LinkProperty(indexed=False)
slug = db.StringProperty(indexed=False)
this model will work fine, and yes, a CommentEntry will be smaller than an ImageEntry from the same user if the ImageEntry has an image URL and/or slug.
however, i'd make this much simpler by putting
created_by, image_url, and slug into Entry and getting rid
of CommentEntry and ImageEntry altogether. since
the app engine datastore is schemaless,
and properties are optional by default,
you'll only pay the cost of the image_url and slug properties when you fill them
in for image entries.
Here are my models:
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
email = db.StringProperty()
class Page(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
link = db.StringProperty(required=True)
class UserPage(db.Model):
user = db.ReferenceProperty(User, collection_name='pages')
page = db.ReferenceProperty(Page, collection_name='users')
How would I construct a query to find a users pages?
I found an article that describes a method to do it but is this the best way? http://blog.arbingersys.com/2008/04/google-app-engine-better-many-to-many.html
Your answer will work, but it will perform 7 calls to the datastore:
1 for the call to User.get_by_key_name()
1 for the call to UserPage...fetch()
5 for each dereference of x.page.id inside the loop
An alternative approach which only does 3 calls to the datastore would be something like this:
myuser = User.get_by_key_name("1")
up = UserPage.all().filter('user =', myuser).fetch(5)
keys = [UserPage.page.get_value_for_datastore(x) for x in up]
pages = db.get(keys)
for p in pages:
self.response.out.write(p.id)
See http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine for more details.
After some testing, it appears I can use:
myuser = User.get_by_key_name("1")
up = UserPage.all().filter('user =', myuser).fetch(5)
for x in up:
self.response.out.write(x.page.id)
I would recommend a different approach, that is less "relational-oriented" than your UserPage relationship:
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
email = db.StringProperty()
class Page(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
link = db.StringProperty(required=True)
# Users linking to this page
users = db.ListProperty(db.Key)
And then you can get all pages of a specific user with the following query:
Page.gql("WHERE users = :1", user.key())
Please note that you should place the list property of keys on the side where you expect less items. I've assumed you will have less users liked to a page, than pages linked to a user, so I've put it on the Page side, but that will depend on your specific use case.
See here for official recommendations on the many-to-many topic: http://code.google.com/appengine/articles/modeling.html