{"id":19755613,"url":"https://github.com/jonatandb/dave-gray-django-tutorials","last_synced_at":"2026-04-10T12:31:24.521Z","repository":{"id":235022848,"uuid":"789925552","full_name":"Jonatandb/Dave-Gray-Django-Tutorials","owner":"Jonatandb","description":"Dave Gray - Django Tutorials","archived":false,"fork":false,"pushed_at":"2024-04-29T21:39:59.000Z","size":2922,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-28T09:09:53.292Z","etag":null,"topics":["django","jonatandb","python","sqlite"],"latest_commit_sha":null,"homepage":"https://replit.com/@Jonatandb/Dave-Gray-Django-Tutorials","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jonatandb.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-21T23:14:33.000Z","updated_at":"2024-07-19T22:17:48.000Z","dependencies_parsed_at":"2025-02-28T02:11:03.528Z","dependency_job_id":"a60f0da3-470a-4e9a-85a4-79b07d304375","html_url":"https://github.com/Jonatandb/Dave-Gray-Django-Tutorials","commit_stats":null,"previous_names":["jonatandb/dave-gray-django-tutorials"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Jonatandb/Dave-Gray-Django-Tutorials","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonatandb%2FDave-Gray-Django-Tutorials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonatandb%2FDave-Gray-Django-Tutorials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonatandb%2FDave-Gray-Django-Tutorials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonatandb%2FDave-Gray-Django-Tutorials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jonatandb","download_url":"https://codeload.github.com/Jonatandb/Dave-Gray-Django-Tutorials/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonatandb%2FDave-Gray-Django-Tutorials/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31642674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","jonatandb","python","sqlite"],"created_at":"2024-11-12T03:12:37.203Z","updated_at":"2026-04-10T12:31:24.502Z","avatar_url":"https://github.com/Jonatandb.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# [Dave Gray - Django Tutorials](https://www.youtube.com/playlist?list=PL0Zuz27SZ-6NamGNr7dEqzNFEcZ_FAUVX)\n\n- Posts app with:\n  - User registration\n  - User authentication\n  - Posts listing\n  - Posts creation\n  - Protected routes\n\n---\n\nNote: To follow the tutorial playlist and make a new project for each lesson, I made a script called '_**clone_folder_and_increase_version.py**_' that creates a copy of the previous lesson folder and updates version numbers (in folders and files) accordingly (Thanks ChatGPT ♥)\n\n---\n\n## Lesson 0:\n- Project creation\n- Rendering of html templates\n- Config and use of paths and static files (css, js)\n\nCreate env (only the first time):\n\n  ```py -m venv venv```\n\nActivate env:\n\n  ```source venv/Scripts/activate```\n\nInstall Django (only the first time):\n\n    pip install django\n\nCreate a new Django project:\n\n    django-admin startproject lesson0\n\nStart app:\n\n    cd lesson0\n\n    py manage.py runserver\n\nVisit App:\n\n  - http://localhost:8000\n\nTo render HTML templates, a 'view' function must be created in views.py file:\n\n    def homepage(request):\n      return render(request, 'homepage.html')\n\nTo use it, a 'path' must be specified in urls.py file, inside of 'urlpatterns' list:\n\n    path('', views.homepage, name=\"homepage\"),\n\nBy default Django will look for 'homepage.html' inside 'templates' folder in the root of the project.\n\nFinally, to be able to use static files, the following code must be added to 'settings.py' file:\n\n    import os # Add this at the top\n\n    # Add this at the bottom of settings.py\n    STATICFILES_DIRS = [\n      os.path.join(BASE_DIR, 'static'),\n    ]\n\n  - Now, static files must be placed into '/static' root folder, and can be referenced from 'homepage.html' by using '{% static %} syntax':\n\n      ```\u003clink rel=\"stylesheet\" href=\"{% static 'css/styles.css' %}\"\u003e```\n\n      ```\u003cscript src=\"{% static 'js/index.js' %}\" defer\u003e\u003c/script\u003e```\n\n\n\n![alt text](image.png)\n\n---\n\n## Lesson 1:\n- App creation\n- App configuration\n- Using of namespaced templates\n- VSCode Emmet configuration for Django HTML files\n- Creation and use of \"Base layout\" template\n\nCreate a new Django app:\n\n    py manage.py startapp posts\n\nAdd new 'posts' app to INSTALLED_APPS on settings.py\n\nAdd new 'templates/layout.html' file with ```{% block title %}``` and  ```{% block content %}``` placeholders\n\nUpdate 'homepage.html' and 'about.html' to extends and use base layout by adding ```{% extends 'layout.html' %}``` and specifing blocks content.\n\nAlso add a new posts/templates/posts/posts.list.html file with ```{% extends 'layout.html' %}```\n\nAdd posts/urls.py and update lesson1/urls.py to include the posts urls.\n\nStart app:\n\n    cd lesson1\n\n    py manage.py runserver\n\nVisit App:\n\n  - http://localhost:8000\n  - http://localhost:8000/about\n  - http://localhost:8000/posts\n\n![alt text](image-1.png)\n\n![alt text](image-2.png)\n\n\n---\n\n## Lesson 2:\n\n- Model and migrations\n\nCreate a class called Post inside posts/models.py (must inherit from models.Model)\n\nDefine fields (more info: https://docs.djangoproject.com/en/5.0/ref/models/fields/)\n\nApply base app migrations by running:\n\n    py manage.py migrate\n\nCreate migration for new Post model:\n\n    py manage.py makemigrations\n  - A new 'posts\\migrations\\0001_initial.py' file will be created.\n\nApply migrations:\n\n    py manage.py migrate\n  - This creates Post model (_**table**_) on the database.\n\n\n---\n\n## Lesson 3:\n\n- ORM Intro\n- Adding **'\\__str\\__'** method to Post model to show post title whenever a post is shown:\n\n      def __str__(self):\n        return self.title\n\nA quick way to try and play with the Django ORM is by using the shell this way:\n\n    py manage.py shell\n\nFrom there the Post model can be imported to perform several operations:\n\n    from posts.models import Post\n\nTo create a Post object:\n\n    p = Post()\n\nTo set values for the attributes:\n\n    p.title = \"First Post\"\n    p.body = \"First Post body text\"\n\nNow the Post object can be saved into the database:\n\n    p.save()\n\nFinally it's possible to get all posts from the database:\n\n    Post.objects.all()\n\n  - Expected result:\n\n      \u003cQuerySet [\u003cPost: First post\u003e]\u003e\n\nTo exit from the shell, execute:\n\n    exit()\n\n![alt text](image-3.png)\n\n\n\n---\n\n## Lesson 4:\n\n- Django Admin Introduction\n- Admin panel user creation\n- Model registration to show it in admin panel\n- Django ORM Post model used to retrive ordered posts\n- Use of Python code in Jinja HTML templates to itereate and render posts\n\nAn user must be created to access to /admin panel:\n\n      py manage.py createsuperuser\n\n  - User created: admin\n  - Password: admin123\n\n- Posts can be manipulated by using the admin panel, but first it's requeried to \"register\" the Post model:\n  - Add to '**_posts/admin.py_**', the following lines:\n\n\n        from .models import Post\n        admin.site.register(Post)\n\n  - Next, access to http://localhost:8000/admin\n    - A CMS web interface is available to manipulate (CRUD operations available) posts, users and groups.\n\n![alt text](image-5.png)\n\n- To show posts list, posts must be retrieved from the database by using Django ORM, and then passing it to the render method:\n\n      def posts_list(request):\n        posts = Post.objects.all().order_by('-date')\n        return render(request, 'posts/posts_list.html', { 'posts': posts })\n    - By using '-date' param, it will retrive posts in descending order.\n\n- Finally, the HTML template must iterate the posts list to show the posts, it can be done by using a for loop:\n\n      {% for post in posts %}\n        \u003carticle\u003e\n          \u003ch2\u003e{{ post.title }}\u003c/h2\u003e\n          \u003cp\u003e{{ post.date }}\u003c/p\u003e\n          \u003cp\u003e{{ post.body }}\u003c/p\u003e\n        \u003c/article\u003e\n      {% endfor %}\n\n![alt text](image-4.png)\n\n\n---\n\n## Lesson 5: Pages, URLs \u0026 Slugs\n\n- URL path's names (aliases) and using URL name's on anchor tags\n- Setting app_name to app url's file\n- Using 'slug' Django path converter\n\nSetting _**app_name**_ in _'\\posts\\urls.py'_ to be able to have the same url 'name' in different _**urls.py**_ app files.\n  - To do this, just add a variable with the app name to _'posts/urls.py'_ app file:\n\n        app_name = 'posts'\n\nSetting name to an url path in _'\\posts\\urls.py'_:\n\n    path('', views.posts_list, name=\"list\")\n\n  - Now, whenever an anchor tags is created, it can use app name and url name, like this:\n\n    ```\u003ca href=\"{% url 'posts:list' %}\"\u003ePosts\u003c/a\u003e```\n\nSetting url path config in URL in '\\posts\\urls.py' for use of the post's 'slug':\n\n    path('\u003cslug:slug\u003e', views.post_page, name=\"page\"),\n\n  - First 'slug' term tells Django and slug will be used in URL, second 'slug' term specify the Post model field which will be used as slug for creation of each Post URL.\n  - #### Before this works, all posts must have slug field complete with some value like \"my-first-post\", \"another-post\", etc. ####\n\nFinally, it's possible now to visit a specific post page specifing the post slug in URL, ex:\n  - http://127.0.0.1:8000/posts/first-post\n\n  ![alt text](image-6.png)\n\n\n\n---\n\n## Lesson 6: Upload \u0026 Display Images\n\n- Update 'settings.py' adding at the bottom:\n\n      MEDIA_URL = 'media/'\n      MEDIA_ROOT = os.path.join(BASE_DIR, 'media')\n\n- Create a 'media' root folder.\n- Update main 'urls.py' to add:\n\n      from django.conf.urls.static import static\n      from django.conf import settings\n\n      urlpatterns = [\n        ... # Do not touch this part\n      ]\n\n      # Add this:\n      urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\n- Install Pillow, that allows to use 'models.ImageFiled' in models:\n\n      pip install Pillow\n\n- Update Post model in 'posts/models.py', adding a new 'banner' field:\n\n      banner = models.ImageField(default='fallback.png', blank=True)\n\n- Make and execute migrations:\n\n      py manage.py makemigrations\n      py manage.py migrate\n\n- Create a _requirements.txt_ file:\n\n      pip freeze \u003e requirements.txt\n\n- Go to admin panel and update existing posts adding the value for the banner field (by default 'fallback.png' will be used for all posts)\n\n- Make sure '/media' folder and 'media/fallback.png' file exists.\n\n- Go to 'posts/templates/post_page.html' and add an img tag to show the image of the new 'banner' field\n\n      \u003cimg class=\"banner\"\n            src=\"{{ post.banner.url }}\"\n            alt=\"{{ post.title}}\"\n      /\u003e\n\n- Update CSS file '/static/css/styles.css' adding:\n\n      .banner {\n        display: block;\n        width: 100%;\n        max-width: 800px;\n      }\n\n![alt text](image-7.png)\n\n\n---\n\n## Lesson 7: Adding a new 'Users' app\n- App creation:\n\n      py manage.py startapp users\n\n- App registration in 'lesson7/lesson7/settings.py':\n\n      INSTALLED_APPS = [\n          ... # Do not touch anything here\n          'posts',\n          'users' # \u003c-- Add this line\n      ]\n\n- Add url path to users app in 'lesson7/lesson7/urls.py' file:\n\n      path('posts/', include('posts.urls')), # \u003c-- Below this line\n      path('users/', include('users.urls')), # \u003c-- Add this new line\n\n- Adding a new route path in a new 'users/urls.py' file:\n\n      app_name = 'users'\n\n      urlpatterns = [\n          path('register/', views.register, name=\"register\"),\n      ]\n\n- Adding a new view for register page in 'users/views.py' file:\n\n      def register(request):\n        return render(request, 'users/register.html')\n\n- Creating the register view HTML template in 'users/templates/users/register.html' which extends the base layout:\n\n      {% extends 'layout.html' %}\n\n      {% block title %}\n        Register a New User\n      {% endblock %}\n\n      {% block content %}\n        \u003ch2\u003eRegister a New User\u003c/h2\u003e\n      {% endblock %}\n\n![alt text](image-8.png)\n\n\n\n---\n\n## Lesson 8: Adding user registration form\n- Updating users register view ('_/users/views.py/_') to be able to create and then validate registration form, by using Django UserCreationForm functionality:\n\n      from django.contrib.auth.forms import UserCreationForm\n\n      def register(request):\n          if request.method == 'POST':\n              form = UserCreationForm(request.POST)\n              if form.is_valid():\n                  form.save()\n                  return redirect('posts:list')\n          else:\n              form = UserCreationForm()\n          return render(request, 'users/register.html', {'form': form})\n\n- Updating HTML template _'users\\templates\\users\\register.html'_ to include the Django form created (it will also show validations errors, if any occur):\n\n      {% block content %}\n        \u003ch1\u003eRegister a New User\u003c/h1\u003e\n        \u003cform action=\"\" class=\"form-with-validation\" method=\"post\"\u003e\n          {% csrf_token %}\n          {{ form }}\n          \u003cbutton class=\"form-submit\"\u003eSubmit\u003c/button\u003e\n        \u003c/form\u003e\n      {% endblock %}\n\n  - _**{% csrf_token %}**_ is required to allow Django verify that post data is coming from the same application, and be able to manage/avoid _**Cross site reference forgery**_.\n\n\n![alt text](image-9.png)\n\n\n---\n\n## Lesson 9: Login Form and User Authentication\n- Updated navigation bar to include a login link.\n- Updated '**_users/urls.py_**' to include new 'login/' path:\n\n      path('login/', views.login_view, name=\"login\")\n\n- Added '**_users/templates/login.html_**' page (similar to register.html)\n- Added a new **_login_view_** method in '**_users/views.py_**' to manage the user login by using **_AuthenticationForm_** and **_login_** Django built-in functionalities:\n\n      from django.contrib.auth.forms import UserCreationForm, AuthenticationForm\n      from django.contrib.auth import login\n\n      def login_view(request):\n          if request.method == 'POST':\n              form = AuthenticationForm(data=request.POST)\n              if form.is_valid():\n                  login(request, form.get_user())\n                  return redirect('posts:list')\n          else:\n              form = AuthenticationForm()\n          return render(request, 'users/login.html', {'form': form})\n\n![alt text](image-10.png)\n\n\n---\n\n## Lesson 10: User Authorization\n#### Added logout functionality:\n- Added logout view to '**_users/views.py_**':\n\n      def logout_view(request):\n          if request.method == 'POST':\n              logout(request)\n              return redirect('posts:list')\n\n- Added logout url path to '**_users/urls.py_**':\n\n      path('logout/', views.logout_view, name=\"logout\"),\n\n- Added logout navbar button to layout template '**_templates/layout.html_**':\n\n      \u003cform class=\"logout\" action=\"{% url 'users:logout' %}\" method=\"post\"\u003e\n        {% csrf_token %}\n        \u003cbutton class=\"logout-button\" aria-label=\"User Logout\" title=\"User Logout\"\u003e👋🏻\u003c/button\u003e\n      \u003c/form\u003e\n\n#### Protected route -\u003e New Post:\n- Added '_new-post/_' url path to '**_posts/urls.py_**':\n\n      path('new-post/', views.post_new, name=\"new\"),\n\n- Added a new html template for the new post page: '**_posts/templates/post_new.html_**'.\n- Added a new navbar link to the new route '**_posts/new-post_**'.\n- Added the view for new post page with the '**_@login_required()_**' decorator that will redirect the user if he is not logged in:\n\n\n      @login_required(login_url='/users/login/')\n      def post_new(request):\n        return render(request, 'posts/post_new.html')\n\n- URL when an unauthenticated user try to access to '_/posts/new-post_':\n\n![alt text](image-11.png)\n\n\n\n#### Using the '_next_' query param (if it exists) to redirect the user to the page from where he was redirect to login (surely because the route was protected):\n\n- Updating the users login page to save the '_next_' parameter, in a hidden input, if it exists:\n\n      {% block content %}\n        \u003ch1\u003eLogin User\u003c/h1\u003e\n        \u003cform action=\"\" class=\"form-with-validation\" method=\"post\"\u003e\n          {% csrf_token %}\n          {{ form }}\n          {% if request.GET.next %}\n            \u003cinput type=\"hidden\" name=\"next\" value=\"{{ request.GET.next }}\" /\u003e\n          {% endif %}\n          \u003cbutton class=\"form-submit\"\u003eSubmit\u003c/button\u003e\n        \u003c/form\u003e\n      {% endblock %}\n\n- Updating the login_view functionality to redirect the user to the correct page depending on if the _next_ parameter exists in the url:\n\n      def login_view(request):\n          ...\n              if form.is_valid():\n                  login(request, form.get_user())\n                  if 'next' in request.POST:\n                      return redirect(request.POST.get('next'))\n                  else:\n                      return redirect('posts:list')\n          else:\n              ...\n\n- After a successful login:\n\n![alt text](image-12.png)\n\n#### Conditional rendering of menu options depending on if the user is logged in:\n- Updated navbar using '_**if user.is_authenticated**_':\n\n      \u003cnav\u003e\n        \u003ca href=\"{% url 'homepage' %}\"\u003e\n          \u003cspan role=\"img\" aria-label=\"Home\" title=\"Home\"\u003e🏠\u003c/span\u003e\n        \u003c/a\u003e |\n        \u003ca href=\"{% url 'about' %}\"\u003e\n          \u003cspan role=\"img\" aria-label=\"About\" title=\"About\"\u003e😃\u003c/span\u003e\n        \u003c/a\u003e |\n        \u003ca href=\"{% url 'posts:list' %}\"\u003e\n          \u003cspan role=\"img\" aria-label=\"Posts\" title=\"Posts\"\u003e📰\u003c/span\u003e\n        \u003c/a\u003e |\n\n        {% if user.is_authenticated %}\n          \u003ca href=\"{% url 'posts:new' %}\"\u003e\n            \u003cspan role=\"img\" aria-label=\"New Post\" title=\"New Post\"\u003e🆕\u003c/span\u003e\n          \u003c/a\u003e |\n          \u003cform class=\"logout\" action=\"{% url 'users:logout' %}\" method=\"post\"\u003e\n            {% csrf_token %}\n            \u003cbutton class=\"logout-button\" aria-label=\"User Logout\" title=\"User Logout\"\u003e👋🏻\u003c/button\u003e\n          \u003c/form\u003e\n        {% else %}\n          \u003ca href=\"{% url 'users:register' %}\"\u003e\n            \u003cspan role=\"img\" aria-label=\"Register\" title=\"Register\"\u003e🚀\u003c/span\u003e\n          \u003c/a\u003e |\n          \u003ca href=\"{% url 'users:login' %}\"\u003e\n            \u003cspan role=\"img\" aria-label=\"Login\" title=\"Login\"\u003e🔏\u003c/span\u003e\n          \u003c/a\u003e\n        {% endif %}\n      \u003c/nav\u003e\n\n- User not authenticated:\n\n![alt text](image-13.png)\n\n- User authenticated:\n\n![alt text](image-14.png)\n\n\n---\n\n## Lesson 11: Django Forms\n\n#### Added a new Author field to post model\n\n- Delete all posts since now the authenticated user will be the author each time he creates a new post.\n- Update the Post model to include a new foreign key field Author related to the user:\n\n      from django.contrib.auth.models import User\n\n      class Post(models.Model):\n        ... other fileds...\n        author = models.ForeignKey(User, on_delete=models.CASCADE, default=None)\n- Execute makemigrations and migrate to update the database table for Post model.\n\n#### Added a new _CreatePost_ class inside a new '_posts/forms.py_' file\n- It extends from **_forms.ModelForm_** in django forms:\n\n      from django import forms\n\n      class CreatePost(forms.ModelForm):\n        class Meta:\n          model = models.Post\n          fields = ['title','body','slug','banner']\n\n#### Updated post_new view in '_posts/views.py_' to instantiate and use _CreatePost_ class and pass it to the post_new HTML template:\n\n      @login_required(login_url='/users/login/')\n      def post_new(request):\n        if request.method == 'POST':\n          form = CreatePost(request.POST, request.FILES)\n          if form.is_valid():\n            new_post = form.save(commit=False)\n            new_post.author = request.user\n            new_post.save()\n            return redirect('posts:list')\n        else:\n          form = CreatePost()\n        return render(request, 'posts/post_new.html', {'form': form})\n\n#### Updated the post_new template to show the new post form:\n\n        \u003csection\u003e\n          \u003ch2\u003eNew Post\u003c/h2\u003e\n          \u003cform action=\"{% url 'posts:new' %}\" method=\"post\" class=\"form-with-validation\" enctype=\"multipart/form-data\"\u003e\n            {% csrf_token %}\n            {{ form }}\n            \u003cbutton class=\"form-submit\" type=\"submit\"\u003eAdd Post\u003c/button\u003e\n          \u003c/form\u003e\n        \u003c/section\u003e\n\n    - Very important: Add _**enctype=\"multipart/form-data\"**_ to form meta tag, so it can be used to correctly upload the selected image.\n\n#### Updated the _post_page_ and/or the _post_list_ HTML template to show the author of the each post:\n\n      \u003cp\u003e{{ post.date }} by {{ post.author }}\u003c/p\u003e\n\n![alt text](image-16.png)\n\n![alt text](image-15.png)\n\n---\n---\n\n## Lesson 12 - Optional changes for a ready-for-production app:\n\n#### Update of _settings.py_:\n  - Remove import os\n  - Update DEBUG variable to False value\n  - Update ALLOWED_HOSTS variable with known hostnames, ex: 'localhost', '127.0.0.1'.\n  - Add a STATIC_ROOT variable, update STATICFILES_DIRS variable and then add another new MEDIA_ROOT variable as follows:\n\n        STATIC_URL = 'static/'\n        MEDIA_URL = 'media/'\n\n        STATIC_ROOT = BASE_DIR / 'assets'\n        MEDIA_ROOT = BASE_DIR / 'media'\n        STATICFILES_DIRS = [ BASE_DIR / 'static' ]\n\n    Finally, execute:\n\n          py manage.py collectstatic\n\n    This will create a new '_assets_' directory containing all static files from the hole project.\n\n#### Update of _urls.py_ main project file:\n  - Add a new import:\n\n        from django.views.static import serve\n\n  - Add re_path import:\n\n        from django.urls import path, include, re_path\n  - Add two new patterns to _urlpatterns_ list:\n\n        urlpatterns = [\n          re_path(r'^media/(?P\u003cpath\u003e.*)$', serve, {'document_root': settings.MEDIA_ROOT}),\n          re_path(r'^static/(?P\u003cpath\u003e.*)$', serve, {'document_root': settings.STATIC_ROOT}),\n          ... rest of paths...\n  - Remove or comment the last _urlpatterns_ line:\n\n        #urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\n---\n\n# Deploy steps on common online services:\n  - https://docs.render.com/deploy-django\n  - https://blog.replit.com/deploying-django\n  - https://docs.digitalocean.com/developer-center/deploy-a-django-app-on-app-platform/\n  - https://dev.to/osahenru/using-railway-app-to-deploy-your-django-project-3ah1\n  - https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-django.html\n\n\n### Replit deploy available (just clone and then click _Run_):\n- https://replit.com/@Jonatandb/Dave-Gray-Django-Tutorials\n\n[![Replit deploy available](image-17.png)](https://replit.com/@Jonatandb/Dave-Gray-Django-Tutorials)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonatandb%2Fdave-gray-django-tutorials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonatandb%2Fdave-gray-django-tutorials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonatandb%2Fdave-gray-django-tutorials/lists"}