'ReverseManyToOneDescriptor' object has no attribute 'latest' - python

I have received this error when trying to run a function. This is my first django/python project so I am not experienced in this. I have searched for this error but not found anything similar.
def getpriority(chunks):
p = 0
for chunk in chunks:
a = chunk.result_set.all()
l = a.latest()
if pytz.utc.localize(datetime.now()) - l.timestamp > datetime.timedelta(days=3):
x = getresult(chunk)
print(x)
I am trying to assign priorities to my Chunk model so I can select the Chunk with the highest priority to use the object.
I believe that my error is in calling latest() on 'a'.
When I run Chunk.result_set.latest() in a django shell I get the following error:
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'latest'
In my Result model, I have set get_latest_by which I believe is required to run .latest():
class Result(models.Model):
rel_chunk = models.ForeignKey(Chunk, on_delete=models.CASCADE)
score = models.IntegerField()
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
get_latest_by = 'timestamp'
I believe that the error lies in the fact that I'm calling latest on a related object set but if this can't be called on a related object set then how can I find the latest related Result?

It should be chunk.result_set.latest() not Chunk.result_set.latest()
note that chunk should be a instance not a class model.

The error indicates that you're accessing the result_set attribute on the model class. You need to access it on a model instance, in which case it will return a proper manager object instead of a ReverseManyToOneDescriptor:
chunk = Chunk.objects.get(...)
chunk.result_set.latest()
Here, chunk.result_set is a manager that behaves exactly like Result.objects, except it filters the queryset to only include results related to the chunk instance. The manager also has some added methods to manipulate the relation between chunk and the results, such as chunk.result_set.add() and chunk.result_set.remove() to add/remove results from the result set related to this chunk instance.
As this all applies to a specific instance of Chunk, it makes no sense to access the related manager on a class level. That's why you need a Chunk instance to use the related manager.
Since chunk.result_set is a manager instance, it proxies all queryset methods*. There is no reason why you would need chunk.result_set.all().latest() instead of just chunk.result_set.latest().
*) delete() is disabled on managers so you don't accidentally delete all objects. as_manager() is disabled as it makes no sense on a manager.

Related

How to force a Django model to reload fields after saving without using refresh_from_db?

I have the following Django models:
Device had a foreign key to Deployment
I have the adopt method in Device that set the deployment for a device and perform some additional logic.
notice that I pass an id and not a Deployment instance to the adopt method
class Device(Model):
id = models.UUIDField(primary_key=True)
deployment = models.ForeignKey(
Deployment, on_delete=models.SET_NULL, blank=True, null=True, related_name='devices'
)
def adopt(self, deployment_id):
self.deployment_id = deployment_id
self.full_clean()
with transaction.atomic():
self.save()
# self.refresh_from_db()
if self.deployment.private: # this might fail.. see examples
# additional logic
pass
class Deployment(TimeStampedModel, DeploymentResource):
id = models.UUIDField(primary_key=True)
name = models.CharField(max_length=150)
private = models.BooleanField(default=False)
If I do not access to the deployment field of the Device instance, adopt() works as expected.
example:
device = Device.objects.get(pk=device_id)
device.adopt(deployment_id) # this works
if instead I load the deployment field before calling adopt, when I call Adopt I get an AttributeError: 'NoneType' object has no attribute 'private'
this does not works:
device = Device.objects.get(pk=device_id)
print(device.deployment) # example of accessing/loading the field/relation
device.adopt(deployment_id) # this will generate the attribute error
The cause is pretty obvious. device.deployment was None, its value has been loaded and stored inside the model but it's not automatically reloaded and substituted with the new deployment after the save() call.
The first example works simply because the deployment relation has never been accessed before the save.
An obvious solution is to call refresh_from_db after saving (see comment inside adopt method) but this will generate an additional query that I would like to avoid.
Is there a way to force the model to forget the "cached" value of the deployment attribute that does not involve an additional query?
edit: clarified where the exception is raised
I´m not sure if i understand this correctly but to me it seems like the problem is rather that the default value of deployment is null.
So if you try to access deployment without assigning a deployment object first it will be null.
Please check if you are assigning deployment before calling device.deployment and if so please provide some code so i can recreate your situation.

Prefetch object not working with order_by queryset

Using Django 11 with PostgreSQL db. I have the models as shown below. I'm trying to prefetch a related queryset, using the Prefetch object and prefetch_related without assigning it to an attribute.
class Person(Model):
name = Charfield()
#property
def latest_photo(self):
return self.photos.order_by('created_at')[-1]
class Photo(Model):
person = ForeignKey(Person, related_name='photos')
created_at = models.DateTimeField(auto_now_add=True)
first_person = Person.objects.prefetch_related(Prefetch('photos', queryset=Photo.objects.order_by('created_at'))).first()
first_person.photos.order_by('created_at') # still hits the database
first_person.latest_photo # still hits the database
In the ideal case, calling person.latest_photo will not hit the database again. This will allow me to use that property safely in a list display.
However, as noted in the comments in the code, the prefetched queryset is not being used when I try to get the latest photo. Why is that?
Note: I've tried using the to_attr argument of Prefetch and that seems to work, however, it's not ideal since it means I would have to edit latest_photo to try to use the prefetched attribute.
The problem is with slicing, it creates a different query.
You can work around it like this:
...
#property
def latest_photo(self):
first_use_the_prefetch = list(self.photos.order_by('created_at'))
then_slice = first_use_the_prefetch[-1]
return then_slice
And in case you want to try, it is not possible to use slicing inside the Prefetch(query=...no slicing here...) (there is a wontfix feature request for this somewhere in Django tracker).

Django: accessing model attributes

Apologies for the noobish question, I am completely new to both Python and Django and trying to make my first app.
I have a simple class
class About(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
date = models.DateTimeField('date added')
to which I've added a single record. I can access this with
about = About.objects.filter(id=1)
however, if I try to use dot syntax to access its attributes I get the following error
>>> about.title
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'QuerySet' object has no attribute 'title'
I know how to use unicode in the model to specify a nicer return value such as
def __unicode__(self):
return self.title
should I be using this to format the model data into a dictionary/list? Or am I just completely missing some default behaviour?
In your case, about is a QuerySet object, not an instance of your model. Try
print about[0].title
Alternatively, use get() to retrieve a single instance of the model:
about = About.objects.get(id=1)
print about.title
Filter returns a QuerySet and not the single object you are looking for. Use get instead of filter.
Methods that return new QuerySets
filter
...
Methods that do not return QuerySets
get
...
http://docs.djangoproject.com/en/dev/ref/models/querysets/
As the documentation explains, filter always returns a QuerySet, which is a list-like collection of items, even if only one element matches the filter condition. So you can slice the list to access your element - about[0] - or, better, use get() instead:
about = About.objects.get(id=1)
print about.title
If you want get just one row
about = About.objects.get(pk=1)
now about is an object(one row)
filter returns list, so for accessing items in list you must use index(about[0]) or for loop.but get return exactly one row.

Manager isn't accessible via model instances

I'm trying to get model objects instance in another one and I raise this error :
Manager isn't accessible via topic instance
Here's my model :
class forum(models.Model):
# Some attributs
class topic(models.Model):
# Some attributs
class post(models.Model):
# Some attributs
def delete(self):
forum = self.topic.forum
super(post, self).delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Here's my view :
def test(request, post_id):
post = topic.objects.get(id = int(topic_id))
post.delete()
And I get :
post.delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Manager isn't accessible via topic instances
The error in question is caused when you try to access the Manager of a model through an instance of the model. You have used lower case class names. This makes it hard to say if the error is caused by an instance accessing the Manager or not. Since other scenarios that can cause this error are unknown I am proceeding on the assumption that you have somehow mixed up the topic variable so that you end up pointing to an instance of the topic model instead of the class.
This line is the culprit:
forum.topic_count = topic.objects.filter(forum = forum).count()
# ^^^^^
You have to use:
forum.topic_count = Topic.objects.filter(forum = forum).count()
# ^^^^^
# Model, not instance.
What is going wrong? objects is a Manager available at the class level, not to the instances. See the documentation for retrieving objects for details. Money quote:
Managers are accessible only via model classes, rather than from model instances, to enforce a separation between "table-level" operations and "record-level" operations.
(Emphasis added)
Update
See the comments from #Daniel below. It is a good idea (nay, you MUST :P) to use title case for class names. For instance Topic instead of topic. Your class names cause some confusion whether you are referring to an instance or a class. Since the Manager isn't accessible via <model> instances is very specific I am able to offer a solution.The error may not be so self evident always.
topic.__class__.objects.get(id=topic_id)
For django < 1.10
topic._default_manager.get(id=topic_id)
Though you should not use it like this. The _default_manager and _base_manager are private, so it's recomended to use them only if you're inside the Topic model, like when you want to use the Manager in a proprietary function let's say:
class Topic(Model):
.
.
.
def related(self)
"Returns the topics with similar starting names"
return self._default_manager.filter(name__startswith=self.name)
topic.related() #topic 'Milan wins' is related to:
# ['Milan wins','Milan wins championship', 'Milan wins by one goal', ...]
Could also be caused by a pair of parantheses too much, e.g.
ModelClass().objects.filter(...)
instead of the correct
ModelClass.objects.filter(...)
Happens to me sometimes when bpython (or an IDE) automatically adds parantheses.
The result, of course, is the same - you have an instance instead of a class.
if topic were a ContentType instance (which it is not), this would have worked:
topic.model_class().objects.filter(forum = forum)
I just had an issue similar to this error. And looking back at your code it seems that it could be your issue too. I think your issue is that your comparing "id" to "int(topic_id)" and topic_id is not set.
def test(request, post_id):
post = topic.objects.get(id = int(topic_id))
post.delete()
I'm guessing your code should use "post_id" not "topic_id"
def test(request, post_id):
post = topic.objects.get(id = int(post_id))
post.delete()
I got the same error below:
AttributeError: Manager isn't accessible via CustomUser instances
When I accessed Manager with request.user.objects as shown below:
"views.py"
from django.http import HttpResponse
def test(request):
print(request.user.objects)
return HttpResponse("Test")

Query strange behaviour. Google App Engine datastore

I have a model like this:
class Group(db.Model):
name = db.StringProperty()
description = db.TextProperty()
Sometimes when executing queries like:
groups = Group.all().order("name").fetch(20)
or
groups = Group.all()
I'm getting error massages like this:
Traceback (most recent call last):
File "/opt/google_appengine/google/appengine/ext/webapp/__init__.py", line 501, in __call__
handler.get(*groups)
File "/home/al/Desktop/p/mwr-dev/main.py", line 638, in get
groups = Group.all()
AttributeError: type object 'Group' has no attribute 'all'
But when I'm using GQL queries with the same meaning, everything goes fine.
Why does that happens? I'm don't getting why GAE thinks that 'all' is attribute?
UPDATE:
Oops ... I've found out that I also had request handler named the same as model ;(
all is indeed an attribute (specifically an executable one, a method) but as Group inherits from Model it should have that attribute; clearly something strange is going on, for example the name Group at the point does not refer to the object you think it does. I suggest putting a try / except AttributeError, e: around your groups = Group.all() call, and in the except branch emit (e.g. by logging) all possible information you can find about Group, including what __bases__ it actually has, its dir(), and so forth.
This is about how far one can go in trying to help you (diagnosing that something very weird must have happened to the name Group and suggesting how to pinpoint details) without seeing your many hundreds of lines of code that could be doing who-knows-what to that name!-).

Categories