筱团Blog筱团のBlog

Django

筱团·2023-03-18 21:34·165 次阅读

Django

Prerequisite#

视频教程

一、跟着教程学 Django#

视频:Learn Django by Building an Online Marketplace – Python Tutorial for Beginners
Github 仓库:Puddle | Django
PS:这两个半小时信息量巨大,建议直接看,重要的是理解思路,不要跟着敲代码,不然敲一天都敲不完

常用命令:

  • 下载 Django pip install django django-cors-headers
  • 构建新环境(名为 puddle)django-admin startproject puddle
  • 构建应用程序(名为 core)python manage.py startapp core
  • 生成一个新的迁移文件 python manage.py makemigrations
  • 将这些迁移文件应用到数据库 python manage.py migrate
  • 创建管理员 python manage.py createsuperuser
    • 用户名:admin
    • 邮箱:admin@puddle.com
    • 密码:ilovedjango
  • 查看命令作用 python manage.py help
  • 开启当前环境 python manage.py runserver

小技巧:

  • VSCode 中的 HTML 文件,输入 ! 即可创建一个模板

启动项目#

首先进入 puddle 文件下输入如下命令

Copy
# 更新数据库 python manage.py makemigrations python manage.py migrate # 创建管理员 python manage.py createsuperuser # admin # admin@puddle.com # ilovedjango # 启动 python manage.py runserver

http://127.0.0.1:8000/admin 网址登入,进入管理员后台,添加如下数据:

  • Categories
    • Toys
    • Clothes
    • Furniture
  • Items
    • shoe1
    • chair1
    • chair2
    • teddy bear
    • toy car
  • Users
    • xiaoming / qweiop123
    • xiaohong / asdjkl456
    • xiaozhang / zxcbnm789

整体文件的结构#

下面是主体 Project

Copy
mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py

manage.py:一个命令行工具,管理 Django 的交互脚本
mysite/__init__.py:说明这文件夹是个包,可以引用(一般情况下的项目,每个文件夹都要加)
mysite/settings.py:项目的配置文件
mysite/urls.py:路由文件,所有的任务都是从这里开始分配,相当于 Django 驱动站点的目录
mysite/wsgi.py:一个基于 WSGI 的 web 服务器进入点,提供底层的网络通信功能,通常不用关心
mysite/asgi.py:一个基于 ASGI 的 web 服务器进入点,提供异步的网络通信功能,通常不用关心

下面是应用 app

Copy
polls/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py

__init__.py:一个空文件,指示 Python 将该目录视为 Python 包
admin.py:该文件定义了 Django 管理后台中注册该应用程序所需的模型
apps.py:该文件定义了该应用程序的配置
models.py:该文件定义了 Django 中的模型类,用于处理应用程序与数据库之间的数据交互
tests.py:该文件定义了应用程序的测试用例
views.py:该文件定义了处理 HTTP 请求的视图函数
migrations/:该目录用于存放该应用程序的数据库迁移文件
static/:该目录存放应用程序的静态文件,如 CSS、JavaScript 等
templates/:该目录存放应用程序的模板文件,用于渲染 HTML 页面

应用 app 中可能还包含

Copy
polls/ urls.py forms.py

urls/:该文件定义了 URL 路由规则的模块,URL 是用于定位 Web 应用程序中特定资源的地址
forms/:该文件定义了表单的模块,表单是用于收集用户输入数据的界面元素

该项目主要内容#

Copy
manage.py db.sqlite3 puddle/ settings.py urls.py core/ templates/ base.html contact.html index.html login.html signup.html forms.py urls.py views.py item/ templates/ detail.html form.html items.html forms.py urls.py views.py admin.py models.py dashboard/ templates/ index.html urls.py views.py conversation/ templates/ detail.html inbox.html new.html forms.py urls.py views.py admin.py models.py

就挑重点讲了

puddle/urls.py#

Copy
urlpatterns = [ path('', include('core.urls')), path('items/', include('item.urls')), path('dashboard/', include('dashboard.urls')), path('inbox/', include('conversation.urls')), path('admin/', admin.site.urls), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

include 相当于多级路由,一般用于项目核心 urls.py,这个核心共指向四个界面,分别是:

  • /,主页
  • /items/,商品界面
  • /dashboard/,自己的商品面板
  • /inbox/,对话箱
  • /admin/,账号登入窗口

puddle/settings.py#

Copy
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'conversation', 'core', 'dashboard', 'item', ] ... STATIC_URL = 'static/' MEDIA_URL = 'media/' MEDIA_ROOT = BASE_DIR / 'media'

INSTALLED_APPS 下面要接上已创建的 app 应用;最后三行代表静态资源(参考这样的写法)

core/urls.py#

Copy
urlpatterns = [ path('', views.index, name='index'), path('contact/', views.contact, name='contact'), path('signup/', views.signup, name='signup'), path('login/', auth_views.LoginView.as_view(template_name='core/login.html', authentication_form=LoginForm), name='login'), ]

这样的写法就不是多级路由了,就代表了具体的功能:

  • /,主页
  • /contact/,联系页面,类似于友链
  • /signup/,注册页面
  • /login/,登入页面

core/views.py#

Copy
def index(request): items = Item.objects.filter(is_sold=False)[0:6] categories = Category.objects.all() return render(request, 'core/index.html', { 'categories': categories, 'items': items, }) def contact(request): return render(request, 'core/contact.html') def signup(request): if request.method == 'POST': form = SignupForm(request.POST) if form.is_valid(): form.save() return redirect('/login/') else: form = SignupForm() return render(request, 'core/signup.html', { 'form': form })

index 函数表示主页;contact 函数表示联系页面;signup 函数包含了注册页面和登入页面,逻辑是首先进入 signup 网页,此时填写完资料再回车(发送 POST 请求),此时资料会保存到数据库中,并重定向到 login 界面

core/templates/xxx.html#

Copy
<head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdn.tailwindcss.com"></script> <title>{% block title %}{% endblock %} | Puddle</title> </head> <body> <nav class="py-6 px-6 flex justify-between items-center border-b border-gray-200"> <a href="/" class="text-xl font-semibold">Puddle</a> ... </body>
Copy
{% extends 'core/base.html' %} {% block title %}Contact{% endblock %} {% block content %} <h1>The contact page</h1> {% endblock %}

最主要的就是这个 tailwindcss 样式,全部 html 文件都以 class 的形式使用到了它,当然,也非常好看!
基本模板就是 base.html,其他都是以它的基础扩大沿伸(比如上面的 contact.html)

core/forms.py#

Copy
class LoginForm(AuthenticationForm): username = forms.CharField(widget=forms.TextInput(attrs={ 'placeholder': 'Your username', 'class': 'w-full py-4 px-6 rounded-xl' })) password = forms.CharField(widget=forms.PasswordInput(attrs={ 'placeholder': 'Your password', 'class': 'w-full py-4 px-6 rounded-xl' })) class SignupForm(UserCreationForm): class Meta: model = User fields = ('username', 'email', 'password1', 'password2') username = forms.CharField(widget=forms.TextInput(attrs={ 'placeholder': 'Your username', 'class': 'w-full py-4 px-6 rounded-xl' })) email = forms.CharField(widget=forms.EmailInput(attrs={ 'placeholder': 'Your email address', 'class': 'w-full py-4 px-6 rounded-xl' })) password1 = forms.CharField(widget=forms.PasswordInput(attrs={ 'placeholder': 'Your password', 'class': 'w-full py-4 px-6 rounded-xl' })) password2 = forms.CharField(widget=forms.PasswordInput(attrs={ 'placeholder': 'Repeat password', 'class': 'w-full py-4 px-6 rounded-xl' }))

这是用于数据收集的文件,一般来讲(比如 SignupForm 类)都有个 Meta 元类,指定了要收集的名称,下面则是收集的类别(比如 TextInput、EmailInput 等),而特殊的(比如 LoginForm 类)则是在 urls.py 已经隐式的添加了,故不用添加 Meta 元类

其他的文件略,大体一致#

二、看博客学 Django#

参考博客:

解决跨域问题#

Copy
# 在 setting.py 中额外添加如下内容即可 INSTALLED_APPS = [ "corsheaders", ] MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", "corsheaders.middleware.CorsMiddleware", ] # 允许全部来源 CORS_ORIGIN_ALLOW_ALL = True # 如果为 True,将不使用白名单,并且将接受所有来源,默认为 False

配置 MySQL 数据库#

Copy
# 在 setting.py 中修改如下内容即可 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'MySQL', 'USER': 'root', # 用户名 'PASSWORD': 'root', # 密码 'HOST': '127.0.0.1', 'PORT': '3306', } }

三、学习新框架 Django-Ninja#

Ninja 官网:Django Ninja Tutorial
学习视频:Python-Django-Ninja基础入门教程
学习博客:Python系列-Django-Ninja

Ninja 大致用法#

PS:我个人感觉 Django Ninja 和 Flask 没什么区别啊?前者只是把流程简化了一下(把 views.py 中的内容放在 api.py 中)

  • 下载 Django-Ninja 库:pip install django-ninja
  • xxx/api.pyxxx/urls.py 中添加所需
Copy
# api.py from ninja import NinjaAPI api = NinjaAPI() # urls.py from employee.api import api # 也可以用路由拆分 from api import api urlpatterns = [ ... path("api/", api.urls), ]
  • 添加新 app 应用:python manage.py startapp employee
  • xxx/settings.pyINSTALLED_APPS 中添加 employee
  • 万能 api 测试文档,支持查看与测试 api(包括 GET、POST 等):http://127.0.0.1:8000/api/docs

下面代码是 Django-Ninja 的增删改查示例

PS:装饰器中的形参是用于规范数据,如 response=EmployeeOut 表示函数的 return 返回的一定是 EmployeeOut 类型数据

Copy
from datetime import date from typing import List from ninja import NinjaAPI, Schema from django.shortcuts import get_object_or_404 from employees.models import Employee api = NinjaAPI() class EmployeeIn(Schema): first_name: str last_name: str department_id: int = None birthdate: date = None class EmployeeOut(Schema): id: int first_name: str last_name: str department_id: int = None birthdate: date = None @api.post("/employees") def create_employee(request, payload: EmployeeIn): employee = Employee.objects.create(**payload.dict()) return {"id": employee.id} @api.get("/employees/{employee_id}", response=EmployeeOut) def get_employee(request, employee_id: int): employee = get_object_or_404(Employee, id=employee_id) return employee @api.get("/employees", response=List[EmployeeOut]) def list_employees(request): qs = Employee.objects.all() return qs @api.put("/employees/{employee_id}") def update_employee(request, employee_id: int, payload: EmployeeIn): employee = get_object_or_404(Employee, id=employee_id) for attr, value in payload.dict().items(): setattr(employee, attr, value) employee.save() return {"success": True} @api.delete("/employees/{employee_id}") def delete_employee(request, employee_id: int): employee = get_object_or_404(Employee, id=employee_id) employee.delete() return {"success": True}
posted @   筱团  阅读(165)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
目录