Google App engine: No key_name attribute - google-app-engine

I'm trying to learn how the GAE, most things are working, but for some strange reason, this code outputs a
AttributeError: 'User_Account' object has no attribute 'key_name'
Here's the two code extracts that are relevant:
class User_Account(ndb.Model):
name = ndb.StringProperty()
firstname = ndb.StringProperty()
class AddUser(webapp2.RequestHandler):
def get(self):
test_user = User_Account(name = "snow", firstname ="jon", key_name="jon")
I've tried it with db and ndb model, it doesn't work either way...
Thanks in advance for any answer.
UPDATE: Here's the "full" code (i removed all the other un-necessary parts):
import webapp2
import cgi
from google.appengine.ext import ndb
MAIN_PAGE_HTML = """\
<html>
<body>
<br/>
Add a user
</body>
</html>
"""
class Comment(ndb.Model):
content = ndb.StringProperty()
class User_Account(ndb.Model):
name = ndb.StringProperty()
firstname = ndb.StringProperty()
comments = ndb.KeyProperty(repeated=True)
class AddUser(webapp2.RequestHandler):
def get(self):
test_user = User_Account(name = "jon", firstname ="snow", key_name="jon")
self.response.write(test_user.key_name + "<br/>")
test_user.put()
self.response.write("User added")
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write(MAIN_PAGE_HTML)
application = webapp2.WSGIApplication([
('/', MainPage),
('/add_user', AddUser)
], debug=True)
MOAR EDIT:
Even this very simple code, when executed in the dev console, outputs an error
import os
import pprint
from google.appengine.ext import ndb
class Comment(ndb.Model):
content = ndb.StringProperty()
test_comment = Comment(content="Hello world", key_name="hello")
test_comment.put()

Please read documentation for the ndb Model class. Specifically on the model constructor arguments. https://developers.google.com/appengine/docs/python/ndb/modelclass#Constructor
You will see it takes id, rather than key_name. key_name is a constructor argument for db api.

I had a solution to a similar case where I wanted the key_name of an entity (which had key_name only and no ID). I was able to find the key_name from the property self.key().name()

Related

Django DRF Foreign Key

This question or many like it has been asked multiple times but for some reason I am unable to find the answer.
I do have this working to an extent in the way that if you go on the api pages, it renders, creates and updates without problem. The issue is displaying a field (title) from the nested object instead of just the primary key on the front end.
Some background before getting into the code:
Races is a finite list (e.g. Race1, Race2, Race3) and the front end does not have the ability to add more.
Cards is not finite, but each card must link to an existing Race (this currently does so by Primary Key).
The front end should display the card_text and race title of the linked race.
It also has the ability to add a new card but this works fine.
I have had this working with separate serializers for read and create/update where the read has a 'depth = 1' to pull through the entire object but the create/update doesn't and you then parse the object and send the primary key back (I couldn't find a way of doing this in the serializer, is it possible?).
So basically my question is, are you meant to pass the entire object through and parse it on a POST method, or do you pass the primary key and pull in the linked objects (Races) and use the primary key as an index (e.g. Races[card_race]). Also, why is 'linked_race' not coming through to the front end?
I realise I've almost answered my own question but as I'm new to Django I'm looking for the correct conventions and who knows, it may save someone else time when searching for the same answer.
urls.py
from .api import CardViewSet, RaceViewSet
from rest_framework.routers import DefaultRouter
from django.conf.urls import url, include
from .views import landing
router = DefaultRouter()
router.register(r'cards', CardViewSet)
router.register(r'races', RaceViewSet)
urlpatterns = [
url(r'^$', landing),
url(r'^api/', include(router.urls)),
]
api.py
from rest_framework.viewsets import ModelViewSet
from .serializers import CardSerializer, RaceSerializer
from .models import Card, Race
class CardViewSet(ModelViewSet):
queryset = Card.objects.filter(active=True)
def get_serializer_class(self):
return CardSerializer
def perform_create(self, serializer):
serializer.save(creator=self.request.user)
class RaceViewSet(ModelViewSet):
queryset = Race.objects.filter(active=True)
serializer_class = RaceSerializer
models.py
from django.db import models
from django.conf import settings
User = settings.AUTH_USER_MODEL
class Race(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=30, blank=False)
active = models.BooleanField(default=True)
def __str__(self):
return "{}".format(self.title)
def __unicode__(self):
return self.title
class Card(models.Model):
card_text = models.CharField(max_length=100, blank=False)
card_description = models.CharField(max_length=100, blank=True)
card_race = models.ForeignKey(Race, related_name='linked_race', on_delete=models.CASCADE)
creator = models.ForeignKey('auth.User', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.card_text
class Meta:
ordering = ('created',)
serializers.py
from rest_framework import serializers
from .models import Card, Race
class RaceSerializer(serializers.ModelSerializer):
class Meta:
model = Race
fields = '__all__'
class CardSerializer(serializers.ModelSerializer):
linked_race = RaceSerializer(read_only=True, many=True)
class Meta:
model = Card
fields = 'id', 'card_text', 'card_description', 'card_race', 'linked_race',
Javascript extract (AngularJS)
$http.get('/api/races/').then(function (response) {
$scope.races = response.data;
$scope.selectedOption = $scope.races[0];
});
$scope.cards = [];
$http.get('/api/cards/').then(function (response) {
$scope.cards = orderBy(response.data, 'created', true);
});
html extract (AngularJS)
<div class="races--row" ng-repeat="c in cards | filter : card_filter |
orderBy : sortVal : sortDir" ng-class-odd="'odd'" ng-click="openModal(c)">
<div class="races--cell race">{{ c.card_race.title }}</div>
<div class="races--cell card-text">{{ c.card_text }}</div>
</div>
Your first "problem" is with the Card model (I say problem because I don't think you intended to do this). You're defining related_name='linked_race' for the card_race field. This related_name is the name you use to refer to a card FROM a race.
I would suggest you leave it out and use the default that Django already gives us (i.e. my_race.card_set.all() in this case). So change change that field in the Card model to:
class Card(models.Model):
...
card_race = models.ForeignKey(Race, on_delete=models.CASCADE)
...
And let's change the card serializer to:
class CardSerializer(serializers.ModelSerializer):
# no more linked_race
class Meta:
model = Card
fields = ('id', 'card_text', 'card_description', 'card_race')
Alright, this is a vary basic model serializer and you won't see details of a race yet. So now let's get to your main problem which was that you wanted to:
see the details of the associated race of a card
perform create/get/update/delete operations using the same serializer
For this, let's further change the CardSerializer to include another field called race_detail:
class CardSerializer(serializers.ModelSerializer):
race_detail = RaceSerializer(source='card_race', read_only=True)
class Meta:
model = Card
fields = ('id', 'card_text', 'card_description', 'card_race', 'race_detail')
We have defined two serializer fields for the same model field. Note the source and read_only attributes. This makes this field available when you GET a card (which is what we want), but not when you're performing POSTs or PUTs (which avoids the problem of sending the whole race object and parsing and stuff). You can just send the race id for the card_race field and it should work.

How to create an entity of a model with referenceProperty without the reference exists?

I have two model classes Team and Student. Each Team entity has more than one Users entities, I think "one to many" is a proper model. I code like this:
class Team(db.Model):
teamNmae = db.StringProperty(required=True)
teamID = db.IntegerProperty(required=True)
class Users(db.Model):
name = db.StringProperty(required=True)
reference = db.ReferenceProperty(Team,collection_name=teamMembers)
Follow this document, I need to first create a Team entity, then create Users whose reference is set to this Team entity. But,here is the problem, I want to create User first, then User can create a Team. So, how to set reference when I create a User that no Team exists ?
EDIT1:
I write simple code to test if I can create a entity without its reference entity created.
_author__ = 'Steven_yang'
import os
import webapp2
from google.appengine.ext import db
from google.appengine.ext.webapp import template
defaultStu = [
'qingWANG',
'stevenYANG',
'jingZHU',
'conghuiHE',
'lianDUAN',
'xinHAO'
]
class Students(db.Model):
#reference = db.ReferenceProperty(Team,collection_name='teamMember',required=False)
name = db.StringProperty(required=True)
class Team(db.Model):
teamName = db.StringProperty(required=True)
teamID = db.IntegerProperty(required=True)
def createStu():
stu_count = Students.all().count(1)
if stu_count == 0:
for stu in defaultStu:
newStu = Students(name = stu)
newStu.put()
class testReferenceHandler(webapp2.RequestHandler):
def get(self):
createStu()
self.render_page()
def render_page(self):
stus = Students.all().fetch(10)
templateValues={}
templateValues['stus'] = stus
form = os.path.join(os.path.dirname(__file__),'template/testref.html')
renderForm = template.render(form,templateValues)
self.response.out.write(renderForm)
app = webapp2.WSGIApplication([('/testref',testReferenceHandler)],debug=True)
HTML file is:
<body>
{% for s in stus%}
<div>{{s.name}}</div>
{% endfor%}
</body>
</html>
when I comment out the ReferenceProperty line, everything is fine. When I add the ReferenceProperty line, I got a server error. So, I can't create a entity without its reference created before?
Did you try to set reference to Team model as None when creating a User instance?
Also change the last line your code snippet to:
reference = db.ReferenceProperty(Team,required=False)
i.e. add required=False. This is what is suggested in this answer.

GAE simple data model error '_ReverseReferenceProperty' object has no attribute 'fetch'

I have one-to-many model scheme. All seems correct, data population works but linkitem_set.fetch fails with:
AttributeError: '_ReverseReferenceProperty' object has no attribute
'fetch'
There also one question here on SO with the same error but without solution.
My code below:
class Project(db.Model):
name = db.StringProperty()
class LinkItem(db.Model):
url = db.StringProperty()
project = db.ReferenceProperty(Project)
class Show(webapp2.RequestHandler):
def get(self):
links = Project.linkitem_set.fetch(100)
self.response.headers['Content-Type'] = 'text/plain'
for li in links:
self.response.out.write(li + '/r/n')
class PopulateDb(webapp2.RequestHandler):
def get(self):
prj = Project(name = 'SomeProject 1')
prj.put()
for i in range(1000):
rlink = random.betavariate(1, 2)
link = LinkItem(url = str(rlink), project = prj)
link.put()
I'm using Python 2.7 and tested this localy and hosted.
I think that the problem is that the linkitem_set collection will only exist for an instance of Project, but you are trying to use it on the class itself.
Your code should look something more like this:
class Show(webapp2.RequestHandler):
def get(self):
prj_name = "" # Get a valid value, probably from URL params
prj_to_show = Project.all().filter("name=", prj_name).get()
if prj_to_show is not None:
links = prj_to_show.linkitem_set.fetch(100)
self.response.headers['Content-Type'] = 'text/plain'
for li in links:
self.response.out.write(li + '/r/n')

Override Django User model __unicode__

Currently, Django 1.2.3 User model unicode is
def __unicode__(self):
return self.username
and I'd like to override it so its:
def __unicode__(self):
return u'%s, %s' % (self.last_name, self.first_name)
How to?
To similar effect:
User._meta.ordering = ['last_name', 'first_name']
works when defined anywhere
If you simply want to show the full name in the admin interface (which is what I needed), you can easily monkey-patch it during runtime. Just do something like this in your admin.py:
from django.contrib import admin
from django.contrib.auth.models import User
def user_unicode(self):
return u'%s, %s' % (self.last_name, self.first_name)
User.__unicode__ = user_unicode
admin.site.unregister(User)
admin.site.register(User)
Django's Proxy Model solved this problem.
This is my solution:
form.fields['students'].queryset = Student.objects.filter(id__in = school.students.all())
Here school.students is a m2m(User), Student is a proxy model of User.
class Student(User):
class Meta:
proxy = True
def __unicode__(self):
return 'what ever you want to return'
All above helps you to solve if your want to show your User ForeignKey in your custom method. If your just want to change it in admin view, there is a simple solution:
def my_unicode(self):
return 'what ever you want to return'
User.__unicode__ = my_unicode
admin.site.unregister(User)
admin.site.register(User)
add these codes to admin.py, it works.
If you need to override these, chances are you would need more customizations later on.
The cleanest practice would be using a user profile models instead of touching the User model
Create a proxy User class.
class UserProxy(User):
class Meta:
proxy = True
ordering = ['last_name', 'first_name']
def __unicode__(self):
return u'%s, %s' % (self.last_name, self.first_name)
I just found this simple method on django 1.5
def __unicode__(self):
a = self.last_name
b = self.first_name
c = a+ "-" +b
return c
it will return what you want

Django-nonrel in Google App Engine ListField

I am trying to build an example app in Google App Engine using django-nonrel. and am having problems implementing ListField attribute into a model.
I have created an app test_model and have included it as an installed app in my settings. The model.py is:
from django.db import models
from djangotoolbox import *
from dbindexer import *
# Create your models here.
class Example(models.Model):
some_choices = models.ListField('Choice_examples')
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
The above example gives me:
AttributeError:'module' object has no attribute 'Model'
If I comment out the djangotoolbox import, I get the following :
AttributeError: 'module' object has no attribute 'ListField'
What am I doing wrong here? I can't seem to find any documention as to how to go about using ListField in django-nonrel. Is that because it is supposed to really obvious?
Your imports are smashing each other:
from django.db import models
from djangotoolbox import *
The second import will replace the django.db models with djangotoolbox' empty models module. Using from X import * is a terrible idea in general in Python and produces confusing results like these.
If you're looking to use ListField from djangotoolbox, use:
from djangotoolbox import fields
and refer to the ListField class as fields.ListField.
OK, here is what I did to be able to use ListFields. MyClass the equivalent to your Example class and AnotherClass is the same as your Choice_examples. What I describe will allow you to use ListFields in the admin interface and your self implemented views.
I'll start from the beginning
This is what what my model looks like
class MyClass(models.Model):
field = ListField(models.ForeignKey(AnotherClass))
I wanted to be able to use the admin interface to create/edit instances of this model using a multiple select widget for the list field. Therefore, I created some custom classes as follows
class ModelListField(ListField):
def formfield(self, **kwargs):
return FormListField(**kwargs)
class ListFieldWidget(SelectMultiple):
pass
class FormListField(MultipleChoiceField):
"""
This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
"""
widget = ListFieldWidget
def clean(self, value):
#TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
return value
These classes allow the listfield to be used in the admin. Then I created a form to use in the admin site
class MyClassForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MyClasstForm,self).__init__(*args, **kwargs)
self.fields['field'].widget.choices = [(i.pk, i) for i in AnotherClass.objects.all()]
if self.instance.pk:
self.fields['field'].initial = self.instance.field
class Meta:
model = MyClass
After having done this I created a admin model and registered it with the admin site
class MyClassAdmin(admin.ModelAdmin):
form = MyClassForm
def __init__(self, model, admin_site):
super(MyClassAdmin,self).__init__(model, admin_site)
admin.site.register(MyClass, MyClassAdmin)
This is now working in my code. Keep in mind that this approach might not at all be well suited for google_appengine as I am not very adept at how it works and it might create inefficient queries an such.
I don't know, but try with:
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
class Example(models.Model):
some_choices = models.ListField(Choice_examples)
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
Looks like the answer is that you cannot pass an object into fields.ListField.
I have ditched trying to work with ListField as documentation is limited and my coding skills aren't at a level for me to work it out.
Anyone else coming across a similar problem, you should consider create a new model to map the ManyToMany relationships. And if the admin view is important, you should look into the following to display the ManyToMany table inline with any given admin view:
http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#s-working-with-many-to-many-models

Resources