It is good practice to get all object in RetrieveUpdateDestroy Method? - django

Why we need to get all object in RetrieveUpdateDestroy Method?
In real project can I do it just like this Without fear even if there is large data?

Why [do] we need to get all object[s] in [a] RetrieveUpdateDestroy [view]?
We don't: the queryset is not evaluated. This is only used as a "parent" queryset to make querysets to retrieve, update, and delete a single object.
Indeed, for a retrieve method, it will add .get(pk=some_pk) at the end, and thus make a query to retrieve that single object.
The queryset can be used to filter certain items, to prevent retrieving, updating and removing certain objects for example. You can for example use queryset = Student.objects.filter(active=True) to only be able to retrieve active Students.

Related

Debugging QuerySets in Django

When in debug mode and looking at a QuerySet that did return results, how / where can I see the objects in the debugger? I am not interested in the code to evaluate (e.g. Class.objects.all() etc, but more like the structure, e.g.:
- QuerySet
-- object_list
--- object[0]
--- object[1]
--- object[n]
Thanks!
EDIT:
Let's say I am looking at a QuerySet in the debugger, I am getting a bunch of attributes and related objects, but I cannot seem to find the actual objects that I am after. If I have a class A and I am executing qs = A.objects.get.all() and I am looking at the structure of qs in the debugger, I am getting a bunch of different items but cannot find the actual objects / instances of A.
EDIT(2):
From the documentation,
Internally, a QuerySet can be constructed, filtered, sliced, and generally passed around without actually hitting the database. No database activity actually occurs until you do something to evaluate the queryset.
Which means, wheever you call Class.objects.all(), it won't fetch the actual instances from DB (just like generators in Python)
to evaluate all objects, do something like this,
all_instance = [i for i in Class.objects.all()]
The above method is not recomended for your production/live code, because it's too ugly to store all instance in a list
Suppose the best way is to add to watches list(Class.objects.all())

How to modify a queryset and save it as new objects?

I need to query for a set of objects for a particular Model, change a single attribute/column ("account"), and then save the entire queryset's objects as new objects/rows. In other words, I want to duplicate the objects, with a single attribute ("account") changed on the duplicates. I'm basically creating a new account and then going through each model and copying a previous account's objects to the new account, so I'll be doing this repeatedly, with different models, probably using django shell. How should I approach this? Can it be done at the queryset level or do I need to loop through all the objects?
i.e.,
MyModel.objects.filter(account="acct_1")
# Now I need to set account = "acct_2" for the entire queryset,
# and save as new rows in the database
From the docs:
If the object’s primary key attribute is not set, or if it’s set but a
record doesn’t exist, Django executes an INSERT.
So if you set the id or pk to None it should work, but I've seen conflicting responses to this solution on SO: Duplicating model instances and their related objects in Django / Algorithm for recusrively duplicating an object
This solution should work (thanks #JoshSmeaton for the fix):
models = MyModel.objects.filter(account="acct_1")
for model in models:
model.id = None
model.account = "acct_2"
model.save()
I think in my case, I have a OneToOneField on the model that I'm testing on, so it makes sense that my test wouldn't work with this basic solution. But, I believe it should work, so long as you take care of OneToOneField's.

django queryset ordering

I'm listing queryset results and would like to add an option for choosing the order results are displayed.
I would like to pass the actual data from the database to other page for sorting.
I was able to achieve such thing by getting all objects ids and use django session to recreate a new queryset based on the order criteria.
I was thinking if there is any other way to achieve such goal?
10x
Assuming you are currently displaying the data as a table, you could give chance to some javascript client side table sorter such as tablesorter. There are lots of javascript table sorte.
I'm away from my development machine right now, but I think you could just pass the list of ids to a new Queryset, pk__in=list_of_object_ids, and then use the native order_by function.
For example:
objs = Object.objects.filter(pk__in=list_of_object_ids).order_by('value_to_order_by')
Anyway, that's what I would try first, though I'm sure there are better optimizations.
For example, instead of a list of object ids, you could pass a dictionary with a key:value pair that has the value you want to order by.
For example:
[{'obj_id':1,'obj_value':'foo'},{'obj_id':2,'obj_value':'foo'}]
Then use some lambda function to sort it, like here.

Passing limited queryset to related_to() in django-tagging

I want to use the related_to() function in django-tagging and I am passing a queryset looking like this:
Chapter.objects.all().order_by('?')[:5] #the important thing here is the "[:5]"
My problem is that this function apparently uses the in_bunk() function and you Cannot use 'limit' or 'offset' with in_bulk
How can I restrict my queryset to only pass 5 objects and at the same time make use of in_bunk?
I know that related_to() lets you pass the variable num (which is the number of objects it should return) but I don't want it to output the same queryset every single time. So i came up with the idea of ordering it randomly and limiting it before it was passed to the function. But as you can see: limited querysets and bunk_it doesn't go hand in hand very well.
I found a solution though it wasn't the best and though it processes unnecessary data. I simply run through all instances of the model related to the current instance and I then sort randomly and slice afterwards:
related_objects = instance.related_to(Model) # all related objects are found
related_objects = random.sample(related_objects,5) # .. and afterwards sorted randomly and sliced

Django - How to annotate QuerySet using multiple field values?

I have a model called "Story" that has two integer fields called "views" and "votes". When I retrieve all the Story objects I would like to annotate the returned QuerySet with a "ranking" field that is simply "views"/"votes". Then I would like to sort the QuerySet by "ranking". Something along the lines of...
Story.objects.annotate( ranking=CalcRanking('views','votes') ).sort_by(ranking)
How can I do this in Django? Or should it be done after the QuerySet is retrieved in Python (like creating a list that contains the ranking for each object in the QuerySet)?
Thanks!
PS: In my actual program, the ranking calculation isn't as simple as above and depends on other filters to the initial QuerySet, so I can't store it as another field in the Story model.
In Django, the things you can pass to annotate (and aggregate) must be subclasses of django.db.models.aggregates.Aggregate. You can't just pass arbitrary Python objects to it, since the aggregation/annotation actually happens inside the database (that's the whole point of aggregate and annotate). Note that writing custom aggregations is not supported in Django (there is no documentation for it). All information available on it is this minimal source code: https://code.djangoproject.com/browser/django/trunk/django/db/models/aggregates.py
This means you either have to store the calculations in the database somehow, figure out how the aggregation API works or use raw sql (raw method on the Manager) to do what you do.