Many-to-many relationship modeling in google app engine - google-app-engine

I followed what is outlined here. Here is my code:
from google.appengine.api import users
from google.appengine.ext import db
class Book(db.Model):
title = db.StringProperty()
class Author(db.Model):
name = db.StringProperty()
class BookAuthor(db.Model):
book = db.ReferenceProperty(Book, required=True, collection_name='books')
author = db.ReferenceProperty(Author, required=True, collection_name='authors')
b = Book(title="My Book")
a = Author(name="Author of My Book")
db.put([b, a])
ba = BookAuthor(book=b, author=a)
ba.put()
b.authors
a.books
and I get AttributeError: 'Book' object has no attribute 'authors'

ReferenceProperties add query-objects as attributes to the referenced class. So look carefully at your mappings:
class BookAuthor(db.Model):
# This adds a query-object as an attribute named 'books' to Book entities.
book = db.ReferenceProperty(Book, required=True, collection_name='books')
# This adds a query-object as an attribute named 'authors' to Author entities.
author = db.ReferenceProperty(Author, required=True, collection_name='authors')
In your code:
b = Book(title="My Book")
a = Author(name="Author of My Book")
So, b would have a books attribute, not authors. And, a would have a authors attribute, not books.
If you change the collection names, your code should run.
class BookAuthor(db.Model):
# This adds a query-object as an attribute named 'authors' to Book entities.
book = db.ReferenceProperty(Book, required=True, collection_name='authors')
# This adds a query-object as an attribute named 'books' to Author entities.
author = db.ReferenceProperty(Author, required=True, collection_name='books')
Also, if BookAuthor does not have additional properties, make sure you look at the list-of-keys method outlined in the article you referenced.

Related

Got AttributeError when attempting to get a value for field `people` on serializer `commentsSerializer`

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.

Django - Filter on many to many model

I have 2 models: Book, Author
class Author(models.Model):
name = models.CharField(max_length=30)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
and in admin :
class BookAdmin(admin.ModelAdmin):
list_display = ('title')
filter_horizontal = ('authors',)
in admin , I want to see only Authors that related to specified Book
not all Authors
(in add mode Authors must be empty)
AdminBook:

Using GeoDjango model as an abstract class

I'm playing with GeoDjango and have some doubts. I'll really appreciate any comment and suggestion.
This is my problem. First, I've defined this (abstract) class:
from django.contrib.gis.db import models
from django.contrib.gis.geos import *
class LocatableModel(models.Model):
country = models.CharField(max_length=48, blank=True)
country_code = models.CharField(max_length=2, blank=True)
locality = models.CharField(max_length=48, blank=True)
sub_locality = models.CharField(max_length=48, blank=True)
street = models.CharField(max_length=48, blank=True)
address = models.CharField(max_length=120, blank=True)
point = models.PointField(null=True)
objects = models.GeoManager()
class Meta:
abstract = True
Second, I've defined this other 'Entity' class, which
represents a person or organization related to my site:
from django.db import models
class Entity(models.Model):
name = models.CharField(max_length=64)
slug = models.SlugField(max_length=64, unique=True)
website = models.URLField(verify_exists=False, blank=True)
email = models.EmailField(blank=True)
...
Finally, I've created a class from the previous ones:
import LocatableModel
import Entity
class Organization(Entity, LocatableModel):
timetable = models.CharField(max_length=64)
...
In my views, I'd like to find organizations near a specific point:
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
def index(request):
pnt = Point(12.4604, 43.9420)
dic = { 'orgs': Organization.objects.filter(point__distance__lte=(pnt, D(km=7))) }
return render_to_response('index.html', dic)
But I receive the error:
"Join on field 'point' not permitted. Did you misspell 'distance' for
the lookup type?"
I think I'm doing a mess with the model 'objects' property, but I'm not sure. Any ideas?
Thanks in advance.
This error has been seen before, and claimed to be solved in this ticket 3 years ago:
https://code.djangoproject.com/ticket/9364
When I ran into this same problem, I noticed in the ticket that the query manager was set explicitly to GeoManager in the inherited model(s). So adding a line like,
class Organization(Entity, LocatableModel):
timetable = models.CharField(max_length=64)
...
objects = models.GeoManager()
...may solve the issue you're seeing, it worked for me.

How to determine Google App Engine class type?

Say I have 3 entities:
class A(db.Model):
something = db.StringProperty()
class B(db.Model):
somethingelse = db.StringProperty()
class C(db.Model):
reference = db.ReferenceProperty()
where the Reference in C can be either A or B, how to I determine, given an instance of C, the reference's type (A or B)?
Regards,
Johnny
You can do this without fetching the referenced entity like this:
c_instance = C.get(...)
referenced_kind = C.reference.get_value_for_datastore(c_instance).kind()
or, if you already have an entity:
entity.key().kind()
See the docs on Key and Property for more info.

Relationships in Django Admin

I get really confused with many-to-many database relationships, so can some one please clarify how I would achieve this?
I need a table of "Tags" (as in tag words) and a table for "Entries", such at many "Entries" could correspond to many Tag words.
Right now I have my models like this:
# models.py
class Tags(models.Model):
tag = models.CharField(max_length=255)
entry = models.ManyToManyField(Entry)
class Entry(models.Model):
entry = models.CharField(max_length=255)
description = models.TextField()
Now I'm confused, how would I setup my admin.py so I could then add tags when I create a new entry?
What you need is using the through feature of models:
class Tag(models.Model):
tag = models.CharField(max_length=255)
entry = models.ManyToManyField(Entry, through='TaggedEntries')
class Entry(models.Model):
entry = models.CharField(max_length=255)
description = models.TextField()
class TaggedEntries(models.Model):
entry = models.ForeignKey(Entry)
tag = models.ForeignKey(Tag)
and now use that model in your admin:
class TagsInline(admin.TabularInline):
model = TaggedEntries
extra = 1
class EntryAdmin(admin.ModelAdmin):
inlines = (TagsInline, )
admin.site.register(Entry, EntryAdmin)
admin.site.register(Tag)
You will need something along the lines of:
# admin.py
from django.contrib import admin
from models import *
class TagsInline(admin.TabularInline):
model = Tag
extra = 1
class EntryAdmin(admin.ModelAdmin):
inlines = (TagsInline, )
admin.site.register(Entry, EntryAdmin)
admin.site.register(Tag)
(Note, this code was written in a browser!)

Resources