Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Django Queryset API Is Enough.
Chidozie C. Okafor
Chidozie C. Okafor

Posted on

     

Django Queryset API Is Enough.

Let's Explore Django Queryset API indepth.


Making efficient database queries is one of the most important skill of any backend operation. Queries can either make your application or destroy it. Optimising your application from the backend lies on writing efficient algorithms. Django developers had taken enough time writing these complex algorithms for other developers to reuse. If you are curious like me to find out what is happening. You should explore the django project on Github.

Today, We will be focusing on Django based application and how we can leverage the built-in queryset API to speed up not just the development time but your application response time.

Our Models

fromdjango.dbimportmodelsfromdjango.confimportsettingsclassBaseModel(models.Model):created_at=models.DateTimeField(auto_now_add=True)modified_at=models.DateTimeField(auto_now=True)user=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)classMeta:abstract=TrueclassInvestment(BaseModel):title=models.CharField(max_length=200)interest=models.DecimalField(decimal_places=2,max_digits=4)min_invest=models.DecimalField(decimal_places=2,max_digits=8)max_invest=models.DecimalField(decimal_places=2,max_digits=8)duration=models.DurationField()active=models.BooleanField(default=False)def__str__(self)->str:returnself.titleclassMeta:verbose_name_plural="Investment"ordering="-created_at"classUserInvest(BaseModel):amount=models.DecimalField(max_digits=4,decimal_places=2)package=models.ForeignKey(Investment,on_delete=models.PROTECT)started=models.BooleanField(default=False)def__str__(self)->str:returnf"{self.user.username} invested{self.amount} in{self.package.title)package"''' other methods for comes in. I love writing fat models because it makes my work easy and makes the application code to have one source of truth Note:Youshouldalwaysusedjango.utils.translationfortranslation.'''
Enter fullscreen modeExit fullscreen mode

Our Views

This is where the fun begins. we will touch every part of queryset api showing you more complex methods to query your database.

Get all queries in reverse order.

'''We will make database queries through our models.Note: we assume that we have enough data in our database to work with.'''fromdjango.views.genericimportListViewfromdjango.db.models.queryimportQfrommyapp.investment.modelsimportInvestment,UserInvestclassInvestmentListView(ListView):template_name="investment/investment_list.html"model=Investmentcontext_object_name="investment"defget_queryet(self,**kwargs):returnsuper().get_queryset(self,kwargs).order_by("-created_at")
Enter fullscreen modeExit fullscreen mode

The query above list out all the investment package that the company have starting from the latest. Django have provided an efficient way that is optimised. instead of using the built in python methods, django provide a good api to optimise such query.

Note: Don't use python built in methods if django have provided an alternative. instead of reverse(queries) use
queries.order_by() function or pass in the ordering keywords with the model Meta Class.

#You can pass in the ordering keywords with the model to re-order your data. likeclassMeta:ordering="-created_at"# OR usedefget_querset(self,**kwargs):returnsuper().get_queryset(self,kwargs).order_by("-created_at")
Enter fullscreen modeExit fullscreen mode

Alternatives to common queries

instead of using this to check if objects exists.

forinvestmentinInvestment.objects.all():ifinvestment.title=="UBA stock":\print(f"investment.title exists")
Enter fullscreen modeExit fullscreen mode

Do This

Investment.objects.filter(title="UBA stock").exist()
Enter fullscreen modeExit fullscreen mode

To count objects use

Investment.objects.count()
Enter fullscreen modeExit fullscreen mode

To Select to first/last few elements use slicing

Investment.objects.all()[:5]
Enter fullscreen modeExit fullscreen mode

To use Conditions in getting objects, try filtering by such condition,

fromdjango.db.model.queryimportQInvestment.objects.filter(active=True,created_at__month=datetime.datetime.now().month)## complex queries use Q objectsinvest=Q(Investment.objects.filter(active=True)|Investment.objects.filter(completed=True))
Enter fullscreen modeExit fullscreen mode

To Exclude some objects with certain conditions, try this

Investment.objects.exclude(created_at__gt=datetime.date(2022,6,2),title='Morgan Stock')
Enter fullscreen modeExit fullscreen mode

NB: You can chain these individual queries to perform a more complex queries

To reverse queries

Investment.objects.reverse()
Enter fullscreen modeExit fullscreen mode

To get queries that have distinct values

Investment.objects.order_by('created_at').distinct('created_at')
Enter fullscreen modeExit fullscreen mode

To query on values

Investment.objects.filter(title__istartswith="UBA")Investment.objects.filter(title__iendswith="stock")Investment.objects.filter(title__icontains="stock")## These are case sensitive operations, so i prefer using i to prefix the startswith or endswith
Enter fullscreen modeExit fullscreen mode

What of dates

>>>Investment.objects.dates('created_at','year')[datetime.date(2022,1,1)]>>>Investment.objects.dates('created_at','month')[datetime.date(2022,2,1),datetime.date(2022,3,1)]>>>Investment.objects.dates('created_at','week')[datetime.date(2022,2,14),datetime.date(2022,3,14)]>>>Investment.objects.dates('created_at','day')[datetime.date(2022,2,20),datetime.date(2022,3,20)]>>>Investment.objects.dates('created_at','day',order='DESC')[datetime.date(2022,3,20),datetime.date(2022,2,20)]>>>Investment.objects.filter(title__contains='UBA').dates('pub_date','day')[datetime.date(2022,3,20)]
Enter fullscreen modeExit fullscreen mode

If you want to combine multiple distinct queries use union

invest1=Investment.objects.filter(active=True)invest2=Investment.objects.filter(completed=True)invest3=Investment.objects.filter(active=False)invest=invest1.union(invest2)invest4=invest1.union(invest2,invest3)
Enter fullscreen modeExit fullscreen mode

To get the intersection of 2 queries use

invest1=Investment.objects.filter(active=True)invest2=Investment.objects.filter(completed=True)invest3=Investment.objects.filter(active=False)invest=invest1.intersection(invest2)
Enter fullscreen modeExit fullscreen mode

To get the difference of 2 queries use

invest1=Investment.objects.filter(active=True)invest2=Investment.objects.filter(completed=True)invest3=Investment.objects.filter(active=False)invest=invest1.difference(invest2)
Enter fullscreen modeExit fullscreen mode

If you have objects that has relationships and you don't want multiple database queries to get the relationships, use select_related or prefetch_related function

UserInvest.objects.select_related("package").get(id="7")UserInvest.objects.filter(amount__gte=200).prefetch_related("package")UserInvest.objects.filter(amount__gte=200).select_related("package")
Enter fullscreen modeExit fullscreen mode

There are lots of things going on while using select_related or prefetch related. I suggest you look atdjango docs and understand deeply how they both perform their queries.

Instead of writing raw queries using cursor objects, use django select and extra function

Investment.objects.extra(select={'is_recent':"created_at >'2022-01-01'"})UserInvest.objects.extra(select={'entry_count':'SELECT COUNT(*) FROM userinvest_entry WHERE userinvest_entry.userinvest_id = userinvest_userinvest.id'},)## This query might not make much sense, but it shows what is possible.
Enter fullscreen modeExit fullscreen mode

In some complex data-modeling situations, your models might contain a lot of fields, some of which could contain a lot of data (for example, text fields), or require expensive processing to convert them to Python objects. If you are using the results of a queryset in some situation where you don’t know if you need those particular fields when you initially fetch the data, you can tell Django not to retrieve them from the database. use defer in this case

UserInvest.objects.defer("package")
Enter fullscreen modeExit fullscreen mode

If you want to defer all other fields except some, use only.

Investment.objects.only("title","duration").only("user")
Enter fullscreen modeExit fullscreen mode

If you are connected to multiple databases and wanted to use a specific database, Use using to specify the database.

Investment.objects.using('backup')
Enter fullscreen modeExit fullscreen mode

To first or last query

p=Investment.objects.order_by('title','created_at').first()q=Investment.objects.order_by('title','created_at').last()
Enter fullscreen modeExit fullscreen mode

To count or sum a field, use aggregate and Sum function

fromdjango.db.models.aggregatesimportSum,Countq=Investment.objects.aggregate(Count('title'))total_amount=UserInvest.objects.aggregate(Sum("amount"))
Enter fullscreen modeExit fullscreen mode

Django provides lots of api to make highly optimised queries. All you need to do isread the doc

Happy Coding!!!

Top comments(1)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
say_whaaaaaattt profile image
Hypertext
  • Education
    Bs
  • Work
    Backend developer
  • Joined

good tips..

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Software Engineer & Backend Magician 🎩 | Python, TypeScript, Node.js & Golang | Conjuring Microservices, Apache Kafka & Scalable Solutions | Empowering Organizations with a Touch of Code Sorcery 🧙‍♂️✨
  • Location
    Regensburg Germany
  • Education
    University Of Benin
  • Pronouns
    Mr
  • Work
    Backend Engineer @ ProPro Productions
  • Joined

More fromChidozie C. Okafor

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp