passing object of a class to another class in google app engine - google-app-engine

I am working with google app engine,
I have 2 classes namely A and B and one db model say DB,
I have processed object of DB model in class A, and i want
to send the same object in class B, How can i do this?
Here is my code,
class Candidate(db.Model):
name = db.StringProperty()
lastname = db.StringProperty()
email = db.StringProperty()
mobno = db.StringProperty()
class A(webapp2.RequestHandler):
def post(self):
currCandidate = Candidate(key_name=self.request.get('email'))
currCandidate.name = self.request.get('name')
currCandidate.lastname=self.request.get('lname')
currCandidate.email=self.request.get('email')
currCandidate.mobno=self.request.get('mobno')
class B(webapp2.RequestHandler):
def get(self):
# currCandidate
# want to access currCandidate object here,
# currCandidate is from class A
I want to access the currCandidate object from class B.

Your 'A' handler is a POST, and gets a Candidate object via keyname, which is the email request parameter. Can you not use the same mechanism for the 'B' handler? This is a GET so you will need to pass the email in as a URL parameter. For example https://yourapp.appspot.com/b?email=someemail#domain.com.
You can then pick it up again with the same code you are using in the POST - currCandidate = Candidate(key_name=self.request.get('email')).

since you are creating a web app,you can store the object in session variable and access it in other class.In java this is done by serializing the object and storing it in session variable

Related

Django Models: Accessing Parent Object Attribute Within a Related Object Using OneToOneField

I am trying to access the username attribute of a Django User object from a Profile object that is related by a OneToOneField.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.TextField(default=user.username, primary_key=True)
image = models.ImageField(upload_to='images/profile')
header = models.CharField(max_length=64)
slug = AutoSlugField(populate_from='x')
bio = models.CharField(max_length=300, blank=True)
The intent of this is to be able to get a Profile object using a ReactJS frontend by passing the username provided at login back to a profile detail endpoint in a Django API, where the username is the primary key for the endpoint.
path('<pk>/profile/', ShowProfilePageView.as_view(), name='show_profile_page'),
I've tried many different things for the default argument passed to the Profile username attribute, but nothing is working so far. Is this even possible?
Addendum 1: ShowProfilePageView view
class ShowProfilePageView(generics.RetrieveUpdateDestroyAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
model = Profile
I think you can simply override the lookup_field in the View, like this:
class ShowProfilePageView(generics.RetrieveUpdateDestroyAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
model = Profile
lookup_field='user__username'
lookup_url_kwarg='username'
And update the url like this:
path('<str:username>/profile/', ShowProfilePageView.as_view(), name='show_profile_page')
Because through lookup_field, the view will look for the value in User model from Profile model. And lookup_url_kwargs is to map what value it should use from urls. More information can be found in documentation. FYI you should remove username field from Profile model, it should use AutoField(which is the default field for primary key in models).
To access the attribute of one-to-one field you can just do this:
profile = Profile.objects.get(pk='profile_pk') # an object of profile
username = profile.user.username
To search Profile via username:
profile = Profile.objects.get(user=User.objects.get(username='username'))
Thus, you don't need to define username field on Profile class

Serializer field for side effect model django rest framework

I have a django.db.models.Model A whose instances are created in a rest_framework.serializers.ModelSerializer from POST requests.
Depending on the data being sent in the POST, I would like to create one of several other "addon" models, let's say B or C, which I link to the original through a django.db.models.OneToOneField:
from django.db import models
class A(models.Model):
some_field = models.CharField()
class B(models.Model):
a = models.OneToOneField(A, related_name='addon', on_delete=models.CASCADE)
class C(models.Model):
a = models.OneToOneField(A, related_name='addon', on_delete=models.CASCADE)
What I would like to is to have a serializer which validates the incoming data, including some string indicating which addon to use. The serializer then creates the model instance of A and based on this creates the addon model.
I do not want to create a utility field in model A used to determine which addon to use, I would like to create the model directly using the instance of model A and information from the POST itself.
At the same time when accessing the data through a get, I would like to return the original string used to determine which addon to use.
What I have come up with so far:
from rest_framework import serializers
str2model = {'b': B, 'c': C}
class AddonField(serializers.Field):
def to_representation(self, value):
# I completely ignore "value" as no "internal value" is set in "to_internal_value"
myvalue = self.parent.instance.addon
for addon_name, addon_class in str2model.items():
if isinstance(myvalue, addon_class):
return addon_name
def to_internal_value(self, data):
# I create the "internal value" after "A" instance is created, thus here I do nothing?
return data
class ASerializer(serializers.ModelSerializer):
some_field = serializers.CharField()
the_addon = AddonField()
def validate_the_addon(self, value): # here addon is a string
if value in str2model.keys():
return value
def create(self, validated_data):
addon_name = validated_data.pop('the_addon')
addon_class = str2model[addon]
a = super(ASerializer, self).create(validated_data)
addon_class.objects.create(a=a)
return a
class Meta:
model = A
fields = ["some_field", "the_addon"]
When testing this I get:
AttributeError: Got AttributeError when attempting to get a value for field `the_addon` on serializer `ASerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `A` instance.
Original exception text was: 'A' object has no attribute 'the_addon'.
How can I temporarily store the_addon in the serializer until the A instance has been created?
This is how I would typically approach it
# Serializer
class ASerializer(serializers.Serializer):
some_field = serializers.CharField()
addon_b = serializers.CharField(required=False, allow_null=True)
addon_c = serializers.CharField(required=False, allow_null=True)
def create(self, validated_data):
addon_b = validated_data.pop('addon_b')
addon_c = validated_data.pop('addon_c')
a = A.objects.create(some_field=validated_data['some_field'])
if addon_b:
B.objects.create(a=a)
if addon_c:
C.objects.create(a=a)
return a
You can do other validations if necessary.
class TestAPIView01(generics.CreateAPIView):
permission_classes = {}
serializer_class = serializers.ASerializer
queryset = A.objects.all()
Also, look at the related_name on B and C you may want to consider making them different, as that might throw an error in the future. Cheers

Add field to drf serializer dynamically

I have an API endpoint that return a list of objects of one of my models.
I have a very trivial serializer that currently returns all the model fields.
What I need now is to add to this serializer another field which is calculated by applying a logic on one of the model field and another data structure that is also calculated dynamicly - but should be calculated only once for each call to the API.
What is the way to supply this structure to the serializer for every API call but not for every object the serializer returns?
My ModelViewSet (without the extra field) is quite trivial:
class MyModelViewset(ModelViewSet):
queryset = SomeModel.objects.all()
serializer_class = SomeModelSerializer
Some suggestions on how you can achieve this:
To calculate something only once and use it in the serializer you should add it to the serializer context.
You can create #property in your SomeModel class and it can be exposed via serializer fields as read only. Django has also #cached_property so that value is only calculated once and persist as long as the instance does
You can use SerializerMethodField field if you want to calculate something (you have access the serializer context in there).
Just a quick example on how to use this.
class MyModelViewset(ModelViewSet):
queryset = SomeModel.objects.all()
serializer_class = SomeModelSerializer
def get_serializer_context(self):
context = super().get_serializer_context()
context['my_value'] = [] # calculate something here, you have access to self.request
return context
class SomeModelSerializer(serializers.ModelSerializer):
my_data = serializers.SerializerMethodField()
class Meta:
model = SomeModel
def get_my_data(self, obj):
# you have access to self.context['my_value']
# you have access to obj.some_property
return my_data

Updating existing entity in endpoints-proto-datastore

I am using Endpoints-proto-datastore written by Danny Hermes for Google App Engine and need help figuring out how to update an entity.. My model for what I need to update is the following
class Topic(EndpointsModel):
#_message_fields_schema = ('id','topic_name','topic_author')
topic_name = ndb.StringProperty(required=True)
topic_date = ndb.DateTimeProperty(auto_now_add=True)
topic_author = ndb.KeyProperty(required=True)
topic_num_views = ndb.IntegerProperty(default=0)
topic_num_replies = ndb.IntegerProperty(default=0)
topic_flagged = ndb.BooleanProperty(default=False)
topic_followers = ndb.KeyProperty(repeated=True)
topic_avg_rating = ndb.FloatProperty(default=0.0)
topic_total_rating = ndb.FloatProperty(default=0.0)
topic_num_ratings = ndb.IntegerProperty(default=0)
topic_raters = ndb.KeyProperty(repeated=True)
And as you can see, the rating properties have a default of 0. So each time a topic is rated, I need to update each of the rating properties. However, none of my properties is the actual rating being provided by the user. How can i pass in the value the user rated the topic to be able to update the properties in the model? Thanks!
You can do this by having an "alias" property called rating associated with your UserModel:
from endpoints_proto_datastore.ndb import EndpointsAliasProperty
class UserModel(EndpointsModel):
...
def rating_set(self, value):
# Do some validation
self._rating = value
#EndpointsAliasProperty(setter=rating_set)
def rating(self):
return self._rating
This will allow ratings to be sent with UserModels in requests but won't require those ratings to be stored.
You're better off using the OAuth 2.0 token for the user and calling endpoints.get_current_user() to determine who the user is in the request.
Something like a dedicated model for ratings could be much easier:
from endpoints_proto_datastore.ndb import EndpointsUserProperty
class Rating(EndpointsModel):
rater = EndpointsUserProperty(raise_unauthorized=True)
rating = ndb.IntegerProperty()
topic = ndb.KeyProperty(kind=Topic)
and then transactionally retrieving the Topic from the datastore and updating it in a request method decorated by #Rating.method.

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.

Resources