├── .gitignore ├── .idea ├── .gitignore ├── dataSources.xml ├── django101.iml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml └── modules.xml ├── LICENSE ├── README.md ├── class_based_views_advanced ├── .idea │ ├── .gitignore │ ├── class_based_views_advanced.iml │ ├── dataSources.xml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── class_based_views_advanced │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── web │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_todo_slug.py │ │ │ ├── 0003_todo_tenant_alter_todo_slug.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── wsgi.py ├── manage.py └── templates │ ├── base.html │ └── web │ ├── create_todo.html │ ├── detail_todo.html │ └── todo_list.html ├── class_based_views_basics ├── .idea │ ├── .gitignore │ ├── class_based_views_basics.iml │ ├── dataSources.xml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── class_based_views_basics │ ├── __init__.py │ ├── asgi.py │ ├── custom_class_base_views │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ ├── settings.py │ ├── urls.py │ ├── web │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── forms.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_category_todo_category.py │ │ │ ├── 0003_alter_todo_category.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── wsgi.py ├── manage.py └── templates │ └── web │ ├── create_todo.html │ ├── details_todo.html │ ├── index.html │ └── list_todos.html ├── django101 ├── .idea │ ├── .gitignore │ ├── dataSources.xml │ ├── django101.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ └── modules.xml ├── django101 │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── tasks │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── middlewares.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_task_done.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── templates │ └── tasks │ └── index.html ├── docker-compose.yml ├── exam_prep_my_music_app ├── .idea │ ├── .gitignore │ ├── dataSources.xml │ ├── exam_prep_my_music_app.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── exam_prep_my_music_app │ ├── __init__.py │ ├── albums │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_alter_album_artist_name_alter_album_image_url_and_more.py │ │ │ ├── 0003_alter_album_genre.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ ├── asgi.py │ ├── common │ │ ├── __init__.py │ │ └── profile_helpers.py │ ├── profiles │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_alter_profile_username.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ ├── validators.py │ │ └── views.py │ ├── settings.py │ ├── urls.py │ ├── web │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── forms.py │ │ ├── migrations │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── wsgi.py ├── manage.py ├── staticfiles │ ├── css │ │ ├── catalog.css │ │ ├── create.css │ │ ├── details.css │ │ ├── home.css │ │ ├── login.css │ │ ├── style.css │ │ └── typography.css │ └── images │ │ ├── BrandiCarlile.png │ │ ├── Lorde.jpg │ │ ├── back.jpg │ │ ├── headphones.png │ │ ├── musicIcons.webp │ │ └── pinkFloyd.jpg └── templates │ ├── albums │ ├── album-add.html │ ├── album-delete.html │ ├── album-details.html │ └── album-edit.html │ ├── base.html │ ├── profiles │ ├── profile-delete.html │ └── profile-details.html │ └── web │ ├── home-no-profile.html │ └── home-with-profile.html ├── form_basics ├── .idea │ ├── .gitignore │ ├── dataSources.xml │ ├── form_basics.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── form_basics │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── web │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── forms.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_department_alter_employee_first_name_and_more.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── wsgi.py ├── manage.py └── templates │ └── web │ ├── employee_details.html │ ├── index.html │ ├── index_old.html │ └── modelform_index.html ├── forms_advanced ├── .idea │ ├── .gitignore │ ├── dataSources.xml │ ├── forms_advanced.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── forms_advanced │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── web │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── forms.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_person_age_person_last_name_alter_person_first_name.py │ │ │ ├── 0003_person_created_by.py │ │ │ ├── 0004_person_profile_image.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ ├── validators.py │ │ └── views.py │ └── wsgi.py ├── manage.py ├── non_django_demos │ ├── __init__.py │ └── callables.py ├── requirements.txt └── templates │ └── web │ ├── formsets.html │ └── index.html ├── templates_advanced ├── .idea │ ├── .gitignore │ ├── dataSources.xml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── jsLibraryMappings.xml │ ├── misc.xml │ ├── modules.xml │ ├── templates_advanced.iml │ └── vcs.xml ├── manage.py ├── staticfiles │ ├── about.css │ ├── main.css │ └── sidebar.css ├── templates │ ├── master.html │ ├── master_with_sidebar.html │ ├── partials │ │ ├── footer.html │ │ └── header.html │ ├── tags │ │ └── profile_avatar.html │ └── web │ │ ├── about.html │ │ ├── bootstrap.html │ │ └── index.html └── templates_advanced │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── web │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── templatetags │ │ ├── __init__.py │ │ ├── list_tags.py │ │ ├── number_filters.py │ │ └── user_tags.py │ ├── tests.py │ ├── urls.py │ └── views.py │ └── wsgi.py ├── templates_static_files ├── .idea │ ├── .gitignore │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── templates_static_files.iml ├── manage.py ├── staticfiles │ ├── css │ │ └── site.css │ ├── imgs │ │ └── cat.jpg │ └── js │ │ └── site.js ├── templates │ ├── base.html │ ├── demo.html │ └── employees │ │ ├── details.html │ │ └── index.html └── templates_static_files │ ├── __init__.py │ ├── asgi.py │ ├── employees │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ └── views.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── urls_and_views_demos ├── .idea ├── .gitignore ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── urls_and_views_demos.iml └── vcs.xml ├── manage.py ├── staticfiles ├── main.css └── main.js ├── templates ├── 404.html └── core │ └── index.html └── urls_and_views_demos ├── __init__.py ├── asgi.py ├── core ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── departments ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── settings.py ├── urls.py └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | 132 | # Docker volumes 133 | postgresql 134 | pgadmin4 135 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://localhost:5432/ 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/django101.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Doncho Minkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-web-basics -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/class_based_views_advanced.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /class_based_views_advanced/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_advanced/class_based_views_advanced/__init__.py -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for class_based_views_advanced project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "class_based_views_advanced.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URL configuration for class_based_views_advanced project. 3 | 4 | The `urlpatterns` list routes URLs to views. For more information please see: 5 | https://docs.djangoproject.com/en/4.2/topics/http/urls/ 6 | Examples: 7 | Function views 8 | 1. Add an import: from my_app import views 9 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 10 | Class-based views 11 | 1. Add an import: from other_app.views import Home 12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 13 | Including another URLconf 14 | 1. Import the include() function: from django.urls import include, path 15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 16 | """ 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | 20 | urlpatterns = [ 21 | path("admin/", admin.site.urls), 22 | path("", include("class_based_views_advanced.web.urls")), 23 | ] 24 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_advanced/class_based_views_advanced/web/__init__.py -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "class_based_views_advanced.web" 7 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-12 16:06 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | initial = True 8 | 9 | dependencies = [] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name="Todo", 14 | fields=[ 15 | ( 16 | "id", 17 | models.BigAutoField( 18 | auto_created=True, 19 | primary_key=True, 20 | serialize=False, 21 | verbose_name="ID", 22 | ), 23 | ), 24 | ("title", models.CharField(max_length=24)), 25 | ("description", models.TextField()), 26 | ("is_done", models.BooleanField(default=False)), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/migrations/0002_todo_slug.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-12 17:51 2 | 3 | import class_based_views_advanced.web.models 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ("web", "0001_initial"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name="todo", 15 | name="slug", 16 | field=models.SlugField( 17 | default=class_based_views_advanced.web.models.generate_slug, 18 | editable=False, 19 | ), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/migrations/0003_todo_tenant_alter_todo_slug.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-12 18:05 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("web", "0002_todo_slug"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="todo", 14 | name="tenant", 15 | field=models.CharField(blank=True, default=None, max_length=16, null=True), 16 | ), 17 | migrations.AlterField( 18 | model_name="todo", 19 | name="slug", 20 | field=models.SlugField(editable=False), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_advanced/class_based_views_advanced/web/migrations/__init__.py -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/models.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | from django.db import models 4 | from django.utils.text import slugify 5 | 6 | 7 | def get_random_hash(): 8 | return uuid.uuid4().hex[-4:] 9 | 10 | 11 | def generate_slug(*args, **kwargs): 12 | return get_random_hash() 13 | 14 | 15 | class Todo(models.Model): 16 | MAX_TITLE_LENGTH = 24 17 | MAX_TENANT_LENGTH = 16 18 | 19 | title = models.CharField( 20 | max_length=MAX_TITLE_LENGTH, 21 | null=False, 22 | blank=False, 23 | validators=(), 24 | ) 25 | 26 | description = models.TextField() 27 | 28 | is_done = models.BooleanField( 29 | null=False, 30 | blank=False, 31 | default=False, 32 | ) 33 | 34 | slug = models.SlugField( 35 | editable=False, 36 | ) 37 | 38 | tenant = models.CharField( 39 | max_length=MAX_TENANT_LENGTH, 40 | null=True, 41 | blank=True, 42 | default=None, 43 | ) 44 | 45 | def save(self, *args, **kwargs): 46 | self.slug = slugify(self.title) + get_random_hash() 47 | return super().save(*args, **kwargs) 48 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from class_based_views_advanced.web.views import CreateTodoView, ListTodoView, DetailTodoView 4 | 5 | urlpatterns = ( 6 | # path("create/", create_todo), 7 | 8 | path("", ListTodoView.as_view(), name="todos-list"), 9 | 10 | path("create/", CreateTodoView.as_view(), name="todos-create"), 11 | 12 | path("/", DetailTodoView.as_view(), name="todos-detail"), 13 | path("/", DetailTodoView.as_view(), name="todos-detail"), 14 | path("//", DetailTodoView.as_view(), name="todos-detail"), 15 | ) 16 | -------------------------------------------------------------------------------- /class_based_views_advanced/class_based_views_advanced/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for class_based_views_advanced project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "class_based_views_advanced.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /class_based_views_advanced/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault( 10 | "DJANGO_SETTINGS_MODULE", "class_based_views_advanced.settings" 11 | ) 12 | try: 13 | from django.core.management import execute_from_command_line 14 | except ImportError as exc: 15 | raise ImportError( 16 | "Couldn't import Django. Are you sure it's installed and " 17 | "available on your PYTHONPATH environment variable? Did you " 18 | "forget to activate a virtual environment?" 19 | ) from exc 20 | execute_from_command_line(sys.argv) 21 | 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /class_based_views_advanced/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 22 | 23 | {% block content %} 24 | {% endblock %} 25 | 26 | 27 | {% block scripts_body_end %} 28 | {% endblock %} 29 | 30 | -------------------------------------------------------------------------------- /class_based_views_advanced/templates/web/create_todo.html: -------------------------------------------------------------------------------- 1 |
2 | {{ form.as_p }} 3 | 4 | 5 | 6 | {% csrf_token %} 7 |
-------------------------------------------------------------------------------- /class_based_views_advanced/templates/web/detail_todo.html: -------------------------------------------------------------------------------- 1 | {{ object }} 2 | 3 | {{ todo }} -------------------------------------------------------------------------------- /class_based_views_advanced/templates/web/todo_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |

{{ title }}

5 | 6 |
7 | {{ filter_form }} 8 | 9 | 10 |
11 | 12 | 17 | 18 | 25 | 26 | 43 | {% endblock %} 44 | 45 | {% block scripts_body_end %} 46 | 84 | {% endblock %} -------------------------------------------------------------------------------- /class_based_views_basics/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/class_based_views_basics.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /class_based_views_basics/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_basics/class_based_views_basics/__init__.py -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for class_based_views_basics project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "class_based_views_basics.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_basics/class_based_views_basics/custom_class_base_views/__init__.py -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CustomClassBaseViewsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "class_based_views_basics.custom_class_base_views" 7 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_basics/class_based_views_basics/custom_class_base_views/migrations/__init__.py -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from class_based_views_basics.custom_class_base_views.views import index, IndexView 4 | 5 | urlpatterns = ( 6 | path("", index, name='ccbc_index'), 7 | path("cbv/", IndexView.as_view(), name='ccbc_cbv_index'), 8 | ) -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/custom_class_base_views/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | from django.shortcuts import render 3 | 4 | 5 | class BaseView: 6 | @classmethod 7 | def as_view(cls): 8 | def view(request, *args, **kwargs): 9 | self = cls() 10 | 11 | # dispatch 12 | if request.method == "GET": 13 | return self.get(request, *args, **kwargs) 14 | else: 15 | return self.post(request, *args, **kwargs) 16 | 17 | return view 18 | 19 | # BaseView.as_view() -> cls = BaseView 20 | # IndexView.as_view() -> cls = IndexView 21 | 22 | class IndexView(BaseView): 23 | def get(self, request): 24 | return HttpResponse("It works with CBVs!") 25 | 26 | 27 | def index(request): 28 | return HttpResponse("IT works with FBVs!") 29 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.static import static 3 | from django.contrib import admin 4 | from django.urls import path, include 5 | 6 | urlpatterns = [ 7 | path("admin/", admin.site.urls), 8 | path("", include("class_based_views_basics.web.urls")), 9 | path("custom/", include("class_based_views_basics.custom_class_base_views.urls")) 10 | ] 11 | 12 | if settings.DEBUG: 13 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 14 | 15 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_basics/class_based_views_basics/web/__init__.py -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "class_based_views_basics.web" 7 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from class_based_views_basics.web.models import Todo 4 | 5 | 6 | class TodoBaseForm(forms.ModelForm): 7 | class Meta: 8 | model = Todo 9 | fields = "__all__" 10 | 11 | def clean_title(self): 12 | pass 13 | 14 | # def save(self, commit=True): 15 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-07 17:48 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | initial = True 9 | 10 | dependencies = [] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name="Todo", 15 | fields=[ 16 | ( 17 | "id", 18 | models.BigAutoField( 19 | auto_created=True, 20 | primary_key=True, 21 | serialize=False, 22 | verbose_name="ID", 23 | ), 24 | ), 25 | ( 26 | "title", 27 | models.TextField( 28 | max_length=24, 29 | validators=[django.core.validators.MinLengthValidator(3)], 30 | ), 31 | ), 32 | ("date_created", models.DateTimeField(auto_now_add=True)), 33 | ("deadline", models.DateTimeField(blank=True, null=True)), 34 | ], 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/migrations/0002_category_todo_category.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-07 18:50 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ("web", "0001_initial"), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name="Category", 16 | fields=[ 17 | ( 18 | "id", 19 | models.BigAutoField( 20 | auto_created=True, 21 | primary_key=True, 22 | serialize=False, 23 | verbose_name="ID", 24 | ), 25 | ), 26 | ( 27 | "name", 28 | models.CharField( 29 | max_length=32, 30 | validators=[django.core.validators.MinLengthValidator(3)], 31 | ), 32 | ), 33 | ], 34 | ), 35 | migrations.AddField( 36 | model_name="todo", 37 | name="category", 38 | field=models.ForeignKey( 39 | blank=True, 40 | null=True, 41 | on_delete=django.db.models.deletion.DO_NOTHING, 42 | to="web.category", 43 | ), 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/migrations/0003_alter_todo_category.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-07 18:50 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ("web", "0002_category_todo_category"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name="todo", 15 | name="category", 16 | field=models.ForeignKey( 17 | default=1, 18 | on_delete=django.db.models.deletion.DO_NOTHING, 19 | to="web.category", 20 | ), 21 | preserve_default=False, 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/class_based_views_basics/class_based_views_basics/web/migrations/__init__.py -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/models.py: -------------------------------------------------------------------------------- 1 | from django.core.validators import MinLengthValidator 2 | from django.db import models 3 | 4 | 5 | class Category(models.Model): 6 | MIN_NAME_LENGHT = 3 7 | MAX_NAME_LENGHT = 32 8 | name = models.CharField( 9 | max_length=MAX_NAME_LENGHT, 10 | validators=( 11 | MinLengthValidator(MIN_NAME_LENGHT), 12 | ) 13 | ) 14 | 15 | 16 | class Todo(models.Model): 17 | MIN_TITLE_LENGTH = 3 18 | MAX_TITLE_LENGTH = 24 19 | title = models.TextField( 20 | max_length=MAX_TITLE_LENGTH, 21 | validators=( 22 | MinLengthValidator(MIN_TITLE_LENGTH), 23 | ), 24 | null=False, 25 | blank=False, 26 | ) 27 | 28 | date_created = models.DateTimeField( 29 | auto_now_add=True, 30 | ) 31 | 32 | deadline = models.DateTimeField( 33 | null=True, 34 | blank=True, 35 | ) 36 | 37 | category = models.ForeignKey( 38 | Category, 39 | on_delete=models.DO_NOTHING, 40 | null=False, 41 | blank=False, 42 | ) 43 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from django.views.generic import TemplateView 3 | 4 | from class_based_views_basics.web.views import index, IndexRawView, IndexView, TodoCreateView, TodoDetailsView 5 | 6 | urlpatterns = ( 7 | path("", IndexView.as_view(), name="index"), 8 | path("initkwargs/", TemplateView.as_view(template_name="web/index.html")), 9 | 10 | path("todos/create/", TodoCreateView.as_view(), name="todo_create"), 11 | path("todos//", TodoDetailsView.as_view(), name="todo_details"), 12 | 13 | path("raw/", IndexRawView.as_view(), name="index_raw"), 14 | path("raw//", IndexRawView.as_view(), name="index_raw_with_pk"), 15 | ) 16 | -------------------------------------------------------------------------------- /class_based_views_basics/class_based_views_basics/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for class_based_views_basics project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "class_based_views_basics.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /class_based_views_basics/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "class_based_views_basics.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /class_based_views_basics/templates/web/create_todo.html: -------------------------------------------------------------------------------- 1 |
    2 | {% for todo in todo_list %} 3 |
  • 4 | {{ todo.title }} - {{ todo.deadline }} 5 |
  • 6 | {% endfor %} 7 |
8 | 9 |
10 | {{ form.as_p }} 11 | 12 | 13 | {% csrf_token %} 14 |
-------------------------------------------------------------------------------- /class_based_views_basics/templates/web/details_todo.html: -------------------------------------------------------------------------------- 1 |

{{ todo.title }}

2 |

{{ todo.deadline }}

-------------------------------------------------------------------------------- /class_based_views_basics/templates/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 12 |

It works!

13 |

{{ title }}

14 |

Static time: {{ static_time|time:"s" }}

15 |

Dynamic time: {{ dynamic_time|time:"s" }}

16 | 17 |
    18 | {% for todo in todo_list %} 19 |
  • 20 | {{ todo.title }} - {{ todo.deadline }} 21 |
  • 22 | {% endfor %} 23 |
24 | 25 | -------------------------------------------------------------------------------- /class_based_views_basics/templates/web/list_todos.html: -------------------------------------------------------------------------------- 1 | {% for todo in todo_list %} 2 | 3 | {% endfor %} -------------------------------------------------------------------------------- /django101/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /django101/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://localhost:5432/ 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /django101/.idea/django101.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /django101/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /django101/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /django101/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /django101/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /django101/django101/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/django101/django101/__init__.py -------------------------------------------------------------------------------- /django101/django101/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for django101 project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django101.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /django101/django101/tasks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/django101/django101/tasks/__init__.py -------------------------------------------------------------------------------- /django101/django101/tasks/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from django101.tasks.models import Task 4 | 5 | 6 | # admin.site.register(Task) 7 | 8 | @admin.register(Task) 9 | class TaskAdmin(admin.ModelAdmin): 10 | list_display = ('id', 'title', 'done') 11 | list_filter = ('done',) 12 | -------------------------------------------------------------------------------- /django101/django101/tasks/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TasksConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "django101.tasks" 7 | -------------------------------------------------------------------------------- /django101/django101/tasks/middlewares.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def measure_time(get_response): 5 | def middleware(request, *args, **kwargs): 6 | start_time = time.time() 7 | 8 | result = get_response(request, *args, **kwargs) 9 | 10 | end_time = time.time() 11 | 12 | print(f"Request took {end_time - start_time} seconds") 13 | 14 | return result 15 | 16 | return middleware 17 | -------------------------------------------------------------------------------- /django101/django101/tasks/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-10 17:48 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | initial = True 8 | 9 | dependencies = [] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name="Task", 14 | fields=[ 15 | ( 16 | "id", 17 | models.BigAutoField( 18 | auto_created=True, 19 | primary_key=True, 20 | serialize=False, 21 | verbose_name="ID", 22 | ), 23 | ), 24 | ("title", models.CharField(max_length=120)), 25 | ("description", models.TextField()), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /django101/django101/tasks/migrations/0002_task_done.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-10 17:48 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("tasks", "0001_initial"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="task", 14 | name="done", 15 | field=models.BooleanField(default=False), 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /django101/django101/tasks/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/django101/django101/tasks/migrations/__init__.py -------------------------------------------------------------------------------- /django101/django101/tasks/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Task(models.Model): 5 | # CharField => string (VARCHAR, varying char, ...) 6 | title = models.CharField( 7 | max_length=120, 8 | ) 9 | 10 | description = models.TextField() 11 | 12 | done = models.BooleanField(default=False) 13 | -------------------------------------------------------------------------------- /django101/django101/tasks/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django101/django101/tasks/urls.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Do always when creating new Django App: 3 | 4 | 1. (Optional) Move to project directory 5 | 2. Create `urls.py` file 6 | 3. Register this Django app's `urls.py` in the project's `urls.py` file 7 | 4. Register this Django app in `settings.py`'s `INSTALLED_APPS` 8 | 9 | ''' 10 | from django.urls import path 11 | 12 | from .views import index 13 | 14 | urlpatterns = ( 15 | path("", index), 16 | ) 17 | -------------------------------------------------------------------------------- /django101/django101/tasks/views.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from django import http 4 | from django.http import HttpResponse 5 | from django.shortcuts import render 6 | 7 | from django101.tasks.models import Task 8 | 9 | """ 10 | # FBV: 11 | 1. A function that has one or more params 12 | 2. Returns a response 13 | """ 14 | 15 | 16 | # 17 | # def index(request): 18 | # name = request.GET.get("name", "NONAME") 19 | # 20 | # content = "

It works!

" + \ 21 | # f"

You are welcome to my project, {name}!

" + \ 22 | # "
  • 1
  • 2
" 23 | # 24 | # return http.HttpResponse(content) 25 | # 26 | # # headers={ 27 | # # "Content-Type": "application/json", 28 | # # } 29 | 30 | # def index(request): 31 | # title_filter = request.GET.get("filter", None) 32 | # tasks = Task.objects.all() 33 | # 34 | # if title_filter: 35 | # tasks = tasks.filter(title__icontains=title_filter.lower()) 36 | # 37 | # if not tasks: 38 | # return HttpResponse("

No tasks!!!

") 39 | # 40 | # result = [] 41 | # 42 | # for task in tasks: 43 | # result.append(f""" 44 | #
  • 45 | #

    {task.title}

    46 | #

    {task.description}

    47 | #
  • 48 | # """) 49 | # 50 | # ul = f"
      {''.join(result)}
    " 51 | # 52 | # content = f""" 53 | #

    {len(tasks)} Tasks

    54 | # {ul} 55 | # """ 56 | # return HttpResponse(content) 57 | 58 | def index(request): 59 | title_filter = request.GET.get("title_filter", "") 60 | tasks = Task.objects.all() 61 | 62 | if title_filter: 63 | tasks = tasks.filter(title__icontains=title_filter.lower()) 64 | 65 | context = { 66 | "title": "The tasks app!!!", 67 | "task_list": tasks, 68 | "task_list_count": tasks.count(), 69 | "title_filter": title_filter, 70 | } 71 | 72 | return render( 73 | request, 74 | "tasks/index.html", 75 | context, 76 | ) 77 | -------------------------------------------------------------------------------- /django101/django101/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URL configuration for django101 project. 3 | 4 | The `urlpatterns` list routes URLs to views. For more information please see: 5 | https://docs.djangoproject.com/en/4.2/topics/http/urls/ 6 | Examples: 7 | Function views 8 | 1. Add an import: from my_app import views 9 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 10 | Class-based views 11 | 1. Add an import: from other_app.views import Home 12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 13 | Including another URLconf 14 | 1. Import the include() function: from django.urls import include, path 15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 16 | """ 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | 20 | urlpatterns = ( 21 | path("admin/", admin.site.urls), 22 | 23 | # prefix "" for all URLs in `django101.tasks.urls`, i.e. no prefix 24 | path("", include("django101.tasks.urls")), 25 | 26 | # prefix "ala-bala/" for all URLs in `django101.tasks.urls` 27 | path("ala-bala/", include("django101.tasks.urls")), 28 | ) 29 | 30 | # https://HOST:PORT/FULL/PATH?query=params&other=other_params#fragment 31 | -------------------------------------------------------------------------------- /django101/django101/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django101 project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django101.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /django101/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django101.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /django101/templates/tasks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |

    {{ title }}

    10 | 11 | {% if task_list_count == 0 %} 12 |

    No Tasks

    13 | {% else %} 14 |

    Tasks: {{ task_list_count }}

    15 | {% endif %} 16 | 17 |
    18 | 24 | 25 |
    26 | 27 |
      28 | {% for task in task_list %} 29 |
    • 30 |

      {{ task.title }}

      31 |

      {{ task.description }}

      32 |
    • 33 | {% endfor %} 34 |
    35 | 36 | 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | services: 4 | postgres: 5 | image: postgres 6 | restart: always 7 | ports: 8 | - "5432:5432" 9 | environment: 10 | POSTGRES_PASSWORD: 1123QwER 11 | POSTGRES_USER: postgres 12 | POSTGRES_DB: petstagram_db 13 | PGDATA: /var/lib/postgresql/data/pgdata 14 | volumes: 15 | - ./postgresql:/var/lib/postgresql/data 16 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/exam_prep_my_music_app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/albums/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AlbumsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "exam_prep_my_music_app.albums" 7 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-19 16:49 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | initial = True 10 | 11 | dependencies = [ 12 | ("profiles", "0001_initial"), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name="Album", 18 | fields=[ 19 | ( 20 | "id", 21 | models.BigAutoField( 22 | auto_created=True, 23 | primary_key=True, 24 | serialize=False, 25 | verbose_name="ID", 26 | ), 27 | ), 28 | ("name", models.CharField(max_length=30, unique=True)), 29 | ("artist_name", models.CharField(max_length=30)), 30 | ( 31 | "genre", 32 | models.CharField( 33 | choices=[ 34 | ("Pop Music", "Pop Music"), 35 | ("Jazz Music", "Jazz Music"), 36 | ("Rock Music", "Rock Music"), 37 | ("Country Music", "Country Music"), 38 | ("R&B Music", "R&B Music"), 39 | ("Dance Music", "Dance Music"), 40 | ("Hip Hop Music", "Hip Hop Music"), 41 | ("Other", "Other"), 42 | ], 43 | max_length=30, 44 | ), 45 | ), 46 | ("description", models.TextField(blank=True, null=True)), 47 | ("image_url", models.URLField()), 48 | ( 49 | "price", 50 | models.FloatField( 51 | validators=[django.core.validators.MinValueValidator(0.0)] 52 | ), 53 | ), 54 | ( 55 | "owner", 56 | models.ForeignKey( 57 | on_delete=django.db.models.deletion.DO_NOTHING, 58 | to="profiles.profile", 59 | ), 60 | ), 61 | ], 62 | ), 63 | ] 64 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/migrations/0002_alter_album_artist_name_alter_album_image_url_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-19 19:26 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ("profiles", "0001_initial"), 10 | ("albums", "0001_initial"), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name="album", 16 | name="artist_name", 17 | field=models.CharField(max_length=30, verbose_name="Artist"), 18 | ), 19 | migrations.AlterField( 20 | model_name="album", 21 | name="image_url", 22 | field=models.URLField(verbose_name="Image URL"), 23 | ), 24 | migrations.AlterField( 25 | model_name="album", 26 | name="name", 27 | field=models.CharField( 28 | max_length=30, unique=True, verbose_name="Album Name" 29 | ), 30 | ), 31 | migrations.AlterField( 32 | model_name="album", 33 | name="owner", 34 | field=models.ForeignKey( 35 | on_delete=django.db.models.deletion.CASCADE, to="profiles.profile" 36 | ), 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/migrations/0003_alter_album_genre.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-19 19:41 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("albums", "0002_alter_album_artist_name_alter_album_image_url_and_more"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name="album", 14 | name="genre", 15 | field=models.CharField( 16 | choices=[ 17 | ("Pop Music", "Genre Pop"), 18 | ("Jazz Music", "Genre Jazz"), 19 | ("Rock Music", "Genre Rock"), 20 | ("Country Music", "Genre Country"), 21 | ("R&B Music", "Genre Rnb"), 22 | ("Dance Music", "Genre Dance"), 23 | ("Hip Hop Music", "Genre Hip Hop"), 24 | ("Other", "Genre Other"), 25 | ], 26 | max_length=30, 27 | ), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/albums/migrations/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/models.py: -------------------------------------------------------------------------------- 1 | from django.core.validators import MinValueValidator 2 | from django.db import models 3 | 4 | from exam_prep_my_music_app.profiles.models import Profile 5 | 6 | """ 7 | - Owner 8 | - This field should remain hidden in forms. 9 | """ 10 | 11 | 12 | class Genre(models.TextChoices): 13 | GENRE_POP = "Pop Music" 14 | GENRE_JAZZ = "Jazz Music" 15 | GENRE_ROCK = "Rock Music" 16 | GENRE_COUNTRY = "Country Music" 17 | GENRE_RNB = "R&B Music" 18 | GENRE_DANCE = "Dance Music" 19 | GENRE_HIP_HOP = "Hip Hop Music" 20 | GENRE_OTHER = "Other" 21 | 22 | 23 | class Album(models.Model): 24 | MAX_NAME_LENGTH = 30 25 | MAX_ARTIST_NAME_LENGTH = 30 26 | MAX_GENRE_LENGTH = 30 27 | 28 | MIN_PRICE = 0.0 29 | 30 | name = models.CharField( 31 | max_length=MAX_NAME_LENGTH, 32 | unique=True, 33 | null=False, 34 | blank=False, 35 | verbose_name="Album Name", 36 | ) 37 | 38 | artist_name = models.CharField( 39 | max_length=MAX_ARTIST_NAME_LENGTH, 40 | null=False, 41 | blank=False, 42 | verbose_name="Artist", 43 | ) 44 | 45 | genre = models.CharField( 46 | max_length=MAX_GENRE_LENGTH, 47 | choices=Genre.choices, 48 | null=False, 49 | blank=False, 50 | ) 51 | 52 | description = models.TextField( 53 | null=True, 54 | blank=True, 55 | ) 56 | 57 | image_url = models.URLField( 58 | null=False, 59 | blank=False, 60 | verbose_name="Image URL", 61 | ) 62 | 63 | price = models.FloatField( 64 | null=False, 65 | blank=False, 66 | validators=( 67 | MinValueValidator(MIN_PRICE), 68 | ) 69 | ) 70 | 71 | owner = models.ForeignKey( 72 | Profile, 73 | on_delete=models.CASCADE, 74 | ) 75 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | 3 | from exam_prep_my_music_app.albums.views import CreateAlbumView, DetailAlbumView, EditAlbumView, DeleteAlbumView 4 | 5 | urlpatterns = ( 6 | path("add/", CreateAlbumView.as_view(), name="create_album"), 7 | path( 8 | "/", 9 | include([ 10 | path("details/", DetailAlbumView.as_view(), name="details_album"), 11 | path("edit/", EditAlbumView.as_view(), name="edit_album"), 12 | path("delete/", DeleteAlbumView.as_view(), name="delete_album"), 13 | ]) 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/albums/views.py: -------------------------------------------------------------------------------- 1 | from django.forms import modelform_factory 2 | from django.urls import reverse_lazy 3 | from django.views import generic as views 4 | 5 | from exam_prep_my_music_app.albums.models import Album 6 | from exam_prep_my_music_app.common.profile_helpers import get_profile 7 | 8 | 9 | class AlbumFormViewMixin: 10 | def get_form(self, form_class=None): 11 | form = super().get_form(form_class=form_class) 12 | # Can be moved a mixin 13 | form.fields["name"].widget.attrs["placeholder"] = "Album Name" 14 | form.fields["artist_name"].widget.attrs["placeholder"] = "Artist" 15 | form.fields["description"].widget.attrs["placeholder"] = "Description" 16 | form.fields["image_url"].widget.attrs["placeholder"] = "Image URL" 17 | form.fields["price"].widget.attrs["placeholder"] = "Price" 18 | 19 | return form 20 | 21 | 22 | class ReadonlyViewMixin: 23 | def get_form(self, form_class=None): 24 | form = super().get_form(form_class=form_class) 25 | 26 | for field in form.fields.values(): 27 | field.widget.attrs["readonly"] = "readonly" 28 | 29 | return form 30 | 31 | 32 | class CreateAlbumView(AlbumFormViewMixin, views.CreateView): 33 | queryset = Album.objects.all() 34 | fields = ("name", "artist_name", "genre", "description", "image_url", "price") 35 | template_name = "albums/album-add.html" 36 | success_url = reverse_lazy("index") 37 | 38 | def form_valid(self, form): 39 | form.instance.owner_id = get_profile().pk 40 | return super().form_valid(form) 41 | 42 | 43 | class DetailAlbumView(views.DetailView): 44 | queryset = Album.objects.all() 45 | template_name = "albums/album-details.html" 46 | 47 | 48 | class EditAlbumView(AlbumFormViewMixin, views.UpdateView): 49 | queryset = Album.objects.all() 50 | template_name = "albums/album-edit.html" 51 | fields = ("name", "artist_name", "genre", "description", "image_url", "price") 52 | success_url = reverse_lazy("index") 53 | 54 | 55 | class DeleteAlbumView(ReadonlyViewMixin, views.DeleteView): 56 | queryset = Album.objects.all() 57 | template_name = "albums/album-delete.html" 58 | success_url = reverse_lazy("index") 59 | form_class = modelform_factory( 60 | Album, 61 | fields=("name", "artist_name", "genre", "description", "image_url", "price"), 62 | ) 63 | 64 | def get_form_kwargs(self): 65 | kwargs = super().get_form_kwargs() 66 | kwargs["instance"] = self.object 67 | return kwargs 68 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for exam_prep_my_music_app project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exam_prep_my_music_app.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/common/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/common/profile_helpers.py: -------------------------------------------------------------------------------- 1 | from exam_prep_my_music_app.profiles.models import Profile 2 | 3 | 4 | def get_profile(): 5 | return Profile.objects.first() 6 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/profiles/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ProfilesConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "exam_prep_my_music_app.profiles" 7 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-19 16:32 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | initial = True 9 | 10 | dependencies = [] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name="Profile", 15 | fields=[ 16 | ( 17 | "id", 18 | models.BigAutoField( 19 | auto_created=True, 20 | primary_key=True, 21 | serialize=False, 22 | verbose_name="ID", 23 | ), 24 | ), 25 | ( 26 | "username", 27 | models.CharField( 28 | max_length=15, 29 | validators=[django.core.validators.MinLengthValidator(2)], 30 | ), 31 | ), 32 | ("email", models.EmailField(max_length=254)), 33 | ("age", models.PositiveIntegerField(blank=True, null=True)), 34 | ], 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/migrations/0002_alter_profile_username.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.10 on 2024-02-19 19:37 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | import exam_prep_my_music_app.profiles.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ("profiles", "0001_initial"), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name="profile", 16 | name="username", 17 | field=models.CharField( 18 | max_length=15, 19 | validators=[ 20 | django.core.validators.MinLengthValidator(2), 21 | exam_prep_my_music_app.profiles.models.validate_username, 22 | ], 23 | ), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/profiles/migrations/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/models.py: -------------------------------------------------------------------------------- 1 | from django.core.validators import MinLengthValidator 2 | from django.db import models 3 | 4 | from exam_prep_my_music_app.profiles.validators import validate_username 5 | 6 | 7 | class Profile(models.Model): 8 | MIN_USERNAME_LENGTH = 2 9 | MAX_USERNAME_LENGTH = 15 10 | 11 | username = models.CharField( 12 | max_length=MAX_USERNAME_LENGTH, 13 | validators=( 14 | MinLengthValidator(MIN_USERNAME_LENGTH), 15 | validate_username, 16 | ), 17 | null=False, 18 | blank=False, 19 | ) 20 | 21 | email = models.EmailField( 22 | null=False, 23 | blank=False, 24 | ) 25 | 26 | age = models.PositiveIntegerField( 27 | null=True, 28 | blank=True, 29 | ) 30 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from exam_prep_my_music_app.profiles.views import DetailProfileView, DeleteProfileView 4 | 5 | urlpatterns = ( 6 | path("details/", DetailProfileView.as_view(), name="details_profile"), 7 | path("delete/", DeleteProfileView.as_view(), name="delete_profile"), 8 | ) 9 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/validators.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | 4 | def validate_username(username): 5 | is_valid = all(ch.isalnum() or ch == '_' for ch in username) 6 | 7 | if not is_valid: 8 | raise ValidationError("Ensure this value contains only letters, numbers, and underscore.") 9 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/profiles/views.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse_lazy 2 | from django.views import generic as views 3 | 4 | from exam_prep_my_music_app.common.profile_helpers import get_profile 5 | 6 | 7 | class DetailProfileView(views.DetailView): 8 | template_name = "profiles/profile-details.html" 9 | 10 | def get_object(self, queryset=None): 11 | return get_profile() 12 | 13 | 14 | class DeleteProfileView(views.DeleteView): 15 | template_name = "profiles/profile-delete.html" 16 | success_url = reverse_lazy("index") 17 | 18 | def get_object(self, queryset=None): 19 | return get_profile() 20 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | urlpatterns = [ 5 | path("admin/", admin.site.urls), 6 | 7 | path("", include('exam_prep_my_music_app.web.urls')), 8 | path("album/", include('exam_prep_my_music_app.albums.urls')), 9 | path("profile/", include('exam_prep_my_music_app.profiles.urls')), 10 | ] 11 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/web/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "exam_prep_my_music_app.web" 7 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from exam_prep_my_music_app.profiles.models import Profile 4 | 5 | 6 | class CreateProfileForm(forms.ModelForm): 7 | class Meta: 8 | model = Profile 9 | fields = ("username", "email", "age") 10 | 11 | widgets = { 12 | "username": forms.TextInput( 13 | attrs={ 14 | "placeholder": "Username" 15 | }, 16 | ), 17 | "email": forms.EmailInput( 18 | attrs={ 19 | "placeholder": "Email" 20 | }, 21 | ), 22 | "age": forms.NumberInput( 23 | attrs={ 24 | "placeholder": "Age", 25 | }, 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/exam_prep_my_music_app/web/migrations/__init__.py -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from exam_prep_my_music_app.web.views import index, create_profile 4 | 5 | urlpatterns = ( 6 | path("", index, name="index"), 7 | path("create-profile/", create_profile, name="create_profile"), 8 | ) 9 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/web/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | 3 | from exam_prep_my_music_app.albums.models import Album 4 | from exam_prep_my_music_app.common.profile_helpers import get_profile 5 | from exam_prep_my_music_app.web.forms import CreateProfileForm 6 | 7 | 8 | def create_profile(request): 9 | form = CreateProfileForm(request.POST or None) 10 | 11 | if form.is_valid(): 12 | form.save() 13 | return redirect("index") 14 | 15 | context = { 16 | "form": form, 17 | "no_nav": True, 18 | } 19 | 20 | return render(request, "web/home-no-profile.html", context) 21 | 22 | 23 | def index(request): 24 | profile = get_profile() 25 | 26 | if profile is None: 27 | return create_profile(request) 28 | 29 | context = { 30 | "albums": Album.objects.all(), 31 | } 32 | 33 | return render(request, "web/home-with-profile.html", context) 34 | 35 | # class IndexView(views.TemplateView): 36 | # def get_template_names(self): 37 | # if get_profile() is None: 38 | # return ["web/home-no-profile.html"] 39 | # return ["web/home-with-profile.html"] 40 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/exam_prep_my_music_app/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for exam_prep_my_music_app project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exam_prep_my_music_app.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exam_prep_my_music_app.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/css/details.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | height: 400px; 3 | width: 1000px; 4 | border-radius: 7px 7px 7px 7px; 5 | box-shadow: 0 0 1.5px 3px gray; 6 | margin: 30px auto 200px; 7 | } 8 | 9 | .albumCover, .profilePage { 10 | float: left; 11 | height: 100%; 12 | width: auto; 13 | margin-right: 20px; 14 | } 15 | 16 | .albumCover img, .profilePage img { 17 | border-radius: 12px 0 0 7px; 18 | height: 100%; 19 | } 20 | 21 | .albumText, .profileText { 22 | padding-left: 10px; 23 | padding-top: 20px; 24 | } 25 | 26 | .albumText h1, .profileText h1 { 27 | color:gainsboro; 28 | font-weight: bolder; 29 | font-size: 28px; 30 | } 31 | 32 | .albumText h3 { 33 | font-size: 18px; 34 | color: gray; 35 | letter-spacing: 0.2em; 36 | margin: 8px 0 0 18px; 37 | } 38 | 39 | .albumText h4 { 40 | margin: 8px 0 10px 18px; 41 | font-size: 16px; 42 | color: #9F9991; 43 | letter-spacing: 0.2em; 44 | } 45 | 46 | .albumText h5 { 47 | margin: 8px 0 10px 14px; 48 | font-size: 16px; 49 | color: white; 50 | } 51 | 52 | .albumText > p, .profileText > p { 53 | height: auto; 54 | width: 100%; 55 | color: #9F9991; 56 | line-height: 1.6em; 57 | font-size: 18px; 58 | font-weight: bold; 59 | margin-right: 20px; 60 | } 61 | 62 | .actionBtn { 63 | display: flex; 64 | text-align: center; 65 | left: auto; 66 | top: auto; 67 | right: 0; 68 | bottom: 0; 69 | } 70 | 71 | .actionBtn > a { 72 | width: 200%; 73 | height: 50px; 74 | cursor: pointer; 75 | border: none; 76 | border-radius: 10px; 77 | display: inline; 78 | align-items: center; 79 | justify-content: center; 80 | background-color: #1b2845; 81 | background-image: linear-gradient(315deg, #45a29e 0%, #0d324d 74%); 82 | background-size: 200% 100%; 83 | background-position: left; 84 | background-repeat: no-repeat; 85 | transition: 500ms; 86 | color: white; 87 | font-family: "Lato", serif; 88 | font-size: 20px; 89 | margin-bottom: 10px; 90 | margin-top: 20px; 91 | padding: 10px; 92 | text-decoration: none; 93 | margin-right: 50px; 94 | } 95 | 96 | .actionBtn > a:hover { 97 | background-position: right; 98 | } -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/css/home.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('/static/images/back.jpg'); 3 | background-size: cover; 4 | } 5 | 6 | .container-inline { 7 | margin: 1rem; 8 | padding: 2rem 2rem; 9 | } 10 | 11 | nav, 12 | footer { 13 | background-color: #0B0C10; 14 | width: 100%; 15 | display: flex; 16 | font-size: 16px; 17 | justify-content: space-around; 18 | align-items: center; 19 | padding: 0 5px 0 3px; 20 | margin: 0; 21 | color: white; 22 | } 23 | 24 | nav a { 25 | text-decoration: none; 26 | color: #8f8f8f; 27 | font-size: 20px; 28 | font-weight: bolder; 29 | position: relative; 30 | margin: 20px; 31 | } 32 | 33 | nav ul { 34 | margin: 0 0 0 auto; 35 | } 36 | 37 | nav ul li { 38 | display: inline; 39 | margin: 0 2px; 40 | } 41 | 42 | li::before { 43 | display: inline; 44 | } 45 | 46 | nav a { 47 | text-decoration: none; 48 | border-radius: 50%; 49 | padding: 0.5em; 50 | color: white; 51 | } 52 | 53 | footer { 54 | position: fixed; 55 | width: 100%; 56 | left: 0; 57 | bottom: 0; 58 | padding: 15px; 59 | text-align: center; 60 | color: #c5c6c7; 61 | font-weight: bold; 62 | } 63 | 64 | nav a:hover { 65 | cursor: pointer; 66 | color: #45a29e; 67 | font-weight: bolder; 68 | } 69 | 70 | #welcomePage { 71 | float: left; 72 | width: 50%; 73 | color: #45a29e; 74 | font-size: 24px; 75 | padding: 30px; 76 | margin: 10px; 77 | 78 | } 79 | 80 | #welcomePage img { 81 | width: 80% 82 | } 83 | 84 | nav > img { 85 | width: 90px; 86 | height: 80px; 87 | margin-left: 0.2em; 88 | margin-right: 0.2em; 89 | } -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/css/login.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:100,300,400,700); 2 | 3 | fieldset { 4 | float: left; 5 | width: 50%; 6 | margin: 1em auto; 7 | padding: 2em; 8 | border-radius: 2px; 9 | border-color: #2d333b; 10 | background: #1b1f24; 11 | box-shadow: 0 2px 2px #131518; 12 | 13 | } 14 | 15 | fieldset legend { 16 | font-weight: 700; 17 | font-size: 2em; 18 | text-transform: uppercase; 19 | letter-spacing: 0.12em; 20 | text-align: center; 21 | background: #171a1e; 22 | -o-border-image: linear-gradient(180deg, rgba(255, 255, 255, 0) 50%, #2d333b 50%) 1 round; 23 | border-width: 1px; 24 | border-style: solid; 25 | display: block; 26 | width: 100%; 27 | margin: 0 auto; 28 | } 29 | 30 | input, input + label > i { 31 | border-radius: 3px; 32 | box-shadow: none; 33 | border: 1px solid #384049; 34 | background: #15171b; 35 | display: block; 36 | width: 100%; 37 | color: white; 38 | transition: all 0.3s ease; 39 | } 40 | 41 | input[type=text], input[type=number], input[type=email] { 42 | font-size: 1.2em; 43 | line-height: 1; 44 | padding: 0.3em 0.4em; 45 | margin: 0 0.5em 1em 0; 46 | } 47 | 48 | input[type=text]::-webkit-input-placeholder, input[type=number]::-webkit-input-placeholder, input[type=email]::-webkit-input-placeholder { 49 | color: #343b44; 50 | line-height: 1.2; 51 | -webkit-transition: all 0.2s ease; 52 | transition: all 0.2s ease; 53 | } 54 | 55 | input[type=text]:hover, input[type=number]:hover, input[type=email]:hover { 56 | border-color: #4e5966; 57 | } 58 | 59 | input[type=text]:focus, input[type=number]:focus, input[type=email]:focus { 60 | outline: none; 61 | border-color: #39a086; 62 | } 63 | 64 | .register { 65 | width: 150px; 66 | height: 50px; 67 | cursor: pointer; 68 | border: none; 69 | border-radius: 10px; 70 | display: inline; 71 | align-items: center; 72 | justify-content: center; 73 | background-color: #1b2845; 74 | background-image: linear-gradient(315deg, #45a29e 0%, #0d324d 74%); 75 | background-size: 200% 100%; 76 | background-position: left; 77 | background-repeat: no-repeat; 78 | transition: 500ms; 79 | color: white; 80 | font-family: "Lato", serif; 81 | font-size: 20px; 82 | margin-bottom: 5px; 83 | margin-top: 20px; 84 | } 85 | 86 | #registerPage { 87 | font-family: "Lato", serif; 88 | font-size: 16px; 89 | color: #aab2bd; 90 | padding: 1em 0 10em; 91 | } 92 | 93 | * { 94 | box-sizing: border-box; 95 | } 96 | 97 | p { 98 | padding-top: 20px; 99 | } -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/css/style.css: -------------------------------------------------------------------------------- 1 | @import "typography.css"; 2 | @import "home.css"; 3 | @import "login.css"; 4 | @import "create.css"; 5 | @import "catalog.css"; 6 | @import "details.css"; -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/css/typography.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: 'Lato', serif; 3 | font-size: 16px; 4 | box-sizing: border-box; 5 | } 6 | 7 | *, 8 | *::before, 9 | *::after { 10 | margin: auto; 11 | padding: 0; 12 | box-sizing: inherit; 13 | line-height: 1.3; 14 | } -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/BrandiCarlile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/BrandiCarlile.png -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/Lorde.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/Lorde.jpg -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/back.jpg -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/headphones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/headphones.png -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/musicIcons.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/musicIcons.webp -------------------------------------------------------------------------------- /exam_prep_my_music_app/staticfiles/images/pinkFloyd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/exam_prep_my_music_app/staticfiles/images/pinkFloyd.jpg -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/albums/album-add.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block main_content %} 4 |
    5 |
    6 |
    7 | Add Album 8 |
    9 | {{ form }} 10 | 11 | {% csrf_token %} 12 |
    13 |
    14 |
    15 |
    16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/albums/album-delete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block main_content %} 4 |
    5 |
    6 |
    7 | Delete Album 8 |
    9 | {{ form }} 10 | 11 | {% csrf_token %} 12 |
    13 |
    14 |
    15 |
    16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/albums/album-details.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block main_content %} 4 |
    5 |
    6 |
    7 | 8 | {{ object.description }} 9 |
    10 | 11 |
    12 |
    13 | 14 |

    Name: {{ object.name }}

    15 |

    Artist: {{ object.artist_name }}

    16 |

    Genre: {{ object.genre }}

    17 |

    Price: ${{ object.price|floatformat:2 }}

    18 |

    19 | Description: {{ object.description }} 20 |

    21 |
    22 | 23 |
    24 | Edit 25 | Delete 26 |
    27 |
    28 |
    29 |
    30 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/albums/album-edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block main_content %} 3 |
    4 |
    5 |
    6 | Edit Album 7 |
    8 | {{ form }} 9 | 10 | {% csrf_token %} 11 |
    12 |
    13 |
    14 |
    15 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | My Music App 8 | 9 | 10 | 11 | 12 | 13 |
    14 | 15 |
    16 | 29 |
    30 | 31 | {% block main_content %} 32 | {% endblock %} 33 | 34 |
    35 |
    ©SoftUni Team 2024. All rights reserved.
    36 |
    37 | 38 |
    39 | 40 | 41 | -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/profiles/profile-delete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block main_content %} 3 | 4 |
    5 |
    6 |
    7 |

    Are you sure you want to delete your profile?

    8 |
    9 | 10 | {% csrf_token %} 11 |
    12 |
    13 |
    14 |
    15 | 16 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/profiles/profile-details.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block main_content %} 3 |
    4 |
    5 |
    6 | Profile Image 10 |
    11 | 12 |
    13 | 14 |

    Username: {{ object.username }}

    15 |

    Email: {{ object.email }}

    16 | {% if object.age %} 17 |

    Age: {{ object.age }}

    18 | {% endif %} 19 |

    Albums: {{ object.album_set.count }}

    20 |
    21 | 22 |
    23 | Delete 24 |
    25 |
    26 |
    27 | 28 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/web/home-no-profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load static %} 4 | 5 | {% block main_content %} 6 |
    7 |
    8 |
    9 |

    Welcome to

    10 |

    My Music App!

    11 |
    12 |
    13 | music-icon 14 |
    15 |
    16 | 17 | 18 |
    19 |
    20 |
    21 | Profile 22 | {{ form }} 23 | 24 | 25 | {% csrf_token %} 26 |
    27 |
    28 |
    29 |
    30 | {% endblock %} -------------------------------------------------------------------------------- /exam_prep_my_music_app/templates/web/home-with-profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block main_content %} 4 |
    5 | 6 | {% if albums %} 7 |

    All Albums

    8 | {% else %} 9 |

    No Albums in Catalog!

    10 | {% endif %} 11 | 12 | {% for album in albums %} 13 |
    14 | {{ album.description }} 15 |
    16 |
    17 |

    Name: {{ album.name }}

    18 |

    Artist: {{ album.artist_name }}

    19 |

    Genre: {{ album.genre }}

    20 |

    Price: ${{ album.price|floatformat:2 }}

    21 |
    22 |
    23 | Details 24 |
    25 |
    26 |
    27 | {% endfor %} 28 |
    29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /form_basics/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /form_basics/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /form_basics/.idea/form_basics.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /form_basics/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /form_basics/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /form_basics/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /form_basics/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /form_basics/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /form_basics/form_basics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/form_basics/form_basics/__init__.py -------------------------------------------------------------------------------- /form_basics/form_basics/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for form_basics project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "form_basics.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /form_basics/form_basics/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | urlpatterns = [ 5 | path("admin/", admin.site.urls), 6 | path("", include('form_basics.web.urls')), 7 | ] 8 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/form_basics/form_basics/web/__init__.py -------------------------------------------------------------------------------- /form_basics/form_basics/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "form_basics.web" 7 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from form_basics.web.models import Employee 4 | 5 | 6 | class DemoForm(forms.Form): 7 | firstname = forms.CharField( 8 | max_length=35, 9 | required=False, 10 | label="First Name:", 11 | help_text="Enter your first name", 12 | # disabled=True, 13 | ) 14 | 15 | lname = forms.CharField( 16 | max_length=35, 17 | required=False, 18 | label="Last Name:", 19 | widget=forms.TextInput( 20 | attrs={ 21 | "placeholder": "Enter your last name", 22 | } 23 | ) 24 | ) 25 | 26 | email = forms.EmailField( 27 | required=False, 28 | ) 29 | # @ 30 | # @gmail.com 31 | 32 | # http:// 33 | # .com 34 | 35 | age = forms.IntegerField( 36 | required=False, 37 | ) 38 | 39 | description = forms.Textarea() 40 | 41 | INTERESTS = ( 42 | (7, 'Gaming'), 43 | (6, 'Reading'), 44 | (3, 'Watching'), 45 | (11, 'Sport'), 46 | ) 47 | 48 | interests = forms.ChoiceField( 49 | choices=INTERESTS, 50 | required=False, 51 | ) 52 | 53 | interests2 = forms.IntegerField( 54 | widget=forms.Select(choices=INTERESTS), 55 | required=False, 56 | ) 57 | 58 | interests3 = forms.IntegerField( 59 | widget=forms.RadioSelect(choices=INTERESTS), 60 | ) 61 | 62 | interests4 = forms.IntegerField( 63 | widget=forms.CheckboxSelectMultiple(choices=INTERESTS), 64 | ) 65 | 66 | 67 | class EmployeeNormalForm(forms.Form): 68 | first_name = forms.CharField( 69 | max_length=Employee.MAX_FIRST_NAME_LENGTH, 70 | required=True, 71 | ) 72 | 73 | last_name = forms.CharField( 74 | max_length=35, 75 | required=True, 76 | ) 77 | 78 | role = forms.IntegerField( 79 | widget=forms.RadioSelect(choices=Employee.ROLES), 80 | required=True, 81 | ) 82 | 83 | 84 | class EmployeeForm(forms.ModelForm): 85 | # department2 = forms.CharField() 86 | 87 | class Meta: 88 | model = Employee 89 | fields = '__all__' 90 | # fields = ('first_name', 'last_name',) 91 | # exclude = ('role',) # '__all--' - `role` 92 | 93 | # help_texts 94 | # labels 95 | # error_messages 96 | 97 | labels = { 98 | 'first_name': 'First Name:', 99 | 'last_name': 'Last Name:', 100 | } 101 | 102 | widgets = { 103 | 'role': forms.RadioSelect( 104 | # attrs={ 105 | # 'disabled': 'disabled', 106 | # } 107 | ) 108 | } 109 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-22 18:58 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | initial = True 8 | 9 | dependencies = [] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name="Employee", 14 | fields=[ 15 | ( 16 | "id", 17 | models.BigAutoField( 18 | auto_created=True, 19 | primary_key=True, 20 | serialize=False, 21 | verbose_name="ID", 22 | ), 23 | ), 24 | ("first_name", models.CharField(max_length=35)), 25 | ("last_name", models.CharField(max_length=35)), 26 | ( 27 | "role", 28 | models.IntegerField( 29 | choices=[(1, "Software Developer"), (2, "QA engineer")] 30 | ), 31 | ), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/migrations/0002_department_alter_employee_first_name_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-22 19:34 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import form_basics.web.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ("web", "0001_initial"), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name="Department", 16 | fields=[ 17 | ( 18 | "id", 19 | models.BigAutoField( 20 | auto_created=True, 21 | primary_key=True, 22 | serialize=False, 23 | verbose_name="ID", 24 | ), 25 | ), 26 | ("name", models.CharField(max_length=25)), 27 | ], 28 | ), 29 | migrations.AlterField( 30 | model_name="employee", 31 | name="first_name", 32 | field=models.CharField( 33 | max_length=35, validators=[form_basics.web.models.non_empty_spaces] 34 | ), 35 | ), 36 | migrations.AddField( 37 | model_name="employee", 38 | name="department", 39 | field=models.ForeignKey( 40 | blank=True, 41 | null=True, 42 | on_delete=django.db.models.deletion.DO_NOTHING, 43 | to="web.department", 44 | ), 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/form_basics/form_basics/web/migrations/__init__.py -------------------------------------------------------------------------------- /form_basics/form_basics/web/models.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | from django.db import models 3 | 4 | 5 | def non_empty_spaces(value): 6 | if " " in value: 7 | raise ValidationError(message='Spaces not allowed') 8 | 9 | 10 | class Department(models.Model): 11 | name = models.CharField(max_length=25) 12 | 13 | 14 | class Employee(models.Model): 15 | MAX_FIRST_NAME_LENGTH = 35 16 | ROLES = ( 17 | (1, 'Software Developer'), 18 | (2, 'QA engineer'), 19 | ) 20 | 21 | first_name = models.CharField( 22 | max_length=MAX_FIRST_NAME_LENGTH, 23 | blank=False, 24 | null=False, 25 | validators=(non_empty_spaces,) 26 | ) 27 | 28 | last_name = models.CharField( 29 | max_length=35, 30 | blank=False, 31 | null=False, 32 | ) 33 | 34 | role = models.IntegerField( 35 | choices=ROLES, 36 | blank=False, 37 | null=False, 38 | ) 39 | 40 | department = models.ForeignKey( 41 | Department, 42 | on_delete=models.DO_NOTHING, 43 | null=True, 44 | blank=True, 45 | ) 46 | 47 | @property 48 | def full_name(self): 49 | return f'{self.first_name} {self.last_name}' 50 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from form_basics.web.views import index, index_models, update_employee 4 | 5 | urlpatterns = ( 6 | path("", index, name="index"), 7 | path("modelforms/", index_models, name="index-models"), 8 | path("modelforms//", update_employee, name="update-employee"), 9 | ) 10 | -------------------------------------------------------------------------------- /form_basics/form_basics/web/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | 3 | from form_basics.web.forms import DemoForm, EmployeeForm 4 | from form_basics.web.models import Employee 5 | 6 | 7 | def update_employee(request, pk): 8 | employee = Employee.objects.get(pk=pk) 9 | 10 | if request.method == 'GET': 11 | form = EmployeeForm(instance=employee) 12 | else: 13 | form = EmployeeForm(request.POST, instance=employee) 14 | if form.is_valid(): 15 | print(form.cleaned_data['department']) 16 | form.save() 17 | return redirect('index-models') 18 | 19 | context = { 20 | "form": form, 21 | "employee": employee, 22 | } 23 | 24 | return render(request, "web/employee_details.html", context) 25 | 26 | 27 | def index_models(request): 28 | if request.method == 'GET': 29 | form = EmployeeForm() 30 | else: 31 | form = EmployeeForm(request.POST) 32 | if form.is_valid(): 33 | form.save() 34 | return redirect('index-models') 35 | 36 | context = { 37 | # "normal_employee_form": EmployeeNormalForm(), 38 | "employee_form": form, 39 | "employee_list": Employee.objects.all(), 40 | } 41 | 42 | return render(request, "web/modelform_index.html", context) 43 | 44 | 45 | def index(request): 46 | form = DemoForm( 47 | request.POST or None, 48 | initial={ 49 | "lname": "Minkov", 50 | }) 51 | 52 | if request.method == 'POST': 53 | if form.is_valid(): 54 | print(form.cleaned_data) 55 | return redirect('index') 56 | 57 | context = { 58 | 'employee_form': form, 59 | } 60 | 61 | return render(request, 'web/index.html', context) 62 | 63 | # def index(request): 64 | # if request.method == 'GET': 65 | # context = { 66 | # "employee_form": EmployeeForm(), 67 | # } 68 | # 69 | # return render(request, "web/index.html", context) 70 | # 71 | # else: # request.method == 'POST': 72 | # form = EmployeeForm(request.POST) 73 | # # print(request.POST['first_name']) 74 | # if form.is_valid(): 75 | # # data is valid, populate `cleaned_data` 76 | # print(form.cleaned_data['first_name']) 77 | # # use the data 78 | # # redirect to some URL 79 | # return redirect('index') 80 | # else: 81 | # context = { 82 | # "employee_form": form, 83 | # } 84 | # 85 | # return render(request, "web/index.html", context) 86 | -------------------------------------------------------------------------------- /form_basics/form_basics/wsgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.core.wsgi import get_wsgi_application 4 | 5 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "form_basics.settings") 6 | 7 | application = get_wsgi_application() 8 | -------------------------------------------------------------------------------- /form_basics/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "form_basics.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /form_basics/templates/web/employee_details.html: -------------------------------------------------------------------------------- 1 |
    2 | {{ form.as_p }} 3 | 4 | 5 | {% csrf_token %} 6 |
    -------------------------------------------------------------------------------- /form_basics/templates/web/index.html: -------------------------------------------------------------------------------- 1 |
    2 | {{ employee_form.as_p }} 3 | 4 | {% csrf_token %} 5 | 6 |
    -------------------------------------------------------------------------------- /form_basics/templates/web/index_old.html: -------------------------------------------------------------------------------- 1 |
    2 | {# Form fields #} 3 | {# Inputs #} 4 | {# single-line text #} 5 | 6 | 7 | {# Dropdowns #} 8 | 14 | 15 | 20 | 21 | {# Old school: #} 22 | {# #} 23 |
    -------------------------------------------------------------------------------- /form_basics/templates/web/modelform_index.html: -------------------------------------------------------------------------------- 1 |

    Model form

    2 |
    3 | {{ employee_form.as_p }} 4 | 5 | 6 | {% csrf_token %} 7 |
    8 | 9 |
      10 | {% for employee in employee_list %} 11 |
    • {{ employee.full_name }} 12 | Edit 13 |
    • 14 | {% endfor %} 15 |
    16 | {#
    #} 17 | {##} 18 | {#

    Normal form

    #} 19 | {#{{ normal_employee_form.as_p }}#} 20 | {##} 21 | -------------------------------------------------------------------------------- /forms_advanced/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /forms_advanced/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /forms_advanced/.idea/forms_advanced.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /forms_advanced/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /forms_advanced/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /forms_advanced/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /forms_advanced/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /forms_advanced/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/forms_advanced/forms_advanced/__init__.py -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for forms_advanced project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "forms_advanced.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.static import static 3 | 4 | from django.contrib import admin 5 | from django.urls import path, include 6 | 7 | urlpatterns = ([ 8 | path("admin/", admin.site.urls), 9 | path("", include("forms_advanced.web.urls")), 10 | ] 11 | + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)) 12 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/forms_advanced/forms_advanced/web/__init__.py -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "forms_advanced.web" 7 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/forms.py: -------------------------------------------------------------------------------- 1 | from crispy_forms.helper import FormHelper 2 | from crispy_forms.layout import Submit 3 | from django import forms 4 | from django.forms import modelform_factory, modelformset_factory 5 | from django.urls import reverse 6 | 7 | from forms_advanced.web.models import Person 8 | 9 | 10 | class PersonForm(forms.ModelForm): 11 | class Meta: 12 | model = Person 13 | exclude = ("created_by",) 14 | 15 | labels = { 16 | "first_name": "Enter first name:", 17 | } 18 | 19 | def __init__(self, *args, **kwargs): 20 | if "user" in kwargs: 21 | self.user = kwargs.pop("user") 22 | 23 | super().__init__(*args, **kwargs) 24 | self.helper = FormHelper() 25 | self.helper.form_id = 'id-exampleForm' 26 | self.helper.form_class = 'blueForms' 27 | self.helper.form_method = 'post' 28 | self.helper.form_action = reverse("create-person") 29 | self.helper.add_input(Submit('submit', 'Create person')) 30 | 31 | def clean(self): 32 | cleaned_data = super().clean() 33 | # print(cleaned_data) 34 | 35 | return cleaned_data 36 | 37 | # def clean_first_name(self): 38 | # pass 39 | 40 | def save(self, commit=True): 41 | instance = super().save(commit=False) 42 | if self.user.is_authenticated: 43 | instance.created_by = self.user 44 | instance.save() 45 | return instance 46 | 47 | 48 | class BootstrapFormMixin: 49 | def _init_bootstrap_form(self): 50 | for _, field in self.fields: 51 | field.widget.attrs['class'] = 'form-control' 52 | 53 | 54 | class ReadonlyFieldsMixin: 55 | readonly_fields = () 56 | 57 | def _mark_readonly_fields(self): 58 | for field_name in self.readonly_fields: 59 | self.fields[field_name].widget.attrs["readonly"] = "readonly" 60 | # for _, field in self.fields.items(): 61 | # field.widget.attrs["readonly"] = "readonly" 62 | 63 | 64 | class UpdatePersonForm(ReadonlyFieldsMixin, PersonForm): 65 | readonly_fields = ("age", "last_name") 66 | 67 | def __init__(self, *args, **kwargs): 68 | super().__init__(*args, **kwargs) 69 | 70 | self._mark_readonly_fields() 71 | 72 | 73 | PersonForm2 = modelform_factory(Person, fields="__all__") 74 | 75 | PersonFormSet = modelformset_factory(Person, exclude=('created_by',), extra=2, max_num=3) 76 | 77 | # labels = { 78 | # 'first_name': 'Fname:', 79 | # } 80 | # 81 | # error_messages = { 82 | # 'first_name': { 83 | # 84 | # } 85 | # } 86 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-31 16:20 2 | 3 | from django.db import migrations, models 4 | import forms_advanced.web.models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | initial = True 9 | 10 | dependencies = [] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name="Person", 15 | fields=[ 16 | ( 17 | "id", 18 | models.BigAutoField( 19 | auto_created=True, 20 | primary_key=True, 21 | serialize=False, 22 | verbose_name="ID", 23 | ), 24 | ), 25 | ( 26 | "first_name", 27 | models.CharField( 28 | max_length=32, 29 | validators=[forms_advanced.web.models.validate_first_name], 30 | ), 31 | ), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/migrations/0002_person_age_person_last_name_alter_person_first_name.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-31 16:58 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | import forms_advanced.web.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ("web", "0001_initial"), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name="person", 16 | name="age", 17 | field=models.PositiveSmallIntegerField(default=2), 18 | preserve_default=False, 19 | ), 20 | migrations.AddField( 21 | model_name="person", 22 | name="last_name", 23 | field=models.CharField( 24 | default="asdad", 25 | max_length=32, 26 | validators=[django.core.validators.MinLengthValidator(2)], 27 | ), 28 | preserve_default=False, 29 | ), 30 | migrations.AlterField( 31 | model_name="person", 32 | name="first_name", 33 | field=models.CharField( 34 | max_length=32, 35 | validators=[ 36 | forms_advanced.web.models.validate_first_name, 37 | django.core.validators.MinLengthValidator(2), 38 | ], 39 | ), 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/migrations/0003_person_created_by.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-31 17:52 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 11 | ("web", "0002_person_age_person_last_name_alter_person_first_name"), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name="person", 17 | name="created_by", 18 | field=models.ForeignKey( 19 | null=True, 20 | on_delete=django.db.models.deletion.DO_NOTHING, 21 | to=settings.AUTH_USER_MODEL, 22 | ), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/migrations/0004_person_profile_image.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-31 18:51 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("web", "0003_person_created_by"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="person", 14 | name="profile_image", 15 | field=models.ImageField( 16 | blank=True, null=True, upload_to="web/profile_images" 17 | ), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/forms_advanced/forms_advanced/web/migrations/__init__.py -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.core.exceptions import ValidationError 3 | from django.core.validators import MinLengthValidator 4 | from django.db import models 5 | 6 | 7 | def validate_first_name(value): 8 | if " " in value: 9 | raise ValidationError("First name cannot contain a whitespace") 10 | 11 | 12 | class Person(models.Model): 13 | MIN_LENGTH_FIRST_NAME = 2 14 | MIN_LENGTH_LAST_NAME = 2 15 | 16 | MAX_LENGTH_FIRST_NAME = 32 17 | MAX_LENGTH_LAST_NAME = 32 18 | 19 | first_name = models.CharField( 20 | max_length=MAX_LENGTH_FIRST_NAME, 21 | validators=( 22 | validate_first_name, 23 | MinLengthValidator(MIN_LENGTH_FIRST_NAME), 24 | ), 25 | ) 26 | 27 | last_name = models.CharField( 28 | max_length=MAX_LENGTH_LAST_NAME, 29 | validators=( 30 | MinLengthValidator(MIN_LENGTH_LAST_NAME), 31 | ), 32 | ) 33 | 34 | age = models.PositiveSmallIntegerField() 35 | 36 | profile_image = models.ImageField( 37 | upload_to="web/profile_images", 38 | null=True, 39 | blank=True, 40 | ) 41 | 42 | created_by = models.ForeignKey( 43 | User, 44 | on_delete=models.DO_NOTHING, 45 | null=True, 46 | ) 47 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from forms_advanced.web.views import index, create_person, show_formset 4 | 5 | urlpatterns = ( 6 | path("", index, name="index"), 7 | path("person/create/", create_person, name="create-person"), 8 | path("formsets/", show_formset, name="show-formset"), 9 | ) 10 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/validators.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Django wants a callable with a single arg that raise a ValidationError if data is invalid 3 | ''' 4 | 5 | from django.core.exceptions import ValidationError 6 | 7 | 8 | def validate_email(email): 9 | if "@" not in email: 10 | raise ValidationError("Email is invalid") 11 | 12 | 13 | class FileSizeValidator: 14 | def __init__(self, max_file_size): 15 | self.max_file_size = max_file_size 16 | 17 | def __call__(self, value): 18 | if value.size > self.max_file_size: 19 | raise ValidationError(f"The size of the file should be less that {self.max_file_size} ") 20 | 21 | 22 | validate_email("doncho@minkov.com") 23 | # FileSizeValidator(5)(file) 24 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/web/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | from forms_advanced.web.forms import PersonForm, UpdatePersonForm, PersonFormSet 4 | from forms_advanced.web.models import Person 5 | 6 | 7 | def index(request): 8 | person_form = PersonForm() 9 | update_person_form = UpdatePersonForm() 10 | 11 | context = { 12 | "person_form": person_form, 13 | "update_person_form": update_person_form, 14 | "person_list": Person.objects.all(), 15 | } 16 | 17 | return render(request, "web/index.html", context) 18 | 19 | 20 | def show_formset(request): 21 | form_set = PersonFormSet() 22 | context = { 23 | "form_set": form_set, 24 | } 25 | 26 | return render(request, "web/formsets.html", context) 27 | 28 | 29 | def create_person(request): 30 | print(request.POST) 31 | form = PersonForm(request.POST, request.FILES, user=request.user) 32 | 33 | if form.is_valid(): 34 | form.save() 35 | -------------------------------------------------------------------------------- /forms_advanced/forms_advanced/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for forms_advanced project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "forms_advanced.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /forms_advanced/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "forms_advanced.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /forms_advanced/non_django_demos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/forms_advanced/non_django_demos/__init__.py -------------------------------------------------------------------------------- /forms_advanced/non_django_demos/callables.py: -------------------------------------------------------------------------------- 1 | class Person: 2 | def __init__(self, name, age): 3 | self.name = name 4 | self.age = age 5 | 6 | def __call__(self, *args, **kwargs): 7 | pass 8 | 9 | 10 | p = Person('John', 19) 11 | 12 | print(p) 13 | print(p()) 14 | -------------------------------------------------------------------------------- /forms_advanced/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.7.2 2 | crispy-bootstrap4==2023.1 3 | Django==4.2.9 4 | django-crispy-forms==2.1 5 | pillow==10.2.0 6 | sqlparse==0.4.4 7 | typing_extensions==4.9.0 8 | -------------------------------------------------------------------------------- /forms_advanced/templates/web/formsets.html: -------------------------------------------------------------------------------- 1 | {% csrf_token %} 2 | {{ form_set.management_form }} 3 | 4 | {% for form in form_set %} 5 | {{ form.as_p }} 6 | {% endfor %} -------------------------------------------------------------------------------- /forms_advanced/templates/web/index.html: -------------------------------------------------------------------------------- 1 | {% load crispy_forms_tags %} 2 | 3 |
      4 | {% for person in person_list %} 5 |
    • 6 | {% if person.profile_image %} 7 | 10 | {% else %} 11 | 14 | {% endif %} 15 | {{ person.first_name }} {{ person.last_name }} 16 |
    • 17 | {% endfor %} 18 |
    19 | 20 | 21 |

    Create form (raw)

    s 22 |
    25 | {{ person_form }} 26 | 27 | {% csrf_token %} 28 | 29 | 30 |
    31 | 32 |

    Create form (as_p)

    33 |
    34 | {{ person_form.as_p }} 35 | 36 | {% csrf_token %} 37 | 38 | 39 |
    40 | 41 |

    Create form (as_table)

    42 |
    43 | {{ person_form.as_table }} 44 | 45 | {% csrf_token %} 46 | 47 | 48 |
    49 | 50 | 51 |

    Create form (custom)

    52 | {#{% create_form action="{% url 'create-person' %}" method="post" submit_text="Create" %}#} 53 |
    54 | {% for field in person_form %} 55 | 69 | {% endfor %} 70 | 71 | {% csrf_token %} 72 | 73 | 74 |
    75 | 76 |

    Create form (crispy)

    77 | {% crispy person_form %} 78 | 79 | {##} 80 | {#

    Update form

    #} 81 | {#
    #} 82 | {# {{ update_person_form.as_p }}#} 83 | {#
    #} 84 | {##} 85 | {##} 86 | -------------------------------------------------------------------------------- /templates_advanced/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /templates_advanced/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 9 | $ProjectFileDir$ 10 | 11 | 12 | file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/org/xerial/sqlite-jdbc/3.40.1.0/sqlite-jdbc-3.40.1.0.jar 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /templates_advanced/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /templates_advanced/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /templates_advanced/.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /templates_advanced/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /templates_advanced/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates_advanced/.idea/templates_advanced.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /templates_advanced/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /templates_advanced/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_advanced.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /templates_advanced/staticfiles/about.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | color: #00f; 3 | } -------------------------------------------------------------------------------- /templates_advanced/staticfiles/main.css: -------------------------------------------------------------------------------- 1 | h1, h2, h3, h4, h5, h6 { 2 | color: purple; 3 | border-bottom: 1px solid purple; 4 | } 5 | 6 | body { 7 | font-size: 14px; 8 | } 9 | 10 | h1 { 11 | font-size: 2em; 12 | } 13 | 14 | h2 { 15 | font-size: 1.7em; 16 | } 17 | 18 | a { 19 | color: black; 20 | text-decoration: none; 21 | } 22 | 23 | a:hover { 24 | text-decoration: underline; 25 | } 26 | 27 | .btn-success { 28 | --bs-btn-bg: orange; 29 | } -------------------------------------------------------------------------------- /templates_advanced/staticfiles/sidebar.css: -------------------------------------------------------------------------------- 1 | .root { 2 | display: flex; 3 | } 4 | 5 | .root .left { 6 | min-width: 100px; 7 | background: #c5c5c5; 8 | } -------------------------------------------------------------------------------- /templates_advanced/templates/master.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | Doncho's App {% block page_title %}{% endblock %} 8 | 9 | 10 | {% block styles %} {% endblock %} 11 | 12 | {# all pages scripts #} 13 | 14 | {% block head_scripts %} 15 | {% endblock %} 16 | 17 | 18 | 19 | 20 | {% block body_start_scripts %} {% endblock %} 21 | 22 | {% include 'partials/header.html' with text='The app about cats' %} 23 | {#{% include 'partials/header.html' %}#} 24 | 25 |

    Welcome to Doncho's App!

    26 | 27 | {# `block` defines a placeholder where #} 28 | {# inheritor templates can insert their #} 29 | {# custom/specific HTML #} 30 | {% block main_content %} 31 | {# We can define a default HTML #} 32 |

    No content

    33 | {% endblock %} 34 | 35 | {% include 'partials/footer.html' %} 36 | 37 | {% block body_end_scripts %} {% endblock %} 38 | 39 | 40 | -------------------------------------------------------------------------------- /templates_advanced/templates/master_with_sidebar.html: -------------------------------------------------------------------------------- 1 | {% extends 'master.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block styles %} 6 | 7 | {% endblock %} 8 | 9 | {% block main_content %} 10 |
    11 |
    12 | {% block sidebar %} 13 | {% endblock %} 14 |
    15 |
    16 | {% block content %} 17 | {% endblock %} 18 |
    19 |
    20 | {% endblock %} -------------------------------------------------------------------------------- /templates_advanced/templates/partials/footer.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /templates_advanced/templates/partials/header.html: -------------------------------------------------------------------------------- 1 | {% load user_tags %} 2 | 3 |
    4 |
    5 |

    6 | {% if text %} 7 | {{ text }} 8 | {% else %} 9 | Doncho's App 10 | {% endif %} 11 |

    12 | {# `include`d templates have access to the view context #} 13 | {# {% if request.user.is_authenticated %}#} 14 | {# {{ request.user }}#} 15 | {# {% else %}#} 16 | {# Anonymous#} 17 | {# {% endif %}#} 18 | 19 | {% profile_avatar %} 20 |
    21 | 29 |
    -------------------------------------------------------------------------------- /templates_advanced/templates/tags/profile_avatar.html: -------------------------------------------------------------------------------- 1 | {% if user_fullname %} 2 | {{ user_fullname }} 3 | {% else %} 4 | Anonymous 5 | {% endif %} -------------------------------------------------------------------------------- /templates_advanced/templates/web/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'master.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block styles %} 6 | 7 | {% endblock %} -------------------------------------------------------------------------------- /templates_advanced/templates/web/bootstrap.html: -------------------------------------------------------------------------------- 1 | {% extends 'master.html' %} 2 | 3 | {% block styles %} 4 | {% if has_boostrap %} 5 | 8 | {% endif %} 9 | {% endblock %} 10 | 11 | {% block main_content %} 12 |

    Buttons:

    13 | a link 14 | a .btn link 15 | a .btn-success link 16 | 17 |

    Forms:

    18 |
    19 | 23 | 27 | 37 |
    38 | {% endblock %} -------------------------------------------------------------------------------- /templates_advanced/templates/web/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'master_with_sidebar.html' %} 2 | {% load list_tags %} 3 | 4 | {% load number_filters %} 5 | 6 | {% block page_title %} - Home {% endblock %} 7 | 8 | {% block body_end_scripts %} 9 | 14 | {% endblock %} 15 | 16 | {% block sidebar %} 17 | {% include 'web/about.html' %} {# Don't do this!!! #} 18 | {% endblock %} 19 | 20 | {% block content %} 21 |

    This is {{ cat_name|lower|capfirst }}:

    22 | 25 |

    Numbers:

    26 |

    All::{{ numbers }}

    27 |

    Odd:{{ numbers|only_odd }}

    28 |

    Even:{{ numbers|only_even }}

    29 |

    Positive:{{ numbers|only_positive }}

    30 |

    Negative:{{ numbers|only_negative }}

    31 | 32 | 33 |

    With tags

    34 |

    All:: {% list_of numbers %}

    35 |

    Odd:{{ numbers|only_odd }}

    36 |

    Even:{{ numbers|only_even }}

    37 |

    Positive:{{ numbers|only_positive }}

    38 |

    Negative:{{ numbers|only_negative }}

    39 | 40 |

    {% current_time %}

    41 | {% endblock %} 42 | 43 |

    Something else

    -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_advanced/templates_advanced/__init__.py -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for templates_advanced project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_advanced.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | urlpatterns = [ 5 | path("admin/", admin.site.urls), 6 | path("", include('templates_advanced.web.urls')), 7 | ] 8 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_advanced/templates_advanced/web/__init__.py -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "templates_advanced.web" 7 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_advanced/templates_advanced/web/migrations/__init__.py -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_advanced/templates_advanced/web/templatetags/__init__.py -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/templatetags/list_tags.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django import template 4 | from django.template.defaultfilters import safe 5 | 6 | register = template.Library() 7 | 8 | 9 | # Expects to return an HTML string to visualize 10 | @register.simple_tag 11 | def list_of(values): 12 | items_string = ''.join(f'
  • {value}
  • ' for value in values) 13 | return safe(f'
      {items_string}
    ') 14 | 15 | 16 | @register.simple_tag 17 | def current_time(): 18 | return datetime.datetime.now() 19 | 20 | # Expects to return an HTML string based on a template 21 | # @register.inclusion_tag 22 | 23 | 24 | # Expects to return a template Node with `render` func 25 | # @register.tag 26 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/templatetags/number_filters.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | def only_with_condition(numbers, condition_func): 7 | return [x for x in numbers if condition_func(x)] 8 | 9 | 10 | @register.filter 11 | def only_odd(numbers): 12 | return only_with_condition(numbers, lambda x: x % 2 > 0) 13 | 14 | 15 | @register.filter 16 | def only_even(numbers): 17 | return only_with_condition(numbers, lambda x: x % 2 == 0) 18 | 19 | 20 | @register.filter 21 | def only_positive(numbers): 22 | return only_with_condition(numbers, lambda x: x > 0) 23 | 24 | 25 | @register.filter 26 | def only_negative(numbers): 27 | return only_with_condition(numbers, lambda x: x < 0) 28 | 29 | # def only_odd(numbers): 30 | # return [x for x in numbers if x % 2 > 0] 31 | 32 | # def only_even(numbers): 33 | # return [x for x in numbers if x % 2 == 0] 34 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/templatetags/user_tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | @register.inclusion_tag("tags/profile_avatar.html", takes_context=True) 7 | def profile_avatar(context): 8 | print(context) 9 | # Return `context`, much like in `View`s 10 | user = context.request.user 11 | initials = \ 12 | user.first_name[0] + user.last_name[0] \ 13 | if user.is_authenticated \ 14 | else "AN" 15 | 16 | return { 17 | "user_fullname": initials, 18 | } 19 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from templates_advanced.web.views import index, about, show_bootstrap 4 | 5 | urlpatterns = ( 6 | path("", index, name="index"), 7 | path("about/", about, name="about"), 8 | path("bootstrap/", show_bootstrap, name="show_bootstrap"), 9 | ) 10 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/web/views.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import random 3 | 4 | from django.shortcuts import render 5 | 6 | cat_images = ( 7 | "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Juvenile_Ragdoll.jpg/800px-Juvenile_Ragdoll.jpg", 8 | "https://cdn.britannica.com/39/7139-050-A88818BB/Himalayan-chocolate-point.jpg", 9 | ) 10 | 11 | cat_names = ( 12 | "Pepelyashka", 13 | "GoSho", 14 | ) 15 | 16 | 17 | def index(request): 18 | index = random.randint(0, len(cat_images) - 1) 19 | context = { 20 | "cat_image": cat_images[index], 21 | "cat_name": cat_names[index], 22 | "numbers": [x + 1 for x in range(-10, 10)], 23 | } 24 | 25 | return render(request, "web/index.html", context) 26 | 27 | 28 | def about(request): 29 | return render(request, "web/about.html") 30 | 31 | 32 | def show_bootstrap(request): 33 | context = { 34 | "has_boostrap": request.GET.get("has_bootstrap", False), 35 | } 36 | 37 | return render(request, "web/bootstrap.html", context) 38 | -------------------------------------------------------------------------------- /templates_advanced/templates_advanced/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for templates_advanced project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_advanced.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /templates_static_files/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /templates_static_files/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /templates_static_files/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /templates_static_files/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /templates_static_files/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates_static_files/.idea/templates_static_files.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /templates_static_files/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_static_files.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /templates_static_files/staticfiles/css/site.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: green; 3 | font-size: 24px; 4 | } 5 | 6 | body { 7 | padding: 50px; 8 | } 9 | 10 | .young { 11 | color: green; 12 | } 13 | 14 | .not-that-young { 15 | color: purple; 16 | } -------------------------------------------------------------------------------- /templates_static_files/staticfiles/imgs/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_static_files/staticfiles/imgs/cat.jpg -------------------------------------------------------------------------------- /templates_static_files/staticfiles/js/site.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_static_files/staticfiles/js/site.js -------------------------------------------------------------------------------- /templates_static_files/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | {% load static %} 8 | {##} 9 | 10 | 11 | 12 | {#A cute cat#} 13 | A cute cat 14 | 15 |
      16 |
    • {% static 'imgs/cat.jpg' %}
    • 17 |
    • {% static 'css/site.css' %}
    • 18 |
    19 | 20 |
    21 |
    Before block
    22 | 23 | {% block content %} 24 | {% endblock %} 25 | 26 | {% block whatever %} 27 | {% endblock %} 28 | 29 |
    After block
    30 |
    31 | 32 | -------------------------------------------------------------------------------- /templates_static_files/templates/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | {{ title|yesno }} 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates_static_files/templates/employees/details.html: -------------------------------------------------------------------------------- 1 |

    Employee with PK={{ pk }}

    -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_static_files/templates_static_files/__init__.py -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for templates_static_files project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_static_files.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_static_files/templates_static_files/employees/__init__.py -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class EmployeesConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'templates_static_files.employees' 7 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/templates_static_files/templates_static_files/employees/migrations/__init__.py -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from templates_static_files.employees.views import index, employee_details 4 | 5 | urlpatterns = ( 6 | path("", index, name="index"), 7 | path("employees/", employee_details, name="employee_details"), 8 | ) 9 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/employees/views.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import random 3 | 4 | from django.shortcuts import render 5 | from django.urls import reverse 6 | 7 | 8 | class Person: 9 | def __init__(self, first_name, last_name, age=None): 10 | self.first_name = first_name 11 | self.last_name = last_name 12 | self.age = age 13 | 14 | @property 15 | def full_name(self): 16 | return f"{self.first_name} {self.last_name}" 17 | 18 | 19 | def index(request): 20 | person = Person( 21 | "Doncho", 22 | "Minkov" 23 | ) 24 | context = { 25 | "title": "Employees list", # valid 26 | "1as": "567", # valid 27 | 28 | "new.employee": "Doncho", # invalid 29 | "new employee": "Doncho", # invalid 30 | "123": "456", # invalid 31 | 32 | "person": { 33 | "first_name": "Doncho", 34 | "last_name": "Minkov", 35 | }, 36 | "person_obj": person, 37 | "person_dict": person.__dict__, 38 | 39 | "names": ["Doncho", "Gosho", "Maria"], 40 | "ages": [random.randrange(1, 100) for _ in range(10)], 41 | "ages_empty": [], 42 | 43 | "date": datetime.date.today(), 44 | "get_params": request.GET, 45 | } 46 | print(reverse('index')) 47 | 48 | print(context["person"]["first_name"]) 49 | print(context["person"].items()) 50 | 51 | return render(request, "employees/index.html", context) 52 | 53 | 54 | def employee_details(request, pk): 55 | context = { 56 | "pk": pk, 57 | } 58 | 59 | return render(request, 'employees/details.html', context) 60 | # ll = [1, 2, 3] 61 | # for e in ll: 62 | # print(e) 63 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/settings.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | BASE_DIR = Path(__file__).resolve().parent.parent 4 | 5 | SECRET_KEY = "django-insecure-68afg2czn+rxyons4&-!-80e2d@7=&hg0+u6g9)%-b6)*kuya$" 6 | 7 | DEBUG = False 8 | 9 | ALLOWED_HOSTS = [ 10 | 'localhost', 11 | ] 12 | 13 | INSTALLED_APPS = [ 14 | "django.contrib.admin", 15 | "django.contrib.auth", 16 | "django.contrib.contenttypes", 17 | "django.contrib.sessions", 18 | "django.contrib.messages", 19 | "django.contrib.staticfiles", 20 | 21 | "templates_static_files.employees", 22 | ] 23 | 24 | MIDDLEWARE = [ 25 | "django.middleware.security.SecurityMiddleware", 26 | "django.contrib.sessions.middleware.SessionMiddleware", 27 | "django.middleware.common.CommonMiddleware", 28 | "django.middleware.csrf.CsrfViewMiddleware", 29 | "django.contrib.auth.middleware.AuthenticationMiddleware", 30 | "django.contrib.messages.middleware.MessageMiddleware", 31 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 32 | ] 33 | 34 | ROOT_URLCONF = "templates_static_files.urls" 35 | 36 | TEMPLATES = [ 37 | { 38 | "BACKEND": "django.template.backends.django.DjangoTemplates", 39 | "DIRS": [BASE_DIR / 'templates'] 40 | , 41 | "APP_DIRS": True, 42 | "OPTIONS": { 43 | "context_processors": [ 44 | "django.template.context_processors.debug", 45 | "django.template.context_processors.request", 46 | "django.contrib.auth.context_processors.auth", 47 | "django.contrib.messages.context_processors.messages", 48 | ], 49 | }, 50 | }, 51 | ] 52 | 53 | WSGI_APPLICATION = "templates_static_files.wsgi.application" 54 | 55 | DATABASES = { 56 | "default": { 57 | "ENGINE": "django.db.backends.sqlite3", 58 | "NAME": BASE_DIR / "db.sqlite3", 59 | } 60 | } 61 | 62 | AUTH_PASSWORD_VALIDATORS = [ 63 | { 64 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 65 | }, 66 | { 67 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 68 | }, 69 | { 70 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 71 | }, 72 | { 73 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 74 | }, 75 | ] 76 | 77 | LANGUAGE_CODE = "en-us" 78 | 79 | TIME_ZONE = "UTC" 80 | 81 | USE_I18N = True 82 | 83 | USE_TZ = True 84 | 85 | # Base url for access 86 | STATIC_URL = "static/" # For DEV 87 | # STATIC_URL = "https://softuni.bg/" # For PROD 88 | 89 | # The place on FS where the static files are 90 | STATICFILES_DIRS = ( 91 | BASE_DIR / 'staticfiles', 92 | # Other static files dirs 93 | ) 94 | 95 | STATIC_ROOT = BASE_DIR / 'staticfiles_compiled' 96 | 97 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 98 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | urlpatterns = [ 5 | path("admin/", admin.site.urls), 6 | path("", include("templates_static_files.employees.urls")), 7 | ] 8 | -------------------------------------------------------------------------------- /templates_static_files/templates_static_files/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for templates_static_files project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "templates_static_files.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/urls_and_views_demos.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /urls_and_views_demos/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /urls_and_views_demos/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "urls_and_views_demos.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /urls_and_views_demos/staticfiles/main.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: red; 3 | } -------------------------------------------------------------------------------- /urls_and_views_demos/staticfiles/main.js: -------------------------------------------------------------------------------- 1 | alert('It works!') -------------------------------------------------------------------------------- /urls_and_views_demos/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 |

    Error!

    9 | 10 | -------------------------------------------------------------------------------- /urls_and_views_demos/templates/core/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 |

    {{ title }}

    12 |

    Non-existent from here "{{ does_not_exist }}" to here

    13 |
      14 |
    • Method: {{ method }}
    • 15 |
    • Method from request: {{ request.method }}
    • 16 |
    • Path: {{ path }}
    • 17 |
    • User: {{ user }}
    • 18 |
    19 | 20 | 21 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/urls_and_views_demos/urls_and_views_demos/__init__.py -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for urls_and_views_demos project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "urls_and_views_demos.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/urls_and_views_demos/urls_and_views_demos/core/__init__.py -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'urls_and_views_demos.core' 7 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/urls_and_views_demos/urls_and_views_demos/core/migrations/__init__.py -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | 3 | from urls_and_views_demos.core.views import index, index_json, redirect_to_softuni, redirect_to_index, \ 4 | redirect_to_index_with_params, raise_error, raise_exception 5 | 6 | urlpatterns = ( 7 | # redirects 8 | path('to-softuni/', redirect_to_softuni), 9 | path('to-index/', redirect_to_index, name='redirect_to_index'), 10 | path('to-index-with-params/', redirect_to_index_with_params, name='redirect_to_index_with_params'), 11 | 12 | # Errors 13 | path('raise_error/', raise_error, name='raise_error_with_response'), 14 | path('raise_exception/', raise_exception, name='raise_exception'), 15 | 16 | # Normal URLs 17 | path('', index, name='index_no_params'), 18 | path('/', index), 19 | path('/', index), 20 | path('//', index, name='index_with_pk_and_slug'), 21 | 22 | path('json/', include( 23 | [ 24 | path('', index_json), 25 | path('/', index_json), 26 | path('/', index_json), 27 | path('//', index_json) 28 | ])), 29 | ) 30 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/core/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse, JsonResponse, HttpResponseNotFound, Http404 2 | from django.shortcuts import render, redirect 3 | 4 | 5 | def index_no_template(request, *args, **kwargs): 6 | content = f"

    It works with:


    " + \ 7 | f"args={args} and kwargs={kwargs},
    " + \ 8 | f"path={request.path},
    " + \ 9 | f"method={request.method} and
    " + \ 10 | f"user={request.user}" 11 | 12 | return HttpResponse( 13 | content, 14 | # content_type="application/json" 15 | # status=201, 16 | ) 17 | 18 | 19 | def index(request, *args, **kwargs): 20 | context = { 21 | "title": "Request data", 22 | "args": args, 23 | "kwargs": kwargs, 24 | "path": request.path, 25 | "method": request.method, 26 | "user": request.user, 27 | } 28 | 29 | return render(request, 'core/index.html', context) 30 | 31 | 32 | def redirect_to_softuni(request): 33 | return redirect("https://softuni.bg") 34 | 35 | 36 | def redirect_to_index(request): 37 | return redirect('index_no_params') 38 | 39 | 40 | def redirect_to_index_with_params(request): 41 | return redirect('index_with_pk_and_slug', pk=19, slug="Gosho") 42 | 43 | 44 | def index_json(request, *args, **kwargs): 45 | content = { 46 | "args": args, 47 | "kwargs": kwargs, 48 | "path": request.path, 49 | "method": request.method, 50 | "user": str(request.user), 51 | } 52 | 53 | return JsonResponse( 54 | content, 55 | # content_type="application/json", 56 | # status=201, 57 | ) 58 | 59 | 60 | def raise_error(request): 61 | return HttpResponseNotFound( 62 | status=404, 63 | ) 64 | 65 | 66 | def raise_exception(request): 67 | raise Http404 68 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/urls_and_views_demos/urls_and_views_demos/departments/__init__.py -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DepartmentsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'urls_and_views_demos.departments' 7 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Minkov/python-web-basics-demos/62e9c4c609638c981601f7cdcfab95cc0535aead/urls_and_views_demos/urls_and_views_demos/departments/migrations/__init__.py -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, reverse 2 | 3 | from urls_and_views_demos.departments.views import department_details, department_details_by_name 4 | 5 | urlpatterns = ( 6 | # path("departments/1/", department_1_details), 7 | # path("departments/2/", department_2_details), 8 | path("/", department_details, name='department_details'), # departments// 9 | path("/", department_details_by_name), 10 | ) -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/departments/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | # 5 | # def index(request): 6 | # return HttpResponse(f"Response from {time.time()}") 7 | # 8 | # 9 | # def index2(request, *args, **kwargs): 10 | # return HttpResponse(f"Response with {args} and {kwargs}") 11 | # 12 | # 13 | # def department_1_details(request): 14 | # return HttpResponse("Department 1") 15 | # 16 | # 17 | # def department_2_details(request): 18 | # return HttpResponse("Department 2") 19 | 20 | 21 | def department_details(request, pk): 22 | return HttpResponse(f"Department with ID: {pk}") 23 | 24 | 25 | def department_details_by_name(request, name): 26 | return HttpResponse(f"Department with name: {name}") 27 | 28 | 29 | def departments_list(request): 30 | pass 31 | 32 | 33 | def departments_create(request): 34 | pass 35 | 36 | 37 | # ... 38 | 39 | ''' 40 | Request <-> Response 41 | ''' 42 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URL configuration for urls_and_views_demos project. 3 | 4 | The `urlpatterns` list routes URLs to views. For more information please see: 5 | https://docs.djangoproject.com/en/4.2/topics/http/urls/ 6 | Examples: 7 | Function views 8 | 1. Add an import: from my_app import views 9 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 10 | Class-based views 11 | 1. Add an import: from other_app.views import Home 12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 13 | Including another URLconf 14 | 1. Import the include() function: from django.urls import include, path 15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 16 | """ 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | 20 | urlpatterns = [ 21 | path("admin/", admin.site.urls), 22 | 23 | path('', include('urls_and_views_demos.core.urls')), 24 | 25 | # Prefix all urls defined in `urls_and_views_demos.departments.urls` with `departments/` 26 | path("departments/", include("urls_and_views_demos.departments.urls")), 27 | # path("employees/", include([ 28 | # path("asd/", index), 29 | # path("asd2/", department_2_details), 30 | # ]) 31 | # ), 32 | # path("asd//"), 33 | # path("asd///"), 34 | ] 35 | 36 | ''' 37 | # Diff between `path` and `str` in urls: 38 | | | departments// | departments/// | departments// | 39 | | departments/gosho/pesho | No match | Match: name=gosho, fname=pesho | Match: `gosho/pesho` | 40 | ''' 41 | 42 | ''' 43 | When creating new Django App: 44 | 1. Add the Django App in `INSTALLED_APPS` 45 | 2. Create `urls.py` in the Django App 46 | 3. Include the Django App's `urls.py` in global `urls.py` 47 | ''' 48 | -------------------------------------------------------------------------------- /urls_and_views_demos/urls_and_views_demos/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for urls_and_views_demos project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "urls_and_views_demos.settings") 15 | 16 | application = get_wsgi_application() 17 | --------------------------------------------------------------------------------