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.
Related
I am trying to retrieve different .values() from query sets but am having an issue with it returning the proper values. How to write my model so that I can retrieve attributes using the .values() method?
I have tried to change the model's __str__ method to return a dictionary but that does not work or I am doing it wrong.
class Settings(models.Model):
bb_bonus_qualify = models.CharField(max_length=16, default=38.00)
service_breakpoint = models.CharField(max_length=16, default=1700.00)
def __str__(self):
return '%s: %s, %s: %s' % (
'bb_bonus', self.bb_bonus_qualify, 'service_breakpoint', self.service_breakpoint)
I would like to say Settings.objects.last().values('bb_bonus') and be returned the value which is self.bb_bonus_qualify. The common error I seem to get is: AttributeError: 'Settings' object has no attribute 'values'
The problem here is that your .last() will retrieve the last Settings object. You thus will call .values('bb_bonus') on the Settings object. Since a model has no .values(..) method, it will thus not return anything.
You can however retrieve the value of a certain column from a queryset, with:
Settings.objects.values_list('bb_bonus_qualify', flat=True).last()
We here thus use .values_list(..) [Django-doc], this accepts the names of the columns as parameters. It will then usually return a QuerySet of lists with these values. But if you specify one column; then, as the documentation says:
If you only pass in a single field, you can also pass in the flat parameter. If True, this will mean the returned results are single values, rather than one-tuples.
So that means we create a QuerySet of singular values, and we then will retrieve the last entry of that queryset. Note that we do not fetch all the elements from the queryset, the .last() is "injected" in the query we perform on the database, so the result is the scalar value of that column for the last record.
The .values_list(..) thus needs to be performed before the .last(), since otherwise you are talking to a Settings object, not to a QuerySet.
AFAIK __str__ has nothing to do with .values() - the problem here is that you need to specify the values before getting a specific item, rather than the other way round:
Settings.objects.values('bb_bonus').last()
AM using Django v1.11
I have the following models:
class LineItem():
quote = models.ForeignKey(Quote, related_name="quote_line_items")
sku = models.ForeignKey(SKU)
class Quote():
def fetch_as_list_of_dict(self):
return LineItem.objects.filter(quote=self).select_related('sku__product').values()
class SKU():
product = models.ForeignKey(Product)
My fetch_as_list_of_dict fails to contain the sku.product_id or sku.product object. I only need to get the sku.product_id as part of a dictionary which in itself is one of many in a list.
How do I achieve this?
You can simply do it by:
def fetch_as_list_of_dict(self):
return self.listitem_set.select_related('sku__product').values('sku__product') # or any fields like sku__product__name, sku__product__id anything
Please check related object documentation for more details on fetching related object.
The code seems correct, there's one thing you can do -
Change self to self.pk as below
def fetch_as_list_of_dict(self):
return LineItem.objects.filter(quote=self.pk).select_related('sku__product').values()
Second way -
Try to get SKU object only first.
def fetch_as_list_of_dict(self):
return LineItem.objects.filter(quote=self).select_related('sku__product')
I'm building a news website. While I tried to get the list of relative news which have the same tags. The error said:
The QuerySet value for an exact lookup must be limited to one result using slicing.
I have two models News and Tag. Tag is a many-to-many foreign key of News.
# "models.py"
class Tag(models.Model):
name = models.CharField(max_length=40)
class News(models.Model):
tag = models.ManyToManyField(Tag, blank=True, verbose_name='tag')
View:
def newsDetailView(request, news_pk):
news = get_object_or_404(News, id=news_pk)
tags = news.tag.annotate(news_count=Count('news'))
relative_news = News.objects.filter(tag=tags)
return render(request, "news_detail.html", {
'news': news,
'tags': tags,
'relative_news': relative_news
})
The following will work:
def newsDetailView(request, news_pk):
news = get_object_or_404(News, id=news_pk)
relative_news = News.objects.filter(tag__id__in=news.tag.all())
Generally this error occurs when we use model queryset at the place of django models object. In the given question you have done the same. "Objects.filter" returns the model query set there can be single or multiple django model objects, but "objects.get" returns single django model object. Or we can use .last() and .first() with "objects.filter".
this error rises if you use queryset or list in your filter params. For example,
News.objects.filter(title = a)
and here if "a" inside a filter is a queryset or list, then this error raises.
The problem you are facing is that you first take a filter queryset (a collection of objects from your database) for example: Book.objects.filter(subject='fiction') )
and then you are trying to use that filter as a parameter (like subject = 'fiction' in the previous one ) to obtain another filter queryset.
Instead you have to use an object using 'get' instead of 'filter' that is the previous example would become
book = Book.objects.get(subject='fiction')
and then use that object as parameter for next filter.
example: Book_shelf = BookShelf.objects.filter(book = book)
I also experienced the same issue, try doing this, instead of:
relative_news = News.objects.filter(tag=tags)
to
relative_news = News.objects.filter(tag=tags).first()
I got the same error below:
ValueError: The QuerySet value for an exact lookup must be limited to
one result using slicing.
Because I assigned the queryset made by filter() to category as shown below:
# Here # Here
Product.objects.filter(category=Category.objects.filter(pk=1))
So, I put __in after category as shown below, then the error was solved:
# ↓ Here
Product.objects.filter(category__in=Category.objects.filter(pk=1))
Or, I assigned the object made by get() to category as shown below, then the error was solved:
# Here
Product.objects.filter(category=Category.objects.get(pk=1))
I have to query an object from a model, this object is called "exercise" and has many fields(title, body, answers, etc.) I need to get "exercise objects" one by one with all their fields, do some rendering on them and give back a pdf of the exercise as result.
The problem is, if I do:
exercises = ExerciseModel.objects.all()
I get all of them. If I do:
some_exercises = ExerciseModel.objects.filter(something=something)
I get "some of them" depending on filter. And if i do:
exercise = ExerciseModel.objects.get()
I get
error get() returned more than one exercise
How can I get them one by one? I must be able to use them as input for another function.
If you need to perform the task on only 1 exercise, use get() instead. In such case, you need a criteria to make sure get() will return 1 and only 1 result.
Example:
ex = ExerciseModel.objects.get(pk=123)
From the doc:
Returns the object matching the given lookup parameters, which should be in the format described in Field lookups.
get() raises MultipleObjectsReturned if more than one object was found. The MultipleObjectsReturned exception is an attribute of the model class.
get() raises a DoesNotExist exception if an object wasn’t found for the given parameters. This exception is an attribute of the model class.
When you have a QuerySet with filters that ensure the underlying SQL request will return only 1 row, you can call get() without argument on the QuerySet. This return the row as model instance, instead of returning it as a list containing 1 elemnt.
Original answer:
Both filter() and all() methods return a QuerySet instance. You can iterate on it to perform a task for each "exercise" returned by your request
for exercise in ExerciseModel.objects.filter(something=something):
# ... do what you need on your exercise
From the documentation:
A QuerySet is iterable, and it executes its database query the first time you iterate over it. For example, this will print the headline of all entries in the database
What you need is .iterator() which will turn a queryset to an iterator:
exercises = ExerciseModel.objects.all().iterator()
then you get iterate over it in a for loop:
for exercise in exercises:
...
This will improve performance when you have large number of items. However, it has some downsides as well as stated in the docs
Hope it helps!
.get() must return a single object, not a QuerySet instance. If you want to get a single exercise then you must pass a parameter to the .get instance. For example, retrieving an object by name would require the following code:
exercise = ExerciseModel.objects.get(name="an_exercise")
If you want to iterate through all the objects without actually retrieving a QuerySet containing the objects, you could use the following code:
for i in range(Exercise.objects.all().count()):
exercise = Exercise.objects.get(pk=i)
... operate on object ...
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.