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.
Related
I am building a blog website and I am using Django rest framework
I want to fetch top 2 comments for a particular post along with their related data such as user details.
Now I have user details in two models
User
People
and the comments model is related to the user model using foreign key relationship
Models ->
Comments
class Comment(models.Model):
comment = models.TextField(null=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments_post')
user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='comments_user')
The People model is also connected to the user model with a foreign key relationship
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,related_name='people')
Name = models.CharField(max_length=255,null=True)
following = models.ManyToManyField(to=User, related_name='following', blank=True)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
for fetching the comments I am using rest-framework and the serializers look like this
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=255)
class peopleSerializer(serializers.Serializer):
Name = serializers.CharField(max_length=255)
class commentsSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
comment = serializers.CharField(max_length=255)
Created_date = serializers.DateTimeField()
user = UserSerializer()
people = peopleSerializer()
The query to fetch the comments look like this ->
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(post_id=post_id).select_related('user').prefetch_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
I am getting this error ->
Got AttributeError when attempting to get a value for field `people` on serializer `commentsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Comment` instance. Original exception text was: 'Comment' object has no attribute 'people'.
Unable to find a way out.
The source is user.people, not people, so:
class commentsSerializer(serializers.Serializer):
# …
people = peopleSerializer(source='user.people')
In the .select_related(…) [Django-doc] to can specify user__people: this will imply selecting user and will fetch the data in the same query, not in an extra query as is the case for .prefetch_related(…) [Django-doc]:
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(
post_id=post_id
).select_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
Note: normally a Django model is given a singular name, so Person instead of People.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: created_date instead of Created_date.
On the Google App Engine, I have a webapp2 model like this:
def Person(db.model):
first_name = db.StringProperty()
surname = db.StringProperty()
languages_spoken = db. ListProperty()
However, I'd like to have the languages_spoken list constrained to a list of options, say English, French, and Spanish, that can change as time goes on. With SQL this would be easy with person, language, and person_language tables (or similar) but I can't get my head round how to do it in this case, or even if it's possible. Any suggestions anyone?
I you are starting an appengine project, use the new NDB instead of the datastore. You can use properties with arguments like: choices and validator: https://developers.google.com/appengine/docs/python/ndb/properties
By using the NDB, you can have the following:
def Person(ndb.model):
first_name = db.StringProperty()
surname = db.StringProperty()
languages_spoken = db. ListProperty(choices=['English', 'French', 'Spanish'])
For more information about it, take a look at NDB Property Options.
However, notice that these options cannot change "on-the-fly". When a new option is supported by your application, you will need to add it in your model manually.
In the end I went with this, thanks to the pointers from the two other answers:
from google.appengine.ext import ndb
languages = ['English', 'French', 'Spanish']
def Person(ndb.model):
first_name = ndb.StringProperty()
surname = ndb.StringProperty()
languages_spoken = ndb.StringProperty(repeated=True, choices=languages)
I have a main table
Slideshow
then a site specific table that captures a few extra details for that site.
Site1_Slideshow
In a web app (specific to a site) i want a single model i.e. Slideshow that combines the 2 tables above.
Currently i have the code below, but i dont think this is correct. I cant do things like
s = Slideshow.objects.get(slideshowId=1) as Slideshows only has the properties featurecategory and slideshow. So how can i have an model called Slideshow that is composed of these 2 tables but looks like it was a single db table.
class SlideshowAbstract(models.Model):
slideshowid = models.IntegerField(primary_key=True, db_column=u'SlideshowId') # Field name made lowercase.
headline = models.TextField(db_column=u'Headline') # Field name made lowercase.
class Meta:
db_table = u'Slideshow'
class Slideshow(models.Model):
slideshow = models.OneToOneField(SlideshowAbstract, primary_key=True,db_column=u'SlideshowId')
def __unicode__(self):
return self.slideshow.headline
class Meta:
db_table = u'Site1_Slideshow'
Think i found the solution.
On the Site1_Slideshow you need to add a column for django to use, that i presume is always the same as primary key value.
Its name is SlideshowAbstract_ptr_id
Once that is added you can change the Slideshow model to be
class Slideshow(SlideshowAbstract):
featureCategory = models.ForeignKey(Featurecategory,db_column=u'FeatureCategoryId')
def __unicode__(self):
return self.headline
class Meta:
db_table = u'Site1_Slideshow'
So doable but not the nicest if you are not doing "model first" and already have the schema. Would be good to be able to override the name of the _ptr_id column.
I did try adding the following to Slideshow too see if i could map this ptr col to the primary key
slideshowabstract_ptr_id = models.IntegerField(primary_key=True, db_column=u'SlideshowId')
but no cigar.
I havent tested inserts either but ...objects.all() works
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.
Maybe my question is somehow unspecific, sorry for that. I'm learning python and app engine (webapp2) at the moment.
I have this class:
class Ice(db.Model):
"""Models an individual Guestbook entry with an author, content, and date."""
name = db.StringProperty()
description = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
def getTags(self):
return Tag.all().ancestor(self).fetch(10)
Tags are referenced via ancestor.
When I use a jinja-template i can call ice.getTags() foreach Ice.
Now i want to serialize my Ice-object to JSON and want to have all Tags that belong to the Ice-object in my JSON-Output.
This does serialisation for me:
It works okay, but it doesn't include the Tags.
I'm feeling, that i have to declare Tags as Ice-Attribute, but i don't know how.
class IceHandler(basehandler.BaseHandler):
def get(self):
ice_query = model.Ice.all().order('-date')
ices = ice_query.fetch(10)
self.response.write(json.encode(ices))
Thanks!