Django Get and Filter - django

I have a design question on django.
Can someone explain to me why the Django ORM 'get' doesn't return a queryset?
To the best of my understanding, a queryset should/is the result of a db query. With that logic, isn't a get query a queryset?
Also, from my research towards this question, I found out the get query calls the model manager while the queryset doesn't.
Is there a reasoning behind all of this?

From django documentation queryset api reference
get() raises MultipleObjectsReturned if more than one object was found. The MultipleObjectsReturned exception is an attribute of the model class.
While filter returns a set of instances that match the lookups kwargs in an instance of QuerySet
For example:
A=Model.objects.get(id=1)
B=Model.objects.filter(id=1)
print(isinstance(A,Model)) # True
print(isinstance(B,QuerySet)) # True
Get sql >>
select * from public.app_model where id=1;
Filter sql >>
select * from public.app_model where id=1;
but at implementation get must return an instance, if the query returns more than 1 row it will raise MultipleObjectsReturned yet filter not, it will return all the rows in Model class instance form
BTW, Both use the cache property

Related

How do I check for the existence of a specific record in Django?

If I retrieve a QuerySet from a Django model (using filter(), for example), I can use the QuerySet methods exists() or count() to determine if the result will be void or not:
if myModel.objects.filter(id__lte=100).exists():
# Do something...
However, if I want to retrieve a specific record (using get(), for example)
myModel.objects.get(id=100)
the record object returned has no exists() or count() method. Moreover, if this record doesn't exist, instead of doing the expected thing and returning None, Django flips its crap entirely and breaks with a DoesNotExist exception, so I can't even test for the record's existence in the normal Pythonic way:
# This throws a DoesNotExist exception
if not myModel.objects.get(id=100):
# Do something else...
How do I test for the existence of a specific record (an element of a QuerySet, not a QuerySet itself) so that the app doesn't break?
(Django 3.0)
you can try this way
try:
instance = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
print "Not Found"
else:
#Do your stuff
OR
MyModel.objects.filter(id=1).exists()
You can use .filter. It will scan the database and if the object is present, it will return a Queryset and if not the length of Queryset will be none.
myModel.objects.filter(id=100)
You can find about filters here:
https://docs.djangoproject.com/en/3.0/topics/db/queries/

Why does get and filter work differently for annotated fields?

I have a get_queryset in a custom Manager for a Model that renames fields:
class Manager:
def get_queryset(self):
return super(Manager, self).get_queryset().values(renamed_field=F('original_field'))
Why is it that I can do a .filter on the renamed field but when I do a .get I need to use the original field name?
This works:
Model.objects.filter(renamed_field='Test')
But this errors out with matching query does not exist:
Model.objects.get(renamed_field='Test')
From the docs about Querysets:
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.
When you call the get method, you hit the database. This explains why you get the error about no matching query.

How to filter a query set with the results of another query set in Django?

Right now I have a Django queryset that I want to filter by the result of another query set. Right now I am doing this as (and it works):
field = 'content_object__pk'
values = other_queryset.values_list(field, flat=True)
objects = queryset.filter(pk__in=values)
where the field is the name of a foreign key the pk in queryset. The ORM is smart enough to run the above is one query.
I was trying to simplify this to (ie to filter with the object list themselves rather than having to explicitly say pk):
field = 'content_object'
objects = queryset & other_queryset.values_list(field, flat=True)
but this gives the following error:
AssertionError: Cannot combine queries on two different base models.
What is the right way to do this type of filtering?
You can do the next:
result = MyModel.objects.filter(field__in=other_query)
The results will be the objects in the model where the field is a foreign key to the model in the other_query
you can chain queries in Django...
qs = entry.objects.filter(...).filter(...)

How does one filter a query set in django

Suppose you have a query set in Django how does one filter it, given that
queryset.objects.filter(condition)
doesn't work?
You should be able to do queryset = queryset.filter(condition) See the QuerySet API

Django how to delete from ManyToManyField with extra field?

In my django app I have models set up similar to these models on the django site - Extra fields on many-to-many relationships. Further down the page, I read
The remove() method is disabled for similar reasons. However, the clear() method can be used to remove all many-to-many relationships for an instance:
If the remove method is disabled then how do I remove an object from a manytomany field? It says that I can use the clear method to remove everything but I only want to remove one specific element from the manytomany field.
You can remove the instance on the intermediary model.
From the example provided in djangoproject:
m_qs = Membership.objects.filter(person=person, group=group) #or some other logic to filter
try:
m = m_qs.get() #assuming queryset returns only 1 element
m.delete()
except:
pass #handle more gracefully