From 3bf65b2755e0d88c7d206bca4a1b63377b1fbb53 Mon Sep 17 00:00:00 2001 From: 100gle <569590461@qq.com> Date: Wed, 10 Aug 2022 16:15:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(projects):=20=E6=96=B0=E5=A2=9EDjango?= =?UTF-8?q?=E7=BB=BC=E5=90=88=E6=A1=88=E4=BE=8B=E7=A4=BA=E4=BE=8B=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=8F=8A=E7=B4=A0=E6=9D=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- projects/web-django/delegate.py | 17 ++ projects/web-django/orm.py | 28 ++++ projects/web-django/quickstart/manage.py | 22 +++ .../web-django/quickstart/myapp/__init__.py | 0 projects/web-django/quickstart/myapp/admin.py | 3 + projects/web-django/quickstart/myapp/apps.py | 6 + .../quickstart/myapp/migrations/__init__.py | 0 .../web-django/quickstart/myapp/models.py | 3 + projects/web-django/quickstart/myapp/tests.py | 3 + projects/web-django/quickstart/myapp/views.py | 61 +++++++ .../web-django/quickstart/orm/__init__.py | 0 projects/web-django/quickstart/orm/admin.py | 3 + projects/web-django/quickstart/orm/apps.py | 6 + .../quickstart/orm/migrations/0001_initial.py | 26 +++ .../quickstart/orm/migrations/__init__.py | 0 projects/web-django/quickstart/orm/models.py | 35 ++++ projects/web-django/quickstart/orm/tests.py | 3 + projects/web-django/quickstart/orm/urls.py | 7 + projects/web-django/quickstart/orm/views.py | 5 + .../quickstart/quickstart/__init__.py | 0 .../web-django/quickstart/quickstart/asgi.py | 16 ++ .../quickstart/quickstart/settings.py | 125 +++++++++++++++ .../web-django/quickstart/quickstart/urls.py | 26 +++ .../web-django/quickstart/quickstart/wsgi.py | 16 ++ .../web-django/quickstart/templates/poem.html | 43 +++++ .../web-django/quickstart/tmpl/__init__.py | 0 projects/web-django/quickstart/tmpl/admin.py | 3 + projects/web-django/quickstart/tmpl/apps.py | 6 + .../quickstart/tmpl/migrations/__init__.py | 0 projects/web-django/quickstart/tmpl/models.py | 3 + projects/web-django/quickstart/tmpl/tests.py | 3 + projects/web-django/quickstart/tmpl/urls.py | 7 + projects/web-django/quickstart/tmpl/views.py | 36 +++++ .../web-django/quickstart/view/__init__.py | 0 projects/web-django/quickstart/view/admin.py | 3 + projects/web-django/quickstart/view/apps.py | 6 + .../quickstart/view/migrations/__init__.py | 0 projects/web-django/quickstart/view/models.py | 3 + projects/web-django/quickstart/view/tests.py | 3 + projects/web-django/quickstart/view/urls.py | 8 + projects/web-django/quickstart/view/views.py | 59 +++++++ projects/web-django/server.py | 49 ++++++ projects/web-django/todolist/manage.py | 22 +++ .../web-django/todolist/popup/__init__.py | 0 projects/web-django/todolist/popup/admin.py | 3 + projects/web-django/todolist/popup/apps.py | 6 + .../todolist/popup/migrations/0001_initial.py | 35 ++++ .../todolist/popup/migrations/__init__.py | 0 projects/web-django/todolist/popup/models.py | 47 ++++++ projects/web-django/todolist/popup/tests.py | 3 + projects/web-django/todolist/popup/urls.py | 12 ++ projects/web-django/todolist/popup/views.py | 112 +++++++++++++ .../todolist/static/css/simple-v1.min.css | 1 + .../web-django/todolist/static/css/style.css | 149 ++++++++++++++++++ .../static/images/sspai-logo-light.svg | 84 ++++++++++ .../web-django/todolist/static/js/main.js | 16 ++ .../web-django/todolist/templates/about.html | 24 +++ .../web-django/todolist/templates/base.html | 44 ++++++ .../web-django/todolist/templates/index.html | 19 +++ .../web-django/todolist/templates/tasks.html | 96 +++++++++++ .../web-django/todolist/todolist/__init__.py | 0 projects/web-django/todolist/todolist/asgi.py | 16 ++ .../web-django/todolist/todolist/settings.py | 126 +++++++++++++++ projects/web-django/todolist/todolist/urls.py | 22 +++ projects/web-django/todolist/todolist/wsgi.py | 16 ++ 65 files changed, 1496 insertions(+) create mode 100644 projects/web-django/delegate.py create mode 100644 projects/web-django/orm.py create mode 100755 projects/web-django/quickstart/manage.py create mode 100644 projects/web-django/quickstart/myapp/__init__.py create mode 100644 projects/web-django/quickstart/myapp/admin.py create mode 100644 projects/web-django/quickstart/myapp/apps.py create mode 100644 projects/web-django/quickstart/myapp/migrations/__init__.py create mode 100644 projects/web-django/quickstart/myapp/models.py create mode 100644 projects/web-django/quickstart/myapp/tests.py create mode 100644 projects/web-django/quickstart/myapp/views.py create mode 100644 projects/web-django/quickstart/orm/__init__.py create mode 100644 projects/web-django/quickstart/orm/admin.py create mode 100644 projects/web-django/quickstart/orm/apps.py create mode 100644 projects/web-django/quickstart/orm/migrations/0001_initial.py create mode 100644 projects/web-django/quickstart/orm/migrations/__init__.py create mode 100644 projects/web-django/quickstart/orm/models.py create mode 100644 projects/web-django/quickstart/orm/tests.py create mode 100644 projects/web-django/quickstart/orm/urls.py create mode 100644 projects/web-django/quickstart/orm/views.py create mode 100644 projects/web-django/quickstart/quickstart/__init__.py create mode 100644 projects/web-django/quickstart/quickstart/asgi.py create mode 100644 projects/web-django/quickstart/quickstart/settings.py create mode 100644 projects/web-django/quickstart/quickstart/urls.py create mode 100644 projects/web-django/quickstart/quickstart/wsgi.py create mode 100644 projects/web-django/quickstart/templates/poem.html create mode 100644 projects/web-django/quickstart/tmpl/__init__.py create mode 100644 projects/web-django/quickstart/tmpl/admin.py create mode 100644 projects/web-django/quickstart/tmpl/apps.py create mode 100644 projects/web-django/quickstart/tmpl/migrations/__init__.py create mode 100644 projects/web-django/quickstart/tmpl/models.py create mode 100644 projects/web-django/quickstart/tmpl/tests.py create mode 100644 projects/web-django/quickstart/tmpl/urls.py create mode 100644 projects/web-django/quickstart/tmpl/views.py create mode 100644 projects/web-django/quickstart/view/__init__.py create mode 100644 projects/web-django/quickstart/view/admin.py create mode 100644 projects/web-django/quickstart/view/apps.py create mode 100644 projects/web-django/quickstart/view/migrations/__init__.py create mode 100644 projects/web-django/quickstart/view/models.py create mode 100644 projects/web-django/quickstart/view/tests.py create mode 100644 projects/web-django/quickstart/view/urls.py create mode 100644 projects/web-django/quickstart/view/views.py create mode 100644 projects/web-django/server.py create mode 100755 projects/web-django/todolist/manage.py create mode 100644 projects/web-django/todolist/popup/__init__.py create mode 100644 projects/web-django/todolist/popup/admin.py create mode 100644 projects/web-django/todolist/popup/apps.py create mode 100644 projects/web-django/todolist/popup/migrations/0001_initial.py create mode 100644 projects/web-django/todolist/popup/migrations/__init__.py create mode 100644 projects/web-django/todolist/popup/models.py create mode 100644 projects/web-django/todolist/popup/tests.py create mode 100644 projects/web-django/todolist/popup/urls.py create mode 100644 projects/web-django/todolist/popup/views.py create mode 100755 projects/web-django/todolist/static/css/simple-v1.min.css create mode 100644 projects/web-django/todolist/static/css/style.css create mode 100644 projects/web-django/todolist/static/images/sspai-logo-light.svg create mode 100644 projects/web-django/todolist/static/js/main.js create mode 100644 projects/web-django/todolist/templates/about.html create mode 100644 projects/web-django/todolist/templates/base.html create mode 100644 projects/web-django/todolist/templates/index.html create mode 100644 projects/web-django/todolist/templates/tasks.html create mode 100644 projects/web-django/todolist/todolist/__init__.py create mode 100644 projects/web-django/todolist/todolist/asgi.py create mode 100644 projects/web-django/todolist/todolist/settings.py create mode 100644 projects/web-django/todolist/todolist/urls.py create mode 100644 projects/web-django/todolist/todolist/wsgi.py diff --git a/projects/web-django/delegate.py b/projects/web-django/delegate.py new file mode 100644 index 0000000..92fbaf3 --- /dev/null +++ b/projects/web-django/delegate.py @@ -0,0 +1,17 @@ +class Proxy: + def __init__(self, delegate): + self.delegate = delegate + + def fetch(self): + print(f"fetching {self.delegate.url} by proxy...") + + +class Request: + def __init__(self, url, proxy=False): + self.url = url + self.proxy = Proxy(self) if proxy else None + + +if __name__ == "__main__": + req = Request("https://sspai.com", proxy=True) + req.proxy.fetch() diff --git a/projects/web-django/orm.py b/projects/web-django/orm.py new file mode 100644 index 0000000..c32a8a8 --- /dev/null +++ b/projects/web-django/orm.py @@ -0,0 +1,28 @@ +from dataclasses import dataclass +from pprint import pprint + + +@dataclass +class User: + name: str + age: int + email: str + telephone: str + + +table = [ + User( + name="John", + age=25, + email="example.john@sspai.com", + telephone="021-12345678", + ), + User( + name="Steve", + age=30, + email="example.steve@sspai.com", + telephone="000-1111-1111", + ), +] + +pprint(table) diff --git a/projects/web-django/quickstart/manage.py b/projects/web-django/quickstart/manage.py new file mode 100755 index 0000000..062e0a3 --- /dev/null +++ b/projects/web-django/quickstart/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quickstart.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/projects/web-django/quickstart/myapp/__init__.py b/projects/web-django/quickstart/myapp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/myapp/admin.py b/projects/web-django/quickstart/myapp/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/projects/web-django/quickstart/myapp/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/projects/web-django/quickstart/myapp/apps.py b/projects/web-django/quickstart/myapp/apps.py new file mode 100644 index 0000000..c34fb20 --- /dev/null +++ b/projects/web-django/quickstart/myapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MyappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'myapp' diff --git a/projects/web-django/quickstart/myapp/migrations/__init__.py b/projects/web-django/quickstart/myapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/myapp/models.py b/projects/web-django/quickstart/myapp/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/projects/web-django/quickstart/myapp/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/projects/web-django/quickstart/myapp/tests.py b/projects/web-django/quickstart/myapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/projects/web-django/quickstart/myapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/projects/web-django/quickstart/myapp/views.py b/projects/web-django/quickstart/myapp/views.py new file mode 100644 index 0000000..3813dc5 --- /dev/null +++ b/projects/web-django/quickstart/myapp/views.py @@ -0,0 +1,61 @@ +from django.http import HttpResponse + + +def poem(request): + + content = """ + +
+
+ +

+ Beautiful is better than ugly.
+ Explicit is better than implicit.
+ Simple is better than complex.
+ Complex is better than complicated.
+ Flat is better than nested.
+ Sparse is better than dense.
+ Readability counts.
+ Special cases aren't special enough to break the rules.
+ Although practicality beats purity.
+ Errors should never pass silently.
+ Unless explicitly silenced.
+ In the face of ambiguity, refuse the temptation to guess.
+ There should be one-- and preferably only one --obvious way to do + it.
+ Although that way may not be obvious at first unless you're + Dutch.
+ Now is better than never.
+ Although never is often better than *right* now.
+ If the implementation is hard to explain, it's a bad idea.
+ If the implementation is easy to explain, it may be a good idea.
+ Namespaces are one honking great idea -- let's do more of those!
+

+
+
+
+ ——Tim Peters, The Zen of Python +
+
+ """ + + return HttpResponse(content) diff --git a/projects/web-django/quickstart/orm/__init__.py b/projects/web-django/quickstart/orm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/orm/admin.py b/projects/web-django/quickstart/orm/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/projects/web-django/quickstart/orm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/projects/web-django/quickstart/orm/apps.py b/projects/web-django/quickstart/orm/apps.py new file mode 100644 index 0000000..54bea84 --- /dev/null +++ b/projects/web-django/quickstart/orm/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OrmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'orm' diff --git a/projects/web-django/quickstart/orm/migrations/0001_initial.py b/projects/web-django/quickstart/orm/migrations/0001_initial.py new file mode 100644 index 0000000..0831a1f --- /dev/null +++ b/projects/web-django/quickstart/orm/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 4.0.4 on 2022-06-25 05:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='用户ID')), + ('name', models.CharField(max_length=10, verbose_name='用户名')), + ('age', models.IntegerField(verbose_name='年龄')), + ('gender', models.BooleanField(blank=True, choices=[(0, '女'), (1, '男')], default='', verbose_name='性别')), + ('email', models.EmailField(max_length=50, verbose_name='邮箱')), + ('telephone', models.CharField(blank=True, max_length=11, verbose_name='联系电话')), + ('register_at', models.DateTimeField(auto_now_add=True, verbose_name='注册时间')), + ], + ), + ] diff --git a/projects/web-django/quickstart/orm/migrations/__init__.py b/projects/web-django/quickstart/orm/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/orm/models.py b/projects/web-django/quickstart/orm/models.py new file mode 100644 index 0000000..e0e1205 --- /dev/null +++ b/projects/web-django/quickstart/orm/models.py @@ -0,0 +1,35 @@ +from django.db import models + + +class User(models.Model): + + gender_choices = [ + (0, "女"), + (1, "男"), + ] + + id = models.AutoField( + primary_key=True, + verbose_name="用户ID", + ) + name = models.CharField( + max_length=10, + verbose_name="用户名", + ) + age = models.IntegerField(verbose_name="年龄") + gender = models.BooleanField( + choices=gender_choices, + blank=True, + default="", + verbose_name="性别", + ) + email = models.EmailField(max_length=50, verbose_name="邮箱") + telephone = models.CharField( + max_length=11, + blank=True, + verbose_name="联系电话", + ) + register_at = models.DateTimeField(auto_now_add=True, verbose_name="注册时间") + + def __repr__(self): + return f"User" diff --git a/projects/web-django/quickstart/orm/tests.py b/projects/web-django/quickstart/orm/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/projects/web-django/quickstart/orm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/projects/web-django/quickstart/orm/urls.py b/projects/web-django/quickstart/orm/urls.py new file mode 100644 index 0000000..72d17df --- /dev/null +++ b/projects/web-django/quickstart/orm/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .views import index + +urlpatterns = [ + path("", index, name="orm.index"), +] diff --git a/projects/web-django/quickstart/orm/views.py b/projects/web-django/quickstart/orm/views.py new file mode 100644 index 0000000..da24aab --- /dev/null +++ b/projects/web-django/quickstart/orm/views.py @@ -0,0 +1,5 @@ +from django.http import HttpResponse + + +def index(request): + return HttpResponse("ORM page here.") diff --git a/projects/web-django/quickstart/quickstart/__init__.py b/projects/web-django/quickstart/quickstart/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/quickstart/asgi.py b/projects/web-django/quickstart/quickstart/asgi.py new file mode 100644 index 0000000..1a277e8 --- /dev/null +++ b/projects/web-django/quickstart/quickstart/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for quickstart project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quickstart.settings') + +application = get_asgi_application() diff --git a/projects/web-django/quickstart/quickstart/settings.py b/projects/web-django/quickstart/quickstart/settings.py new file mode 100644 index 0000000..acafdea --- /dev/null +++ b/projects/web-django/quickstart/quickstart/settings.py @@ -0,0 +1,125 @@ +""" +Django settings for quickstart project. + +Generated by 'django-admin startproject' using Django 4.0.4. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.0/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-)8usuw-fz#s1wq7u2_$u!g&=llu!%j5gl5)$a(avyh5h20_ssq" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + # internal apps + "orm", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "quickstart.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR.joinpath("templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "quickstart.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.0/topics/i18n/ + +LANGUAGE_CODE = "zh-Hans" + +TIME_ZONE = "Asia/Shanghai" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.0/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/projects/web-django/quickstart/quickstart/urls.py b/projects/web-django/quickstart/quickstart/urls.py new file mode 100644 index 0000000..e3a4a86 --- /dev/null +++ b/projects/web-django/quickstart/quickstart/urls.py @@ -0,0 +1,26 @@ +"""quickstart URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path +from myapp import views + +urlpatterns = [ + path("admin/", admin.site.urls), + path("poem/", views.poem, name="poem"), + path("view/", include("view.urls")), + path("tmpl/", include("tmpl.urls")), + path("orm/", include("orm.urls")), +] diff --git a/projects/web-django/quickstart/quickstart/wsgi.py b/projects/web-django/quickstart/quickstart/wsgi.py new file mode 100644 index 0000000..2754c6d --- /dev/null +++ b/projects/web-django/quickstart/quickstart/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for quickstart project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quickstart.settings') + +application = get_wsgi_application() diff --git a/projects/web-django/quickstart/templates/poem.html b/projects/web-django/quickstart/templates/poem.html new file mode 100644 index 0000000..26f47b4 --- /dev/null +++ b/projects/web-django/quickstart/templates/poem.html @@ -0,0 +1,43 @@ + + + + + + + The Zen of Python + + + + {% csrf_token %} +
+
+

+ {% for line in lines %} {{ line }}
+ {% endfor %} +

+
+
+ ——{{ author }}, {{ source }} +
+
+ + diff --git a/projects/web-django/quickstart/tmpl/__init__.py b/projects/web-django/quickstart/tmpl/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/tmpl/admin.py b/projects/web-django/quickstart/tmpl/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/projects/web-django/quickstart/tmpl/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/projects/web-django/quickstart/tmpl/apps.py b/projects/web-django/quickstart/tmpl/apps.py new file mode 100644 index 0000000..b75286d --- /dev/null +++ b/projects/web-django/quickstart/tmpl/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TmplConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'tmpl' diff --git a/projects/web-django/quickstart/tmpl/migrations/__init__.py b/projects/web-django/quickstart/tmpl/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/tmpl/models.py b/projects/web-django/quickstart/tmpl/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/projects/web-django/quickstart/tmpl/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/projects/web-django/quickstart/tmpl/tests.py b/projects/web-django/quickstart/tmpl/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/projects/web-django/quickstart/tmpl/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/projects/web-django/quickstart/tmpl/urls.py b/projects/web-django/quickstart/tmpl/urls.py new file mode 100644 index 0000000..915a551 --- /dev/null +++ b/projects/web-django/quickstart/tmpl/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .views import index + +urlpatterns = [ + path("", index, name="tmpl_index"), +] diff --git a/projects/web-django/quickstart/tmpl/views.py b/projects/web-django/quickstart/tmpl/views.py new file mode 100644 index 0000000..2450a16 --- /dev/null +++ b/projects/web-django/quickstart/tmpl/views.py @@ -0,0 +1,36 @@ +from django.shortcuts import render + + +def index(request): + + poem = """\ +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it. +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than *right* now. +If the implementation is hard to explain, it's a bad idea. +If the implementation is easy to explain, it may be a good idea. +Namespaces are one honking great idea -- let's do more of those! +""" + lines = poem.strip().split("\n") + author = "Tim Peters" + source = "The Zen of Python" + + context = dict( + lines=lines, + author=author, + source=source, + ) + return render(request, "poem.html", context=context) diff --git a/projects/web-django/quickstart/view/__init__.py b/projects/web-django/quickstart/view/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/view/admin.py b/projects/web-django/quickstart/view/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/projects/web-django/quickstart/view/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/projects/web-django/quickstart/view/apps.py b/projects/web-django/quickstart/view/apps.py new file mode 100644 index 0000000..1aaf84a --- /dev/null +++ b/projects/web-django/quickstart/view/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ViewConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'view' diff --git a/projects/web-django/quickstart/view/migrations/__init__.py b/projects/web-django/quickstart/view/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/quickstart/view/models.py b/projects/web-django/quickstart/view/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/projects/web-django/quickstart/view/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/projects/web-django/quickstart/view/tests.py b/projects/web-django/quickstart/view/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/projects/web-django/quickstart/view/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/projects/web-django/quickstart/view/urls.py b/projects/web-django/quickstart/view/urls.py new file mode 100644 index 0000000..368cc34 --- /dev/null +++ b/projects/web-django/quickstart/view/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from .views import IndexView, index + +urlpatterns = [ + path("", index), + path("class/", IndexView.as_view()), +] diff --git a/projects/web-django/quickstart/view/views.py b/projects/web-django/quickstart/view/views.py new file mode 100644 index 0000000..e029a2e --- /dev/null +++ b/projects/web-django/quickstart/view/views.py @@ -0,0 +1,59 @@ +from django.http import HttpResponse, HttpResponseNotAllowed +from django.utils.decorators import method_decorator +from django.views import View +from django.views.decorators.csrf import csrf_exempt + + +@csrf_exempt +def index(request): + """index page""" + + method = request.method + + if method == "GET": + return HttpResponseNotAllowed(["POST"]) + elif method == "POST": + return HttpResponse(f"You has got this page by POST method.") + + +@method_decorator(csrf_exempt, name="dispatch") +class IndexView(View): + + template = """\ +

You has got this page by {method} method, the following steps are:
+ {content} +

+ """ + + def get(self, request): + """index page""" + + steps = [ + "1. handle GET request", + "2. log request and other info", + "3. query something from database", + ] + response = self.template.format( + method="GET", + content=r"
".join(steps), + ) + + return HttpResponse(response) + + def post(self, request): + + steps = [ + "1. handle POST request", + "2. log request and other info", + "3. get form or parameters from request", + "4. parse form or parameters", + "5. query something from database", + "6. return response", + ] + + response = self.template.format( + method="POST", + content=r"
".join(steps), + ) + + return HttpResponse(response) diff --git a/projects/web-django/server.py b/projects/web-django/server.py new file mode 100644 index 0000000..895b149 --- /dev/null +++ b/projects/web-django/server.py @@ -0,0 +1,49 @@ +# server.py + +import logging +import socketserver +import sys + +logging.basicConfig( + level=logging.INFO, + format="[{asctime}] [{levelname}] [{module}] - {message}", + style="{", +) +log = logging.getLogger("server") + + +class TCPHandler(socketserver.BaseRequestHandler): + def handle(self) -> None: + request = self.request.recv(1024).decode().strip() + log.info(f"Get request:\n{request}") + header = "HTTP/1.0 200 OK\r\n\n" + content = """ +
+

Hello, World

+

You got it!

+
+ """.strip() + response = header + content + self.request.sendall(response.encode()) + + +def main(): + HOST, PORT = "127.0.0.1", 8000 + srv = socketserver.TCPServer( + server_address=(HOST, PORT), + RequestHandlerClass=TCPHandler, + ) + + log.info(f"Listening on http://{HOST}:{PORT}...") + try: + srv.serve_forever() + except KeyboardInterrupt: + log.info("Server stopped") + srv.server_close() + srv.shutdown() + log.info("Bye...") + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/projects/web-django/todolist/manage.py b/projects/web-django/todolist/manage.py new file mode 100755 index 0000000..87b637d --- /dev/null +++ b/projects/web-django/todolist/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todolist.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/projects/web-django/todolist/popup/__init__.py b/projects/web-django/todolist/popup/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/todolist/popup/admin.py b/projects/web-django/todolist/popup/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/projects/web-django/todolist/popup/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/projects/web-django/todolist/popup/apps.py b/projects/web-django/todolist/popup/apps.py new file mode 100644 index 0000000..55bceaf --- /dev/null +++ b/projects/web-django/todolist/popup/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PopupConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'popup' diff --git a/projects/web-django/todolist/popup/migrations/0001_initial.py b/projects/web-django/todolist/popup/migrations/0001_initial.py new file mode 100644 index 0000000..c318de2 --- /dev/null +++ b/projects/web-django/todolist/popup/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# Generated by Django 4.0.4 on 2022-06-28 13:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Group', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='收集箱', max_length=100, unique=True, verbose_name='分类名称')), + ], + ), + migrations.CreateModel( + name='Task', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='任务名称')), + ('priority', models.IntegerField(choices=[(0, '一般'), (1, '优先'), (3, '紧急')], default=0, verbose_name='任务优先级')), + ('description', models.TextField(blank=True, max_length=500, null=True, verbose_name='任务描述')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('is_done', models.BooleanField(choices=[(False, '未完成'), (True, '已完成')], default=False, verbose_name='是否完成')), + ('group', models.ForeignKey(default=0, on_delete=django.db.models.deletion.DO_NOTHING, to='popup.group', verbose_name='所属分类')), + ], + ), + ] diff --git a/projects/web-django/todolist/popup/migrations/__init__.py b/projects/web-django/todolist/popup/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/todolist/popup/models.py b/projects/web-django/todolist/popup/models.py new file mode 100644 index 0000000..09cb527 --- /dev/null +++ b/projects/web-django/todolist/popup/models.py @@ -0,0 +1,47 @@ +from django.db import models + + +class Task(models.Model): + """the task record in todolist""" + + priority_choices = ( + (0, "一般"), + (1, "优先"), + (3, "紧急"), + ) + + is_done_choices = ( + (False, "未完成"), + (True, "已完成"), + ) + + name = models.CharField(max_length=100, verbose_name="任务名称") + priority = models.IntegerField( + choices=priority_choices, default=0, verbose_name="任务优先级" + ) + description = models.TextField( + max_length=500, verbose_name="任务描述", blank=True, null=True + ) + created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") + is_done = models.BooleanField( + default=False, verbose_name="是否完成", choices=is_done_choices + ) + group = models.ForeignKey( + "Group", on_delete=models.DO_NOTHING, default=0, verbose_name="所属分类" + ) + + def __repr__(self): + return f"" + + +class Group(models.Model): + name = models.CharField( + max_length=100, + default="收集箱", + unique=True, + verbose_name="分类名称", + ) + + def __repr__(self): + return f"" diff --git a/projects/web-django/todolist/popup/tests.py b/projects/web-django/todolist/popup/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/projects/web-django/todolist/popup/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/projects/web-django/todolist/popup/urls.py b/projects/web-django/todolist/popup/urls.py new file mode 100644 index 0000000..890c310 --- /dev/null +++ b/projects/web-django/todolist/popup/urls.py @@ -0,0 +1,12 @@ +from django.urls import path + +from .views import about, create_task, delete_task, index, query_all_tasks, update_task + +urlpatterns = [ + path("", index, name="index"), + path("about/", about, name="about"), + path("tasks/", query_all_tasks, name="tasks"), + path("tasks/create/", create_task, name="create_task"), + path("tasks/update//", update_task, name="update_task"), + path("tasks/delete//", delete_task, name="delete_task"), +] diff --git a/projects/web-django/todolist/popup/views.py b/projects/web-django/todolist/popup/views.py new file mode 100644 index 0000000..c6dff71 --- /dev/null +++ b/projects/web-django/todolist/popup/views.py @@ -0,0 +1,112 @@ +from django.http.response import HttpResponseNotAllowed +from django.shortcuts import redirect, render +from django.utils.html import format_html + +from .models import Group, Task + + +def index(request): + + welcome = "欢迎来到 Todolist 练习项目 Popup 应用主页!" + + index_content = format_html( + """ + 这是《100 小时后请叫我程序员》课程用于进行 Django 实践练习的网站,主要包括了以下几部分: +
    +
  • 少数派 Logo:你可以点击跳转至少数派首页;
  • +
  • Home:即当前页面;
  • +
  • Task:用于实践的待办清单页面,你可以在里面创建、更新以及删除任务;
  • +
  • About:对个人或网站信息进行简要说明的介绍页。
  • +
+ """ + ) + + ctx = dict( + title="home", + welcome=welcome, + index_content=index_content, + ) + + return render(request, "index.html", context=ctx) + + +def about(request): + title = "About" + header = f"{title} Me" + about_content = """ + 这是一段简单的,About Me 页面。 + 它可以用来展示关于个人的一些信息,或者是简单的介绍。 + + 例如: + """.strip().splitlines() + items = [ + ("昵称", "100gle"), + ("职业", "少数派作者"), + ("编程语言", "Python、Golang、JavaScript 等等"), + ] + + ctx = dict( + title=title, + header=header, + about_content=about_content, + items=items, + ) + return render(request, "about.html", context=ctx) + + +def query_all_tasks(request): + tasks = Task.objects.all() + fields = ["序号", "任务名称", "优先级", "任务描述", "是否完成", "分组"] + + if Group.objects.count() == 0: + groups = [ + Group(name="收集箱"), + Group(name="生活"), + Group(name="工作"), + ] + + Group.objects.bulk_create(groups) + + groups = Group.objects.all() + + ctx = dict( + title="Task", + tasks=tasks, + fields=fields, + groups=groups, + ) + return render(request, "tasks.html", context=ctx) + + +def create_task(request): + """create a task""" + if request.method == "POST": + name = request.POST.get("taskName") + priority = request.POST.get("taskPriority") + description = request.POST.get("taskDescription") + group_id = request.POST.get("taskGroup") + group = Group.objects.get(id=group_id) + + Task.objects.create( + name=name, priority=priority, description=description, group=group + ) + return redirect("/tasks/") + else: + return HttpResponseNotAllowed(["POST"]) + + +def update_task(request, task_id): + """update a task""" + task = Task.objects.get(id=task_id) + task.is_done = False if task.is_done else True + + task.save() + return redirect("/tasks/") + + +def delete_task(request, task_id): + """delete a task""" + task = Task.objects.get(id=task_id) + + task.delete() + return redirect("/tasks/") diff --git a/projects/web-django/todolist/static/css/simple-v1.min.css b/projects/web-django/todolist/static/css/simple-v1.min.css new file mode 100755 index 0000000..36b37ae --- /dev/null +++ b/projects/web-django/todolist/static/css/simple-v1.min.css @@ -0,0 +1 @@ +:root{--sans-font:-apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,Noto,"Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif;--mono-font:Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace;--base-fontsize:1.15rem;--header-scale:1.25;--line-height:1.618;--bg:#fff;--accent-bg:#f5f7ff;--text:#212121;--text-light:#585858;--border:#d8dae1;--accent:#0d47a1;--accent-light:#90caf9;--code:#d81b60;--preformatted:#444;--marked:#ffdd33;--disabled:#efefef}@media (prefers-color-scheme:dark){:root{--bg:#212121;--accent-bg:#2b2b2b;--text:#dcdcdc;--text-light:#ababab;--border:#666;--accent:#ffb300;--accent-light:#ffecb3;--code:#f06292;--preformatted:#ccc;--disabled:#111}img,video{opacity:.6}}html{font-family:var(--sans-font)}body{color:var(--text);background:var(--bg);font-size:var(--base-fontsize);line-height:var(--line-height);display:flex;min-height:100vh;flex-direction:column;flex:1;margin:0 auto;max-width:45rem;padding:0 .5rem;overflow-x:hidden;word-break:break-word;overflow-wrap:break-word}header{background:var(--accent-bg);border-bottom:1px solid var(--border);text-align:center;padding:2rem .5rem;width:100vw;position:relative;box-sizing:border-box;left:50%;right:50%;margin-left:-50vw;margin-right:-50vw}header h1,header p{margin:0}main{padding-top:1.5rem}h1,h2,h3{line-height:1.1}nav{font-size:1rem;line-height:2;padding:1rem 0}nav a{margin:1rem 1rem 0 0;border:1px solid var(--border);border-radius:5px;color:var(--text)!important;display:inline-block;padding:.1rem 1rem;text-decoration:none;transition:.4s}nav a:hover{color:var(--accent)!important;border-color:var(--accent)}nav a.current:hover{text-decoration:none}footer{margin-top:4rem;padding:2rem 1rem 1.5rem 1rem;color:var(--text-light);font-size:.9rem;text-align:center;border-top:1px solid var(--border)}h1{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h2{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h3{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h4{font-size:calc(var(--base-fontsize) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h5{font-size:var(--base-fontsize);margin-top:calc(var(--line-height) * 1.5rem)}h6{font-size:calc(var(--base-fontsize)/ var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}a,a:visited{color:var(--accent)}a:hover{text-decoration:none}[role=button],a button,button,input[type=button],input[type=reset],input[type=submit]{border:none;border-radius:5px;background:var(--accent);font-size:1rem;color:var(--bg);padding:.7rem .9rem;margin:.5rem 0;transition:.4s}[role=button][aria-disabled=true],a button[disabled],button[disabled],input[type=button][disabled],input[type=checkbox][disabled],input[type=radio][disabled],input[type=reset][disabled],input[type=submit][disabled],select[disabled]{cursor:default;opacity:.5;cursor:not-allowed}input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;background-color:var(--disabled)}input[type=range]{padding:0}abbr{cursor:help}[role=button]:focus,[role=button]:not([aria-disabled=true]):hover,button:enabled:hover,button:focus,input[type=button]:enabled:hover,input[type=button]:focus,input[type=checkbox]:enabled:hover,input[type=checkbox]:focus,input[type=radio]:enabled:hover,input[type=radio]:focus,input[type=reset]:enabled:hover,input[type=reset]:focus,input[type=submit]:enabled:hover,input[type=submit]:focus{filter:brightness(1.4);cursor:pointer}details{background:var(--accent-bg);border:1px solid var(--border);border-radius:5px;margin-bottom:1rem}summary{cursor:pointer;font-weight:700;padding:.6rem 1rem}details[open]{padding:.6rem 1rem .75rem 1rem}details[open] summary{margin-bottom:.5rem;padding:0}details[open]>:last-child{margin-bottom:0}table{border-collapse:collapse;width:100%;margin:1.5rem 0}td,th{border:1px solid var(--border);text-align:left;padding:.5rem}th{background:var(--accent-bg);font-weight:700}tr:nth-child(even){background:var(--accent-bg)}table caption{font-weight:700;margin-bottom:.5rem}ol,ul{padding-left:3rem}input,select,textarea{font-size:inherit;font-family:inherit;padding:.5rem;margin-bottom:.5rem;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:5px;box-shadow:none;box-sizing:border-box;width:60%;-moz-appearance:none;-webkit-appearance:none;appearance:none}select{background-image:linear-gradient(45deg,transparent 49%,var(--text) 51%),linear-gradient(135deg,var(--text) 51%,transparent 49%);background-position:calc(100% - 20px),calc(100% - 15px);background-size:5px 5px,5px 5px;background-repeat:no-repeat}select[multiple]{background-image:none!important}input[type=checkbox],input[type=radio]{vertical-align:bottom;position:relative}input[type=radio]{border-radius:100%}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent)}input[type=checkbox]:checked::after{content:" ";width:.1em;height:.25em;border-radius:0;position:absolute;top:.05em;left:.18em;background:0 0;border-right:solid var(--bg) .08em;border-bottom:solid var(--bg) .08em;font-size:1.8em;transform:rotate(45deg)}input[type=radio]:checked::after{content:" ";width:.25em;height:.25em;border-radius:100%;position:absolute;top:.125em;background:var(--bg);left:.125em;font-size:32px}textarea{width:80%}@media only screen and (max-width:720px){input,select,textarea{width:100%}}input[type=checkbox],input[type=radio]{width:auto}input[type=file]{border:0}fieldset{border:0;padding:0;margin:0}hr{color:var(--border);border-top:1px;margin:1rem auto}mark{padding:2px 5px;border-radius:4px;background:var(--marked)}main img,main video{max-width:100%;height:auto;border-radius:5px}figure{margin:0}figcaption{font-size:.9rem;color:var(--text-light);text-align:center;margin-bottom:1rem}blockquote{margin:2rem 0 2rem 2rem;padding:.4rem .8rem;border-left:.35rem solid var(--accent);opacity:.8;font-style:italic}cite{font-size:.9rem;color:var(--text-light);font-style:normal}code,kbd,pre,pre span,samp{font-size:1.075rem;font-family:var(--mono-font);color:var(--code)}kbd{color:var(--preformatted);border:1px solid var(--preformatted);border-bottom:3px solid var(--preformatted);border-radius:5px;padding:.1rem}pre{padding:1rem 1.4rem;max-width:100%;overflow:auto;overflow-x:auto;color:var(--preformatted);background:var(--accent-bg);border:1px solid var(--border);border-radius:5px}pre code{color:var(--preformatted);background:0 0;margin:0;padding:0} \ No newline at end of file diff --git a/projects/web-django/todolist/static/css/style.css b/projects/web-django/todolist/static/css/style.css new file mode 100644 index 0000000..e3c28c6 --- /dev/null +++ b/projects/web-django/todolist/static/css/style.css @@ -0,0 +1,149 @@ +/* base layout */ +.container { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +h1 { + margin-left: 15px; +} + +p { + margin: 10px; + word-spacing: 1.5px; +} + +ul { + list-style: none; +} + +/* navbar */ +.navbar ul { + display: flex; + align-items: center; + justify-content: space-between; + text-align: center; + list-style: none; + padding-left: 0; +} + +.navbar a { + display: flex; + justify-content: center; + align-items: center; + text-decoration: none; + border: none; + font-size: 20px; + font-weight: bold; +} + +.navbar a:hover { + color: goldenrod !important; +} + +.content, +.about { + margin: 0 10px; +} + +.content li::before, +.about li::before { + content: "\1F449"; + padding-right: 5px; +} + +/* data table */ +.data-table { + display: table; + table-layout: fixed; + width: 100%; + border-collapse: collapse; +} + +.data-table th, +.data-table td { + text-align: center; + word-wrap: break-word; + overflow-wrap: break-word; +} +.data-table th:first-child { + width: 5%; +} + +.data-table th:nth-child(2) { + width: 15%; +} + +.data-table th:nth-child(4) { + width: 30%; +} + +.data-table td[class="ops"] { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.data-table .ops span { + display: block; + color: var(--accent); + cursor: pointer; +} + +.btn-add-task { + display: flex; + flex-direction: row-reverse; +} + +.btn-add-task > button { + display: block; + width: 50px; + height: 50px; + border-radius: 50%; + font-size: 20px; + box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); +} + +.btn-add-task > button:hover { + background-color: rgb(204, 77, 77); +} + +.task-form { + display: none; + flex-direction: column; + align-items: center; +} +.form { + display: block; + width: 80%; +} + +.form > div { + display: flex; + flex-direction: row; + justify-content: space-between; + vertical-align: middle; +} + +.form .btn-submit { + text-align: center; + transition: 0.1ms; +} + +.form .btn-submit > input { + display: block; + width: 100%; + font-size: 20px; + transition: 0.1ms; +} + +#task-textarea { + width: 60%; + resize: none; +} + +/* footer */ +#footer { + text-align: center; +} diff --git a/projects/web-django/todolist/static/images/sspai-logo-light.svg b/projects/web-django/todolist/static/images/sspai-logo-light.svg new file mode 100644 index 0000000..af50116 --- /dev/null +++ b/projects/web-django/todolist/static/images/sspai-logo-light.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/web-django/todolist/static/js/main.js b/projects/web-django/todolist/static/js/main.js new file mode 100644 index 0000000..85fb11b --- /dev/null +++ b/projects/web-django/todolist/static/js/main.js @@ -0,0 +1,16 @@ +const addTaskButton = document.querySelector(".btn-add-task"); +const formDiv = document.querySelector(".task-form"); +const taskStatus = document.querySelector(".task-status"); +const updateOp = document.querySelector(".update-op"); + +// show task form +if (addTaskButton) { + addTaskButton.addEventListener("click", () => { + // use inline style to override css property. + if (formDiv.style.display === "") { + formDiv.style.display = "none"; + } + formDiv.style.display = + formDiv.style.display == "none" ? "flex" : "none"; + }); +} diff --git a/projects/web-django/todolist/templates/about.html b/projects/web-django/todolist/templates/about.html new file mode 100644 index 0000000..e412294 --- /dev/null +++ b/projects/web-django/todolist/templates/about.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block title %} +{{ title }} +{% endblock %} + +{% block content %} + +
+

{{ header }}

+
+

+ {% for content in about_content %} + {{ content }}
+ {% endfor %} +

+
    + {% for item in items %} +
  • {{ item.0 }}:{{ item.1 }}
  • + {% endfor %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/projects/web-django/todolist/templates/base.html b/projects/web-django/todolist/templates/base.html new file mode 100644 index 0000000..a84257b --- /dev/null +++ b/projects/web-django/todolist/templates/base.html @@ -0,0 +1,44 @@ + + + + + + + {% if title == "home" %} + Todolist Web App + {% else %} + Todolist Web App - {% block title %}{% endblock %} + {% endif %} + + {% load static %} + + + + + +
+ +
+
+ {% block content %} + {% endblock %} +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/projects/web-django/todolist/templates/index.html b/projects/web-django/todolist/templates/index.html new file mode 100644 index 0000000..87779c7 --- /dev/null +++ b/projects/web-django/todolist/templates/index.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% block title %} +{{ title }} +{% endblock %} + +{% block content%} + +
+

🗣 Hello, world

+
+

{{ welcome }}

+

+ {{ index_content }} +

+ +
+
+ +{% endblock%} \ No newline at end of file diff --git a/projects/web-django/todolist/templates/tasks.html b/projects/web-django/todolist/templates/tasks.html new file mode 100644 index 0000000..17a4119 --- /dev/null +++ b/projects/web-django/todolist/templates/tasks.html @@ -0,0 +1,96 @@ +{% extends "base.html" %} + +{% block title%} +{{ title }} +{% endblock %} + +{% block content %} +
+

Tasks

+ {% if not tasks %} +

🤔 Whoops……似乎任务都做完了?那么可以点击下方的按钮添加任务!

+ {% else %} + + + + {% for field in fields %} + + {% endfor%} + + + + + {% for task in tasks %} + + + + + + + + + + {% endfor %} + +
{{ field }}操作
{{ task.id }}{{ task.name }} + {% if task.priority == 1 %} + {{ "一般" }} + {% elif task.priority == 2 %} + {{ "优先" }} + {% else %} + {{ "紧急" }} + {% endif %} + {{ task.description }} + {% if task.is_done %} + {{ "已完成" }} + {% else %} + {{ "未完成" }} + {% endif %} + {{ task.group.name }} +
+ + 更新 + + + 删除 + +
+
+
+{% endif %} +
+ +
+
+
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/projects/web-django/todolist/todolist/__init__.py b/projects/web-django/todolist/todolist/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/web-django/todolist/todolist/asgi.py b/projects/web-django/todolist/todolist/asgi.py new file mode 100644 index 0000000..d5401a2 --- /dev/null +++ b/projects/web-django/todolist/todolist/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for todolist project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todolist.settings') + +application = get_asgi_application() diff --git a/projects/web-django/todolist/todolist/settings.py b/projects/web-django/todolist/todolist/settings.py new file mode 100644 index 0000000..7435716 --- /dev/null +++ b/projects/web-django/todolist/todolist/settings.py @@ -0,0 +1,126 @@ +""" +Django settings for todolist project. + +Generated by 'django-admin startproject' using Django 4.0.4. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.0/ref/settings/ +""" +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-h$0(p$ca027=i@rg(!3ut8zm@((lfkvjdc%=g$f6gecl#5c)ly" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "popup", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "todolist.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "todolist.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.0/topics/i18n/ + +LANGUAGE_CODE = "zh-Hans" + +TIME_ZONE = "Asia/Shanghai" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.0/howto/static-files/ + +STATIC_URL = "static/" +STATICFILES_DIRS = [ + BASE_DIR / "static", +] + +# Default primary key field type +# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/projects/web-django/todolist/todolist/urls.py b/projects/web-django/todolist/todolist/urls.py new file mode 100644 index 0000000..15348c0 --- /dev/null +++ b/projects/web-django/todolist/todolist/urls.py @@ -0,0 +1,22 @@ +"""todolist URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", include("popup.urls")), +] diff --git a/projects/web-django/todolist/todolist/wsgi.py b/projects/web-django/todolist/todolist/wsgi.py new file mode 100644 index 0000000..32dc04c --- /dev/null +++ b/projects/web-django/todolist/todolist/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for todolist project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todolist.settings') + +application = get_wsgi_application()