Django ORM: wrapper for model objects - python

I am looking for some way to define some wrapper that is called before i call to Model.objects.all().
I want whenever i call, Model.objects it call my method (wrapper) and then return the objects back to the query.
Lets take an example:
MyModel.objcts.filter(name="Jack")
Wrapper:
def mymodelWrapper(self):
return self.objects.annotate(size=Sum('id', field='order_size_weight*requested_selling_price'))
I want to run annotate in the background and also want to apply the filter.
I Know what i want to achieve, its the code i am looking for how to do that.

What you are talking about is perfectly doable with Django by using a custom model manager:
class MyModelManager(models.Manager):
def get_query_set(self):
return super(MyModelManager, self).get_query_set().annotate(size=Sum('id', field='order_size_weight*requested_selling_price'))
class MyModel(models.Model):
objects = MyModelManager()
# fields
Also see other similar topics:
Is it possible to override .objects on a django model?
Override djangos's object.all() with the request data
Django custom model managers

Related

Django manager queries don't work in a chain of queries. AttributeError: 'QuerySet' object has no attribute <the manager method>

Problem: I've implemented a custom manager for a model with just one custom query set named get_by_tag and it's working fine if I use it this way:
ViewStatistic.objects.get_by_tag('some-tag-name').filter(user=user_id)
But when I change the order of queries, in this way:
ViewStatistic.objects.filter(user=user_id).get_by_tag('some-tag-name')
it doesn't work! and raises this error:
AttributeError: 'QuerySet' object has no attribute 'get_by_tag'
Am I missing something?! How can I do this in such a order?
P.S: The custom manager is something like this:
class MyCustomManager(models.Manager):
def get_by_tag(self, tag_name):
posts = Post.objects.filter(tags__pk=tag_name)
return super().get_queryset().filter(post__pk__in=posts)
If you want to use your queryset methods inside of queryset chain and not only directly after the manager, you should define them as methods of custom QuerySet class that you connect to a manager.
Two solutions are described in Django documentation Creating a manager with QuerySet methods.
Common part - a custom QuerySet class with queryset methods
class MyCustomQuerySet(models.QuerySet):
def get_by_tag(self, tag_name):
return self.filter(post__pk__in=Post.objects.filter(tags__pk=tag_name))
# more possible queryset methods ...
A) if your manager has only queryset methods and no other custom methods
    then you can create it simply from the QuerySet.
class MyModel(models.Model):
objects = MyCustomQuerySet.as_manager()
B) if your manager need also other methods that do not return a queryset:
class MyCustomManager(models.Manager):
... # other methods
class MyModel(models.Model):
objects = MyCustomManager.from_queryset(MyCustomQuerySet)()
When you say ViewStatistic.objects it returns the object of <django.db.models.manager.Manager>
In your case since it have derived class MyCustomManager having base class models.manager, so it return object of <your_app.models.MyCustomManager> which have get_by_tag function, and you can access get_by_tag.
For second case ViewStatistic.objects.filter return django.db.models.query.QuerySet object and ofcourse it hasn't no method named get_by_tag that's why you get AttributeError.
One more point related to queryset is
The result of refining a QuerySet is itself a QuerySet, so it’s possible to chain refinements together.
https://docs.djangoproject.com/en/3.0/topics/db/queries/#chaining-filters
In your case get_by_tag return QuerySet further you performed .filter() operation, which is fine.
The django official documentation link can be followed related to models Manager and query for more details.
https://docs.djangoproject.com/en/3.0/topics/db/queries/

Django: Override user queryset to filter out admin/staff users from the public?

I want to filter the user manager self.get_queryset() method in such a way that users on the client application don't see admin and staff users when searching for or viewing other accounts. The issue I'm running into is I am unable to login with my auth system if I override get_queryset entirely. My current setup is:
class AccountManager(BaseUserManager):
def get_public_queryset(self):
return self.get_queryset().filter(active=True, verified=True, admin=False, staff=False)
Using this design works fine if I define various sorting methods in the manager (because I can simply call that method), but it seems as though there should be a better way to do this. Any ideas?
I think additional methods, as you've implemented is good a solution, but if you insist using get_queryset method it would be fine to override the method and preserve base functionality. I'd do something like this:
...
def get_queryset(self, *a, **kw):
queryset = super().get_queryset(*a, **kw)
# filter your queryset here as you wish
queryset = queryset.filter(active=True, verified=True, admin=False, staff=False)
return queryset
...
As I've spotted from question text, you tried to call self.get_queryset() which would be recursive call (not super class implementation call), which will finally cause maximum recursion depth exceeded error.
Hope it helps

create custom methods in django class base views

I want to use generic class base views using django 1.9
What i am trying to understand that
from django.views.generic import CreateView
from braces.views import LoginRequiredMixin
from .models import Invoice
class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
...
return invoice
now i want to bind this custom method to url. How can i achive this?
I know using function base view its simple but i want to do this using class base views.
Help will be appreciated.
Yes, this is the main issue to grasp in CBV: when things run, what is the order of execution (see http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/).
In a nutshell, every class based view has an order of running things, each with it's own method.
CBV have a dedicated method for each step of execution.
You would call your custom method from the method that runs the step where you want to call your custom method from. If you, say, want to run your method after the view found that the form is valid, you do something like this:
Class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
... do something with self.object
return invoice
def form_valid(self,form):
self.object = form.save()
self.generate_invoice()
return super(InvoiceCreateView,self).form_valid(form)
So you have to decide where your custom method should run, and define your own method on top of the view generic method for this step.
How do you know what generic method is used for each step of executing the view? That the method the view calls when it gets the initial data for the form is def get_initial? From the django docs, and https://ccbv.co.uk/.
It looks complex, but you actually have to write very few methods, just where you need to add your own behaviour.

django: where to put recurring query on list of model objects

I have Product as a model.
I am refactoring some code, and there is a recurring query spread all over the code base which needs replacement.
So I'd like to centralize this query, in order to encapsulate its logic.
I'd like something like
<an_object>.get_uncompleted_products(products);
In this case, preserving existing code, products is already a result of a query (products = Products.objects.filter(filter_expression))
This is just a convenience question, I know a possible answer, but where would you put get_uncompleted_products(), what could be a good"django-way" solution?
I was initially wanting to put it on the Product model. But I was thinking Product methods to work directly on a single model reference, thus the signature would need to be:
class Product(models.Model):
#classmethod
get_uncompleted_products(list)
I am not sure why this gives me the feeling to be not so appropriate. A possible alternative would be to put it into a utility module. I could also have it in the view module but it seems it's used profusely in other views as well so I'd prefer somewhere more generic.
I guess the 'django way' would be to define it as a custom manager method, instead of class method, which can be shared between different models with composition instead of inheritance in case of class methods.
from django.db import models
class ProductQuerySet(models.query.QuerySet):
def get_uncompleted_products(self):
...
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQueryset(self.model, using=self._db)
def get_uncompleted_products(self):
# defined twice to resolve queryset chaining issue with custom managers
return self.get_queryset().get_uncompleted_products()
class Product(models.Model):
...
objects = ProductManager()

Is it possible to override .objects on a django model?

I'd like to by default only return "published" instances (published=True). Is it possible to override .objects so that MyModel.objects.all() actually returns MyModel.objects.filter(published=True)?
Is this sensible? How would I get the unpublished ones in the rare cases where I did want them?
You can do this by writing a custom Manager -- just override the get_queryset method and set your objects to a Manager instance. For example:
class MyModelManager(models.Manager):
def get_queryset(self):
return super(MyModelManager, self).get_queryset().filter(published=True)
class MyModel(models.Model):
# fields
# ...
objects = MyModelManager()
See the docs for details. It's sensible if that's going to be your usual, default case. To get unpublished, create another manager which you can access with something like MyModel.unpublished_objects. Again, the docs have examples on this type of thing.

Categories