1
\$\begingroup\$

I have been designing websites with Django for a while and I have also designed various sites. But here is a question that comes to mind at the beginning of any new project:

What is the best URLs architectural Design that creates both logical and meaningful URLs path as well as pluggable apps?

I will explain my question with a practical example.

Practical Example And Problem

Suppose that we have project with these features:

  1. It has three applications called Shop, Blog and Support.

  2. It has three URL section:

    2.1. Public section: that start with /.

    2.2. Consumer panel: that start with /panel.

    2.3. Administrator panel: that start with /administrator.

Each application has 3 views. For example Shop has: public_shop_view, panel_shop_view and administrator_shop_view.

Now, What is the best URL design for this project? I describe two possible answers here for URLs design.

Solution 1:

project/urls.py

path('', include('Shop.urls', namespce='Shop')),
path('', include('Blog.urls', namespce='Blog')),
path('', include('Support.urls', namespce='Support')),

Shop/urls.py

path('shop/', views.public_shop_view, name='public_shop_view'),
path('panel/shop/', views.panel_shop_view, name='panel_shop_view'),
path('administrator/shop/', views.administrator_shop_view, name='administrator_shop_view'),

Blog/urls.py

path('blog/', views.public_blog_view, name='public_blog_view'),
path('panel/blog/', views.panel_blog_view, name='panel_blog_view'),
path('administrator/blog/', views.administrator_blog_view, name='administrator_shop_view'),

Support/urls.py

path('support/', views.public_support_view, name='public_support_view'),
path('panel/support/', views.panel_support_view, name='panel_support_view'),
path('administrator/support/', views.administrator_support_view, name='administrator_support_view'),

Solution 2:
In this solution we create three apps (Public, Panel, Administrator) that just have urls.py file (to follow the interface strategy):

project/urls.py

path('', include('Public.urls', namespce='Interface')),
path('panel/', include('Panel.urls', namespce='Panel')),
path('administrator/', include('Administrator.urls', namespce='Administrator')),

Public/urls.py

from Support import views as support_views
from Blog import views as blog_views
from Shop import views as shop_views

path('support/', support_views.public_support_view, name='public_support_view'),
path('blog/', blog_views.public_blog_view, name='public_blog_view'),
path('shop/', shop_views.public_shop_view, name='public_shop_view'),

Panel/urls.py

from Support import views as support_views
from Blog import views as blog_views
from Shop import views as shop_views

path('support/', support_views.panel_support_view, name='panel_support_view'),
path('blog/', blog_views.panel_blog_view, name='panel_blog_view'),
path('shop/', shop_views.panel_shop_view, name='panel_shop_view'),

Administrator/urls.py

from Support import views as support_views
from Blog import views as blog_views
from Shop import views as shop_views

path('support/', support_views.administrator_support_view, name='administrator_support_view'),
path('blog/', blog_views.administrator_blog_view, name='administrator_blog_view'),
path('shop/', shop_views.administrator_shop_view, name='administrator_shop_view'),

Now, What is the best practice? Solution 1 or solution 2 or other solution?

\$\endgroup\$
  • 1
    \$\begingroup\$ Django apps are reusable components. You can plug an app from one django project to some other django project.That is the idea and you should design an app in such as way. \$\endgroup\$ – Vishesh Mangla Jul 16 at 9:59
  • 1
    \$\begingroup\$ Unfortunately CodeReview does not deal in hypotheticals. If you reform this into a stand-alone pet project to demonstrate your situation and show the code from beginning to end, it might become on-topic. \$\endgroup\$ – Reinderien Jul 16 at 13:36
  • 1
    \$\begingroup\$ Code Review requires concrete code from a project, with enough code and / or context for reviewers to understand how that code is used. Pseudocode, stub code, hypothetical code, obfuscated code, and generic best practices are outside the scope of this site. Your phrase What is the best practice, as well as the fact that none of your examples is complete (where do you import path?) bring this off-topic. \$\endgroup\$ – Reinderien Jul 16 at 16:15
  • 1
    \$\begingroup\$ It doesn't (and should not) matter whether your reviewers are familiar with Django or not. Relying on implicit knowledge and assumptions about your code will not allow for a high-quality review and will narrow the possible responses that you get. Your code needs to be runnable, period; rather than hoping that reviewers are able to fill in the blanks and read your mind. \$\endgroup\$ – Reinderien Jul 16 at 16:27
  • 1
    \$\begingroup\$ Yes, absolutely :) \$\endgroup\$ – Reinderien Jul 16 at 16:30
2
\$\begingroup\$

I've read the comments and am a bit torn by the discussion... yes, this code is not runnable; yes, you assume background knowledge; but you do that because 90% of Django starter code is not relevant to this discussion, but is essential to a Django project, so I think this is worth a shot.

For starters, it's worth pointing out that which of these solutions you choose has no impact on the code you write, since you will always refer to URL's by their name rather than by their path. This is solely a matter of beauty for how your capabilities are exposed to users and external services.

For this case, I would suggest a refactor that separates the front-end (paths) from the back-end (functionality). Have an app each for support, blog, and store, each of which implement their own models, serializers, utility functions, Celery tasks, etc. Then, have an app each for panel and administration that implements the paths, views, and user-facing logic about how people interact with those underlying concepts. You end up with some internal dependencies, but they're bipartite (only apps in the "frontend" group depend on only apps in the "backend" groups) and acyclic, so that's not a big deal.

If designed this way, you get the best of both worlds. You can keep the logical separation you show above among isolated logical components, but can use clean path construction and view implementation designed around how the users interact with your system. The downside is a larger number of apps and some internal dependencies, but those dependencies become explicit and you avoid the apps needing to implicitly know about each other and knowing how to avoid path conflicts.

| improve this answer | |
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.