Django Design Patterns and Best Practices: Industry-standard web development techniques and solutions using Python, 2nd Edition
Rate it:
Open Preview
14%
Flag icon
Patterns compensate for the missing language features: Peter Norvig found that 16 of the 23 patterns in design patterns were invisible or simpler in dynamic languages such as Lisp or Python. For instance, as functions are already objects in Python, it would be unnecessary to create separate classes to implement strategy patterns. Patterns repeat best practices: Many patterns are essentially formalizations of best practices, such as separation of concerns, and could seem redundant. Patterns can lead to over-engineering: Implementing the pattern might be less efficient and excessive compared to ...more
Mohamed Feddad
Great points, to highlight abusing design patterns.
15%
Flag icon
"Innovation is not about saying yes to everything. It's about saying NO to all but the most crucial features."                                                                                                                                    – Steve Jobs
15%
Flag icon
I have saved several doomed projects by spending a few days with the client to carefully listen to their needs and set the right expectations. Armed with nothing but a pencil and paper (or their digital equivalents), the process is incredibly simple, but effective. Here are some of the key points to remember while gathering requirements: Talk directly to the application owners even if they are not technically minded. Make sure you listen to their needs fully and note them. Don't use technical jargon such as models. Keep it simple and use end-user friendly terms such as a user profile. Set the ...more
15%
Flag icon
Break down process flows such as user signup. Any multistep functionality needs to be drawn as boxes connected by arrows. Next, work through the features list in the form of user stories or in any easily readable form. Play an active role in prioritizing the features into high, medium, or low buckets. Be very, very conservative in acceptin...
This highlight has been truncated due to consecutive passage length restrictions.
16%
Flag icon
What are the different ways in which I can implement this? What are the trade-offs? Which factors are more important in our context? Finally, which approach is the best?
Mohamed Feddad
Great design decision questions.
16%
Flag icon
Never be afraid to add more apps or refactor the existing ones into multiple apps. A typical Django project contains 15-20 apps.
19%
Flag icon
Think about how you can move the complexity from code to data. It is always harder to understand logic in code compared to data. UNIX has used this philosophy very successfully by giving many simple tools that can be piped to perform any kind of manipulation on textual data.
20%
Flag icon
Drawing a class diagram of your models like this is recommended. Class attributes might be missing at this stage, but you can detail them later.
20%
Flag icon
Boxes represent entities, which become models. Connector lines are bi-directional and represent one of the three types of relationships in Django: one-to-one, one-to-many (implemented with Foreign Keys), and many-to-many.
20%
Flag icon
Any other code in the __init__.py file will be run when the package is imported. Hence, it is the ideal place for any package-level initialization code.
21%
Flag icon
No attribute (cell) with multiple values A primary key defined as a single column or a set of columns (composite key)
22%
Flag icon
all non-primary key columns must be dependent on the entire primary key. In the previous table, notice that Origin depends only on the superhero, that is, Name. It doesn't matter which Power we are talking about. So, Origin is not entirely dependent on the composite primary key — Name and Power. Let's extract just the origin information into a separate table called Origin, as shown here:
22%
Flag icon
all non-primary key columns must be directly dependent on the entire primary key and must be independent of each other. Think about the Country column for a moment. Given the Latitude and Longitude, you can easily derive the Country column. Even though the country where a superpower was sighted is dependent on the Name-Power composite primary key, it is only indirectly dependent on them. So, let's separate the location details into a separate countries table as follows:
23%
Flag icon
class Meta:         unique_together = ("latitude", "longitude")
23%
Flag icon
Normalize while designing, but denormalize while optimizing.
23%
Flag icon
If you have a complex query spanning several tables, such as a count of superpowers by country, then creating a separate denormalized table might improve performance. Typically, this table will be in a faster in-memory database or a cache. As before, we need to update this denormalized table every time the data in your normalized models changes (or you will have the infamous cache-invalidation problem). Denormalization is surprisingly common in large websites because it is a tradeoff between speed and space. Today, space is cheap, but speed is crucial to user experience.
24%
Flag icon
Limitations of abstract models are as follows: They cannot have a Foreign key or many-to-many field from another model They cannot be instantiated or saved They cannot be directly used in a query since it doesn't have a manager
24%
Flag icon
Mixins ought to be orthogonal and easily composable. Drop in a mixin to the list of base classes and they should work. In this regard, they are more similar in behavior to composition rather than inheritance. Smaller mixins are better. Whenever a mixin becomes large and violates the single responsibility principle, consider refactoring it into smaller classes. Let a mixin do one thing and do it well.
25%
Flag icon
models.OneToOneField(settings.AUTH_USER_MODEL,
Mohamed Feddad
Should use django.contrib.auth.get_user_model() instead
25%
Flag icon
Previously, there was no specific place for initializing the signal code. Typically, they were imported or implemented in models.py (which was unreliable). However, with app-loading refactor in Django 1.7, the application initialization code location is well defined.
25%
Flag icon
 def ready(self):         from . import signals
25%
Flag icon
the profile admin can be made inline to the default user admin by defining a custom UserAdmin  in profiles/admin.py as follows: from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import Profile from django.contrib.auth.models import User     class UserProfileInline(admin.StackedInline):     model = Profile     class NewUserAdmin(UserAdmin):     inlines = [UserProfileInline]     admin.site.unregister(User) admin.site.register(User, NewUserAdmin)
Mohamed Feddad
Make admin display, a custom interface for a normalized custom django.contrib.auth.models.User
26%
Flag icon
Problem: Models can get large and unmanageable. Testing and maintenance get harder as a model does more than one thing. Solution: Refactor out a set of related methods into a specialized Service object.
27%
Flag icon
Service objects are plain old Python objects (POPOs) that encapsulate a service or interactions with a system. They are usually kept in a separate file named services.py or utils.py.
27%
Flag icon
In most cases, methods of a service object are stateless, that is, they perform the action solely based on the function arguments without using any class properties. Hence, it is better to explicitly mark them as static methods
28%
Flag icon
Each time we call a property, we are recalculating a function. If it is an expensive calculation, we might want to cache the result. This way, the next time the property is accessed, the cached value is returned: from django.utils.functional import cached_property     #...     @cached_property     def full_name(self):
29%
Flag icon
class PostQuerySet(QuerySet):     def public_posts(self):         return self.filter(privacy="public")   PostManager = PostQuerySet.as_manager
Mohamed Feddad
Quick and easy custom query manager
29%
Flag icon
True to their name (or rather the latter half of their name), QuerySets support a lot of (mathematical) set operations.
30%
Flag icon
# Union >>> User.objects.filter(Q(username__in=["a", "b", "c"]) | Q(username__in=["c", "d"])) [<User: a>, <User: b>, <User: c>, <User: d>]   # Intersection >>> User.objects.filter(Q(username__in=["a", "b", "c"]) & Q(username__in=["c", "d"])) [<User: c>]   # Difference >>> User.objects.filter(Q(username__in=["a", "b", "c"]) & ~Q(username__in=["c", "d"])) [<User: a>, <User: b>]
30%
Flag icon
the Set analogy is not perfect. QuerySets, unlike mathematical sets, are ordered. So, they are closer to Python's list data structure in that respect.
30%
Flag icon
>>>recent = list(posts)+list(comments)     >>>sorted(recent, key=lambda e: e.modified, reverse=True)[:3]     [<Post: user: Post1>, <Comment: user: Comment1>, <Post: user: Post0>]       Unfortunately, this operation has evaluated both the lazy QuerySet objects. The combined memory usage of the two lists can be overwhelming. Besides, it can be quite slow to convert large QuerySets into lists. A much better solution uses iterators to reduce the memory consumption. Use the itertools.chain method to combine multiple QuerySets as follows:     >>> from itertools import chain     >>> recent = ...more
31%
Flag icon
url(r'^hello-fn/(?P<name>\w+)/$', views.hello_fn),     url(r'^hello-fn/$', views.hello_fn), We are reusing the same view function to support two URL patterns. The first pattern takes a name argument. The second pattern doesn't take
31%
Flag icon
simplified routing syntax introduced in Django 2.0. So you will find the following equivalent mappings in viewschapter/urls.py: # In urls.py     path('hello-fn/<str:name>/', views.hello_fn),     path('hello-fn/', views.hello_fn),
34%
Flag icon
A well-written mixin imposes very little requirements. It should be flexible to be useful in most situations.
34%
Flag icon
The ability of mixins to combine with other classes is both their biggest advantage and disadvantage. Using the wrong combination can lead to bizarre results. So, before using a mixin, you need to check the source code of the mixin and other classes to ensure that there are no method or context-variable clashes.
34%
Flag icon
It can get quite tricky figuring out the order to list the base classes. Like most things in Django, the normal rules of Python apply. Python's Method Resolution Order (MRO) determines how they should be arranged. In a nutshell, mixins come first and base classes come last. The more specialized the parent class is, the more it moves to the left. In practice, this is the only rule you will need to remember.
34%
Flag icon
if B is mentioned before A in the list of base classes, then B's method gets called and vice versa. Now imagine A is a base class such as CreateView and B is a mixin such as FeedMixin. The mixin is an enhancement over the basic functionality of the base class. Hence, the mixin code should act first and in turn, call the base method if needed.
35%
Flag icon
syntactic sugar
35%
Flag icon
@login_required def simple_view(request):     return HttpResponse() The following code is exactly the same as the preceding: def simple_view(request):     return HttpResponse()   simple_view = login_required(simple_view)
35%
Flag icon
Decorators are less flexible than mixins. However, they are simpler. You can use both decorators and mixins in Django. In fact, many mixins are implemented with decorators.
36%
Flag icon
Staff members in Django are users with the is_staff flag set in the user model. Here you can use a built-in mixin called UserPassesTestMixin, as follows: from django.contrib.auth.mixins import UserPassesTestMixin     class SomeStaffView(UserPassesTestMixin, TemplateView):     def test_func(self, user):         return user.is_staff
36%
Flag icon
It is recommended to give users the least amount of privileges to objects as possible. This is called the Principle of least privilege. As a best practice, make sure you are explicit about which users or groups can perform certain actions on your objects rather than going with default access levels.
36%
Flag icon
Most generic class-based views are derived from ContextMixin. It provides the get_context_data method, which most classes override, to add their own context variables. While overriding this method, as a best practice, you will need to call get_context_data of the superclass first and then add or override your context variables.
37%
Flag icon
Short and meaningful URLs are not only appreciated by users, but also by search engines. URLs that are long and have less relevance to the content adversely affect your site's search engine rankings.
37%
Flag icon
URLs belong to a more general family of identifiers called Uniform Resource Identifiers (URIs). Hence, a URL has the same structure as a URI. A URI is composed of several parts: URI = Scheme + Net Location + Path + Query + Fragment For example, a URI (http://dev.example.com:80/gallery/videos?id=217#comments) can be deconstructed in Python using the urlparse function: >>> from urllib.parse import urlparse >>> urlparse("http://dev.example.com:80/gallery/videos?id=217#comments") ParseResult(scheme='http', netloc='dev.example.com:80', path='/gallery/videos', params='', query='id=217', ...more
38%
Flag icon
In many ways, urls.py is the entry point for your project. It is usually the first file I open when I study a Django project. It is like reading a map before exploring a terrain.
38%
Flag icon
Old (regular expression pattern) New (simplified pattern) # Homepage url(r'^$', IndexView.as_view(), name='home'), # Homepage path('', IndexView.as_view(), name='home'), url(r'^about/$',  AboutView.as_view(),  name='about'), path('about/', AboutView.as_view(), name='home'), url(r'^hello/(?P<name>\w+)/$', views.hello_fn), path('hello/<str:name>/', views.hello_fn), url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/' '(?P<day>[0-9]+)/(?P<pk>[0-9]+)/$', path('<int:year>/<int:month>/' '<int:day>/<int:pk>/',
39%
Flag icon
str
39%
Flag icon
int
39%
Flag icon
slug
« Prev 1 3 4 5