urls.py decides which view handles a URL, and views.py holds the code that handles it. Keeping them apart lets you change a URL without touching the logic behind it.
urls.py is the router. Its urlpatterns list maps URL patterns to views, and Django calls the view of the first pattern that matches. A pattern can also have a name, so templates and code build links with {% url %} or reverse() instead of hard-coding paths.
views.py holds the view functions or classes. Each one takes an HTTP request, runs the business logic and returns an HTTP response. Here it queries the articles and renders a template with them.
# urls.py
urlpatterns = [
path('articles/', views.article_list, name='article_list'),
]
# views.py
def article_list(request):
articles = Article.objects.all()
return render(request, 'articles/list.html', {'articles': articles})
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓