# Top 5 ORM tips to write high quality Django apps.

# Introduction

Django is a robust framework, it is used by companies like Disqus, Instagram, Pinterest, Bitbucket, etc.

Let's have a quick look at some of the things that can scale your application easily and help you improve performance.


## Tip #1
 - Using class property decorator `@property` to store the dynamically calculated values for a model, instead of storing it in a column. Using property, you do not have to call the model method using `()`:

```python
class User(models.Model):
	first_name = models.CharField(max_length=100)
	last_name = models.CharField(max_length=100)
	...

	@property
	def full_name(self):
		return f"{first_name} {last_name}"

user = User.objects.first()
print(user.full_name) # This will work perfectly
```

## Tip #2
 - Use `@cached_property` instead of just `@property` decorator for Model methods to cache the dynamically calculated value in memory. You have to import it first:

```python
from django.utils.functional import cached_property

class User(models.Model):
	first_name = models.CharField(max_length=100)
	last_name = models.CharField(max_length=100)
	...
	
	@cached_property
	def full_name(self):
		# The returned value will be cached
		return f"{first_name} {last_name}"

user = User.objects.first()
print(user.full_name) # This will work perfectly
```

## Tip #3
 - Use `Q` objects for `AND`, `OR` & `NOT` SQL queries:

```python
from django.db.models import Q

# For OR conditions
queryset = User.objects.filter(
    Q(first_name__startswith='G') | Q(last_name__startswith='S')
)

# For AND conditions
queryset = User.objects.filter(
    Q(first_name__startswith='G') & Q(last_name__startswith='S')
)

# For NOT Queries
queryset = User.objects.filter(~Q(first_name='Gaurav'))
```

## Tip #4
 - Use `select_related`, `prefetch_related` for SQL join operations instead of running multiple queries to get data from related tables.

    So basically, whenever you try to access the ***foreign*** key values from a table to another table, Django will perform those queries smartly in an efficient way.

   `select_related` is used with `ForeignKey` & `OneToOneField` field values, on the other hand, `prefetch_related` is used with `ManyToManyField` in Django.

    There is simple psychology behind these two ORM methods, ***Retrieve everything at once if you know you will need it.***

## Tip #5
 - Use **`bulk_create`**, **`bulk_update`** for the creation and updation of many rows at once.

   When you run an SQL query, it opens a Database connection, and Opening a database connection is an expensive operation. You have to open up network sessions, authenticate, have authorization checked, and so on.

   So if you have hundreds/thousands of records to store in Database, do not use for loop with ORM to perform the creation & Delivery operation.

    Instead we have bulk operations in Django ORM with `bulk_create` and `bulk_update`.

> ***For more such crispy blogs, follow DevJunction, subscribe to our newsletter and get notified.***
>

## Social Links

- **LinkedIn:** [https://www.linkedin.com/in/mnamegaurav/](https://www.linkedin.com/in/mnamegaurav/)
- **YouTube:** [https://www.youtube.com/c/devjunction](https://www.youtube.com/c/devjunction)
- **Website:** [https://gaurav.devjunction.in/](https://gaurav.devjunction.in/)
- **GitHub:** [https://github.com/mnamegaurav](https://github.com/mnamegaurav)
- **Instagram:** [https://www.instagram.com/mnamegaurav/](https://www.instagram.com/mnamegaurav/)
- **Twitter:** [https://twitter.com/mnamegaurav](https://twitter.com/mnamegaurav)
