Swipe left or right to navigate to next or previous post
While naming the model, it is recommended to use the singular nouns like User, Address, Blog. If the single unit of the model does not contains information on the several objects, it is recommended to use a singular noun.
For relationships fields like ForeignKey, OneToOneKey, OneToMany, ManyToMany, it is recommended to use a name to specify a relationship.
Imagine there is a model called Article, - in which one of the relationships is ForeignKey for model User. If this field contains information about the author of the article, then author will be a more appropriate name than user.
In most of the cases, the plural of the model in plural will be correct.
class Owner(models.Model): pass class Item(models.Model): owner = models.ForeignKey(Owner, related_name='items')
Preferred attributes and methods order in a model
It's always better to specify default values for BooleanField. If you want to keep the boolean field empty by default, It is better to use NullBooleanField.
It is better to allocate business logic of the business in models. The business logic can be allocate in models with the help of model methods and model manager.
Do not duplicate model fields in ModelForm or ModelSerializer without any need. If it is required to use all model fields, use MetaFields. If it is required to redefine a widget for a field with nothing changed in the field, use Meta widgets to indicate widgets.
ModelName.DoesNotExist is more specific exception than ObjectDoesNotExist which is a positive practice.
class Article(models.Model): is_published = models.BooleanField(default=False) is_verified = models.BooleanField(default=False) …
Assume an application where the article has the status of draft, verified and published. Instead of using the combination of is_published and is_verified or similar flags, we can use the single status flag that tracks the status of the article.
class Article(models.Model): STATUSES = Choices('new', 'verified', 'published') status = models.IntegerField(choices=STATUSES, default=STATUSES.draft)
While creating a field in a model, it's not logical to add the model name. Like when we create a user status on the user model, we can just create a status field instead of redundant user_status field.
Do not use len method to get the no of objects returned by the query set. While using the len, the queryset to select all the objects in the database is run. The data returned by queryset is transformed into python Object and then finally run the length on that object.
Instead of using the len we can use the count method. It is similar to running COUNT method in SQL query. With count, an easier query is carried out in the database with fewer resources which improve the performance.
Do not use a queryset as a boolean value. In django, queryset are lazy loaded. But while using a queryset as boolean, the actual inappropriate queryset is carried out. So, instead of using if queryset, we can do if queryset.exist() which actually use less resource.
Do not add _id suffix to ForeignKeyField and OneToOneField.
If you want to share the same logic between models, create an abstract models.
class CreatedAtModel(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: abstract = True class Post(CreatedAtModel): ... class Comment(CreatedAtModel): ...
To keep all the business logic in one place, we can use the custom managers and QuerySet.
If you want the no of comments count for the posts, we can:
class CustomManager(models.Manager): def with_comments_counter(self): return self.get_queryset().annotate(comments_count=Count('comment_set')) posts = Post.objects.with_comments_counter() posts[0].comments_count
We should write most of the logic in model itself which results in fat models, skinny views.
For example, while implementing a functionality of sending an email to user, it is better to extend the model with an email function instead of writing the logic in the view. This makes the code easier to unit test.
Templates can be placed at two places, either in the app directory itself or in the root directory. It is recommended to put the templates in the root directory. But if you want to reuse app in multiple places, then you should place in the app directory.
#Good practice root_folder/ my_app1/ my_app2/ my_app3/ templates/ #If you want to make your app reusable root_folder/ my_app1/ templates/ my_app2/ templates/ my_app3/ templates/
Use the separate settings file for the different environment.
settings/ ├── __init__.py ├── base.py ├── ci.py ├── local.py ├── staging.py ├── production.py └── qa.py
settings/local.py
from .base import * ALLOWED_HOSTS = ['localhost'] DEBUG = True DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'local_db', 'HOST': '127.0.0.1', 'PORT': '5432', } }
We can specify which configuration to use with setting parameter
python manage.py runserver --settings=settings.local