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')
Related
I've been trying to post a nested object with one file and some data via django drf for a few days now. The goal is to create a story together with some images, one of these images being the title image of the story. Basically, I am able to post the story successfully with postman (see picture below). However, when I use my react js frontend for sending, I am not able to create the form data in a way that Django understands it. Django always returns the error story_media field is required. I suppose this is because Django does not understand the incoming data correctly.
class Story (models.Model):
title = models.CharField(max_length=100,blank=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
class Story_Media (models.Model):
story = models.ForeignKey(Story,on_delete=models.CASCADE, null=True, related_name = 'story_media', related_query_name = 'story_media')
file = models.FileField(upload_to='story_media/', null=True)
isTitlePicture = models.BooleanField(blank=False, null=True)
# Story Story Media Serializer
class Story_Media_Serializer (serializers.ModelSerializer):
class Meta:
model = Story_Media
fields = ('id','file','isTitlePicture',)
# Story Serializer
class StoryCreateUpdateSerializer (serializers.ModelSerializer):
story_media = Story_Media_Serializer(many=True)
class Meta:
model = Story
fields = ('title','story_media',)
def create(self, validated_data):
current_user = self.context["request"].user
story_media = validated_data.pop('story_media')
story_instance = Story.objects.create(author=current_user, **validated_data)
for story_media_data in story_media:
Story_Media.objects.create(**story_media_data, story=story_instance)
# Story Create View Set
class StoryCreateUpdateViewSet(viewsets.ModelViewSet):
serializer_class = StoryCreateUpdateSerializer
queryset = Story.objects.all()
This is how i create my form data in react js. In this example story_media_array contains only a single image object.
// array that stores all the images
let story_media_array = [];
// single image object
var image_object ={
file: this.state.file[0], // some file
isTitlePicture: "True"
}
// push image object in array
story_media.push(image_object);
let formdata = new FormData();
// title
formdata.append('title', "Test")
// image
formData.append('story_media', story_media_array)
However, as I wrote above, I am not able to create the form with the above code, it returns 'story_media field is required'. But it works with postman. I'm a bit lost at the moment, so I'm glad for any help.
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
Suppose I make a website that starts with initiating an instance of class 'Person' called 'person'.
Before saving 'person' to a database I want to manipulate some of the attributes using different html pages.
I don't understand how to keep track of the instance within Flask. How do I instruct Flask to keep track of the instance while moving from page to page?
See this simplified example within application.py:
from flask import ....
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# database stuff deleted to keep it short
class Person(db.Model):
__tablename__ = "persons"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
nickname = db.Column(db.Text)
def __init__(self, name, nickname):
self.name = name
self.nickname = nickname
self.age
def set_age(self,age):
self.age = age
#app.route("/")
def index():
return render_template("index.html")
#app.route("/register", methods=["POST"])
def register():
if request.form["name"] == "" or request.form["nickname"] == "":
return render_template("failure.html")
person = Person(request.form["name"], request.form["nickname"])
db.session.add(person)
db.session.commit()
return render_template("add_age.html", person = person)
#app.route("/add_age")
def add_age():
age = 23
person.set_age = age
return redirect(url_for("index"))
So I want to edit the 'age' attribute from a different page in this example.
I really don't undestand your question but to do that you have to know how Flask's application context and request context work.
Check out http://flask.pocoo.org/docs/0.12/quickstart/#sessions to persist data on a browser's cookie and acces from all views
I have the following model with a primary_key=True specified:
class Team(models.Model):
name = models.CharField(
max_length=64,
primary_key=True,
)
... other fields
When I serialize this model, I do the following:
class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ('url', 'name',) # and another fields
My viewset:
class TeamViewSet(viewsets.ModelViewSet):
lookup_value_regex = '[-\w.]'
queryset = Team.objects.all()
serializer_class = TeamSerializer
filter_fields = ('name',) # and another fields
My urls.py:
router = routers.DefaultRouter()
router.register(r'teams', TeamViewSet)
urlpatterns = [
url(r'^api/', include(router.urls)),
# I am not sure if this url is right. I repeat of include(router.urls)
url(r'^api/teams/(?P<name>[-\w.]+)/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Then, when I create a Team object with name attribute containing dot ., for example Latinos F.C. and I go to the rest url, I get:
I am not sure about of how to use the lookup_value_regex attribute in my viewset. In this answer is used with some basic regex, but if I use it, any Team object is reachable via my serialized Rest API.
How to can I get a url like as: /api/teams/Name.F.C. in my serialized Team model?
First of all check if you have set APPEND_SLASH to True in your settings, because if not - the missing slash (at the end of the URL) is a problem.
Second - I do not think that dot is a problem, the problem can be a space - coded as %20;
Third - such urls looks just ugly :) You should consider changing it to some kind of a slugs: Latinos F.C. -> latinos-fc;
If you do that (just add additional field on the model with slug - this field should be obviously unique) - set up the lookup_field on your view - this will solve your problem.
Consider the example:
views.py
class SomeViewSet(viewsets.ModelViewSet):
queryset = SomeModel.objects.all()
serializer_class = SomeSerializer
lookup_field = 'slug_name'
serializers.py
class SomeSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = ('id', 'name', 'slug_name')
read_only_fields = ('slug_name',)
def to_internal_value(self, data):
ret = super(SomeSerializer, self).to_internal_value(data)
ret['slug_name'] = slugify(ret['name'])
return ret
models.py
class SomeModel(models.Model):
name = models.CharField(max_length=100)
slug_name = models.SlugField(unique=True, max_length=100)
urls.py
router.register(r'teams', SomeViewSet, base_name='teams')
urlpatterns = router.urls
And now:
creation:
details:
Can you do that this way? Or you really need the dots?
Let me start by saying I'm really new to Python, app engine, and the datastore, so please be kind if I'm missing something obvious.
I'm trying to set up some data in the datastore with ancestor relationships, sort of the same way as in the example guestbook application from Google:
class Guestbook(webapp2.RequestHandler):
def post(self):
greeting = Greeting(parent=guestbook_key)
I created this code as an experiment to see if I could get it to work:
class Subscriber(ndb.Model):
user_nickname = ndb.StringProperty()
user_id = ndb.StringProperty()
class Music(ndb.Model):
level = ndb.StringProperty() # top or sub
parent = ndb.StringProperty() # only if sub
title = ndb.StringProperty()
class SetupHandler(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
subscriber = Subscriber(id=user.user_id())
subscriber.user_id = user.user_id()
subscriber.user_nickname = user.nickname()
haydn = Music(parent=subscriber.key)
haydn.level = "top"
haydn.title = "Haydn Trumpet Concerto"
haydn.put()
It seems to me as though I'm trying to do basically the same thing.. but I get this error:
File "... Application\datastoreexplore\main.py", line 41, in get
haydn = Music(parent=subscriber.key) BadValueError: Expected string, got Key('Subscriber', '12169615523634875051')
I've spent hours reading docs and searching through stackoverflow and elsewhere. I'm stumped. What am I doing wrong??
Your problem is thou have defined parent as a StringProperty but then passing in a key which is a valid constructor argument if you want to create an entity with anancestor. You should not have property called parent.