Django框架+SQLite+SQLalchemy+ORM框架(Python)

Django

# 安装virtualenv(windows)
pip install virtualenv virtualenvwrapper-win

# worken 查看虚拟环境
workon

# mkvirtualenv 创建新的虚拟环境
mkvirtualenv env

# rmvirtualenv 删除虚拟环境
# rmvirtualenv env

# 进入虚拟环境
workon env

# 退出虚拟环境
deactivate

1. 创建虚拟环境

# 创建虚拟环境
mkvirtualenv djangoenv

# 进入虚拟环境
workon djangoenv

(djangoenv) C:\Users\28911>

2. 安装Django

# 4.2是LTS长期支持版本
pip install Django==4.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
# 测试Django是否安装成功
pip show django
# 成功
(djangoenv) C:\Users\28911>pip show django
Name: Django
Version: 4.2	# 版本
Summary: A high-level Python web framework that encourages rapid development and clean, pragmatic design.
Home-page: https://www.djangoproject.com/
Author: Django Software Foundation
Author-email: foundation@djangoproject.com
License: BSD-3-Clause
Location: D:\Virtualenvs\djangoenv\Lib\site-packages
Requires: asgiref, sqlparse, tzdata		# 依赖包
Required-by:

# pip freeze
(djangoenv) C:\Users\28911>pip freeze
asgiref==3.8.1
Django==4.2
sqlparse==0.5.0
tzdata==2024.1

# pip list :查看所有的包
(djangoenv) C:\Users\28911>pip list
Package  Version
-------- -------
asgiref  3.8.1
Django   4.2
pip      24.1.2
sqlparse 0.5.0
tzdata   2024.1

3. 创建一个Django项目

  • 方式 1:进入到指定要存放项目的目录,执行django-admin startproject DjangoPro1来创建一个名字为DjangoPro1的工程
  • 方式 2:使用Pycharm专业版创建DJango项目

4. 测试服务器的启动

python manage.py runserver [ip:port]

# 默认端口8000
# 也可以自己指定ip和端口:
# 1. 监听机器所有可用 IP(电脑可能有多个内网IP或多个外网IP)
python manage.py runserver 0.0.0.0:8000
# 2. 同时在settings.py中将
ALLOWED_HOSTS=['*']
# 3. 在其他局域网电脑上可以通过在浏览器中输入 Django项目所在电脑 IP:8000 访问

5. 数据迁移

迁移的概念:就是将模型映射到数据库的过程

生成迁移文件:

python manage.py makemigrations

执行迁移:

python manage.py migrate

不需要初始化迁移文件夹,每个应用默认有迁移文件夹migrations

6. 创建应用

python manage.py startapp App

创建名称为App的应用

使用应用前需要应用配置到项目中,在settings.py中将应用加入到INSTALLED_APPS选项中

应用目录介绍:

_ init_.py:

​ 其中暂无内容,使得app成为一个包

admin.py:

​ 管理站点模型的声明文件,默认为空

apps.py:

​ 应用信息定义文件,在其中生成了AppConfig,该类用于定义应用名等数据

models.py:

​ 添加模型层数据类文件

views.py:

​ 定义URL相应函数,视图函数

migrations包:

​ 自动生成,生成迁移文件的

test.py:

​ 测试代码文件

7. 基本视图

视图函数

8. 基本模板

模板实际上就是我们用HTML写好的页面

创建模板文件夹templates,在模板文件夹中创建模板文件

在views中去加载渲染模板,使用render函数:return render(request, ‘index.html’)

9. 定义模型

在models.py中引入models

from django.db import models

创建自己的模型类,但切记要继承自 models.Model

class UserModel(models.Model):
    name = models.CharField(max_length=30, unique=True)  # 对应的SQL:name varchar(30)
    age = models.IntegerField(default=18)  # 对应的SQL:age int default 18
    sex = models.CharField(max_length=20)  # 对应的SQL:sex varchar(20)
    is_delete = models.BooleanField(default=False)  # 对应的SQL:is_delete Boolean

10. Admin后台管理

在admin.py中将model加入后台管理:

admin.site.register(UserModel)

创建超级用户:python manage.py createsuperuser

访问admin后台:http://127.0.0.1:8000/admin/

Django路由

路由的分发:主路由转发到各个应用路由的过程

1. 路由匹配

# 使用url给视图函数传参数
path('index/', index)
path('detail/<int:id>/', detail)

# 给url取别名,那么在使用此url的地方可以使用别名
path('index/', index, name='index')
path('detail/<int:id>/', detail, name='detail')

reverse('index') <==> 'index/'

2. 命名空间

为了防止路由冲突,Django提供了命名空间的概念:命名空间是一种将路由命名为层次结构的方式,使得在查询路由时可以限定在该命名空间内。

# 使用命名空间
path('user/', include(('App.urls', 'App'), namespace='App'))

3. 反向解析

Django路由反向解析是一个非常重要的功能,它可以让我们在代码中使用路由别名替代URL路径,在修改URL时避免代码中的硬编码依赖,同时也可以提高可读性和可维护性。

#在视图函数中反向解析url
from django.shortcuts import render, redirect, reverse

# 重定向
def my_redirect(request):
    # return redirect('https://www.baidu.com')
    # return redirect('/user/userlist/')
    # return redirect('/user/detail/2/')

    # 反向解析 带命名空间
    # return redirect(reverse('App:userdetail', args=(1,)))     # 位置参数传参
    return redirect(reverse('App:userdetail', kwargs={'uid': 1}))  # 关键字传参
    # 不带命名空间
    # return redirect(reverse('userdetail', kwargs={'uid': 1}))

4. 传参

path('detail/<int:uid>/', user_detail, name='userdetail'),
def user_detail(request, uid):
    user = UserModel.objects.get(pk=uid)
    return render(request, 'user_detail.html', {'user': user})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户详情</title>
</head>
<body>
    <h2>用户详情</h2>
    <hr>
    <h3>{{ user.name }} - {{ user.age }}</h3>
</body>
</html>

Django模板

模板Template

在Django框架中,模板是可以帮助开发者快速生成呈现给用户页面的工具

模板的设计方式实现了我们 MVT 中 VT 的解耦**(M:Model,V:View,T:Template)**,VT有着 N : M 的关系,一个V可以调用任意个T,一个T可以被任意个V使用。

模板处理分为两个过程

  • 加载HTML

  • 渲染数据

模板主要有两个部分

  • HTML静态代码

  • 模板语言,动态插入的代码段

模板中的动态代码段除了做基本的静态填充,还可以实现一些基本的运算,转换和逻辑

静态页面:页面数据是本地固定的

动态页面:页面数据来源于后台服务器

模板中的变量:视图传递给模板的数据,遵守标识符规则

​ 语法:{{ var }}

​ 如果变量不存在,则插入空字符串

方法不能有参数

  • {{ str }}
  • {{ str.upper }}
  • {{ str.isdigit }}
  • {{ dict.key }}

列表,使用索引,不允许负索引

items = [‘apples’, ‘bananas’, ‘carrots’]

{{ items.2 }}

模板中的标签

语法:{{% tag %}}

作用:

  1. 加载外部传入的变量
  2. 在输出中创建文本
  3. 控制循环或逻辑

if 语句

if单分支:
{% if 表达式 %}
    语句
{% endif %} 

if双分支:
{% if 表达式 %}
	语句
{% else %}
	语句
{% endif %} 

if多分枝:
{% if 表达式 %}
	语句
{% elif %}
	语句
{% else %}
	语句
{% endif %} 

判断true或false:
{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% endif %} 

使用 and or not

使用 innot in
{% if "bc" in "abcdefg" %}
    语句
{% endif %}

for 语句

{% for 变量 in 列表 %}
    语句
{% empty %}
	语句
{% endfor %}
当列表为空或不存在时,执行empty之后的语句

{{ forloop.counter }}	表示当前是第几次循环,从1开始

{% for item in todo_list %}
	<p>{{ forloop.counter }}:{{ item }}</p>
{% endfor %}

{{ forloop.counter0 }}		表示当前是第几次循环,从0开始
{{ forloop.revcounter }}	表示当前是第几次循环,倒着数,到1{{ forloop.revcounter0 }}	表示当前是第几次循环,倒着数,到0{{ forloop.first }}			是否是第一个,返回布尔值
{{ forloop.last }}			是否是最后一个,返回布尔值
{{ forloop.parentloop }}	如果有多个循环嵌套,那么这个属性代表的是上一级的for循环

多行注释

{% comment %}
	内容
{% endcomment %}

过滤器

{{ var|过滤器 }}
作用:在变量显示前修改

add
	{{ value|add:2 }}
	没有减法过滤器,但是可以加负数
	{{ value|add:-2 }}

lower
	{{ name|lower }}

upper
	{{ my_list|upper }}

截断(从第10个字符开始显示...)(只显示前9个字符):
	{{ bio|truncatechars:10 }}

过滤器可以传递参数,参数需要使用引号引起来
比如:join: {{ students|join:"="}}

默认值:default,格式{{ var|default:value }}
如果变量值没有被提供或者为false,空,会使用默认值

根据指定格式转换日期为字符串,针对date进行转换
{{ dateVal | date:'y-m-d' }}
解析html
'code': '<b>I am a good man!</b>'
{{ code|safe }}
I am a good man!

# 模板中开启自动转义(默认开启),那么就会显示成一个普通的字符串
{% autoescape on %}
	<a href='www.baidu.com'>百度</a>
{% endautoescape %}

# 如果把on成off,那么就会显示百度的一个超链接
{% autoescape off %}
	<a href='www.baidu.com'>百度</a>
{% endautoescape %}

模板继承

block:
	{% block xxx %}
		代码
	{% endblock %}

extends继承(写在开头位置):
	{% extends '父模板路径' %}

include:加载模板进行渲染
	{% include '模板文件' %}

{{ block。supper }}:获取父模板中block中的内容

在Django项目中使用Jinja2

Jinja2是Flask框架中的模板引擎,是模仿Django默认模板引擎基础上开发的,比Django模板引擎性能好,功能更全。

1. 安装jinja2模块

pip install jinja2

检查是否已经安装Jinja2

pip freeze

2. 创建jinja2_env.py文件

在settings.py所在目录中创建jinja2_env.py文件,并写入以下内容

from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment


def environment(**options):
    env = Environment(**options)
    env.globals.update({
        'static': static,
        'url': reverse,
    })
    return env

settings.py

TEMPLATES = [
    # 使用jinja2模板引擎
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2'
        ,
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            # 这里要添加environment,并且指定到jinja2_env文件中的environment
            'environment': 'DjangoPro2.jinja2_env.environment',
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
    {
        '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',
            ],
        },
    },
]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h2>Jinja2模板引擎</h2>
    <p>{{ name }}</p>
    <hr>
    {% for n in name %}
        <div>
            {{ loop.index }}:{{ n }}
        </div>
    {% endfor %}
    
    {#  Jinja2 可以调用函数  #}
    {% for i in range(1,5) %}
        <div>
            {{ i }}
        </div>
    {% endfor %}

</body>
</html>

Django配置MySQL

settings.py

DATABASES = {
    # 配置MySQL
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_mysql',
        'USER': 'root',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

SQLalchemy

SQLAlchemy是Python SQL工具包和对象关系映射器,是python中最著名的ORM(Object Relationship Mapping)框架,它简化了应用程序开发人员在原生SQL上的操作,使开发人员将主要精力都放在程序逻辑上,从而提高开发效率。它提供了一整套著名的企业级持久性模式,设计用于高效和高性能的数据库访问。

使用ORM操作数据库:
优势 :代码易读,隐藏底层原生SQL语句,提高了开发效率。
劣势 :执行效率低 ,将方法转换为原生SQL后 原生SQL不一定是最优的

连接数据库

from sqlalchemy import create_engine

# 连接数据库
# create_engine方法用于创建一个数据库连接对象
# 数据库类型+数据库驱动://用户名:密码@主机名:端口号/数据库名
engine = create_engine('mysql://root:1234@localhost:3306/sql_test')

原生SQL查询

import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import *


engine = create_engine('mysql://root:1234@localhost:3306/mp')

conn = engine.connect()

query = sqlalchemy.text('SELECT * FROM user limit 5')

result_set = conn.execute(query)

for row in result_set:
    print(row)

conn.close()

engine.dispose()

创建表

import sqlalchemy

engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)

meta_data = sqlalchemy.MetaData()

person = sqlalchemy.Table(
    'person', meta_data,
    sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
    sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
    sqlalchemy.Column('age', sqlalchemy.Boolean, default=False, nullable=False)
)

meta_data.create_all(engine)

插入数据

插入单条记录

import sqlalchemy

engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)

meta_data = sqlalchemy.MetaData()

person = sqlalchemy.Table(
    'person', meta_data,
    sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
    sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
    sqlalchemy.Column('age', sqlalchemy.String(3), default=18, nullable=False)
)

meta_data.create_all(engine)

# insert a record
person_insert = person.insert()
print(person_insert)
insert_sql = person_insert.values(name='John', age=20)

with engine.connect() as conn:
    conn.execute(insert_sql)
    conn.commit()

engine.dispose()

插入多条记录

import sqlalchemy

engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)

meta_data = sqlalchemy.MetaData()

person = sqlalchemy.Table(
    'person', meta_data,
    sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
    sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
    sqlalchemy.Column('age', sqlalchemy.String(3), default=18, nullable=False)
)

meta_data.create_all(engine)

person_insert = person.insert()

with engine.connect() as conn:
    conn.execute(person_insert, [
        {'name': 'Jack', 'age': 23},
        {'name': 'rous', 'age': 20},
        {'name': 'Yohan', 'age': 21},
    ])
    conn.commit()

engine.dispose()

映射

from sqlalchemy import create_engine, Column, Integer, String, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)

Base = declarative_base()


class Person(Base):
    __tablename__ = 'person'

    id = Column(Integer, primary_key=True)
    name = Column(String(20), unique=True, nullable=False)
    birthday = Column(Date, nullable=False)
    address = Column(String(50), nullable=False)

    def __str__(self):
        return f'{{Person: id:{self.id}, name:{self.name}, birthday:{self.birthday}, address:{self.address}}}'


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

新的映射

from datetime import date, datetime
from typing import Annotated

from sqlalchemy import create_engine, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column
from sqlalchemy.sql import func

engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)
Base = declarative_base()

# 避免代码重复 对部分进行抽象提取
int_pk = Annotated[int, mapped_column(primary_key=True)]
required_unique_name = Annotated[str, mapped_column(String(20), unique=True, nullable=False)]
timestamp_default = Annotated[datetime, mapped_column(nullable=False, server_default=func.now())]


class Customer(Base):
    __tablename__ = 'customer'

    # id: Mapped[int] = mapped_column(primary_key=True)
    # name: Mapped[str] = mapped_column(String(20), unique=True, nullable=False)
    # birthday: Mapped[date]

    id: Mapped[int_pk]
    name: Mapped[required_unique_name]
    birthday: Mapped[date]
    city: Mapped[str] = mapped_column(String(20), nullable=True)
    create_time: Mapped[timestamp_default]


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

ORM映射

from datetime import datetime, date
from typing import List

from sqlalchemy import create_engine, String, func, ForeignKey
from sqlalchemy.orm import declarative_base, Mapped, mapped_column, sessionmaker, relationship
from typing_extensions import Annotated

engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)
Base = declarative_base()

int_pk = Annotated[int, mapped_column(primary_key=True)]
required_unique_name = Annotated[str, mapped_column(String(20), unique=True, nullable=False)]
timestamp_not_null = Annotated[datetime, mapped_column(server_default=func.now(), nullable=False)]


class Department(Base):
    __tablename__ = 'department'

    id: Mapped[int_pk]
    name: Mapped[required_unique_name]
    create_time: Mapped[timestamp_not_null]

    # 一对多关系用懒惰,避免查一个部门连带查出很多员工的情况降低查询效率
    employees: Mapped[List["Employee"]] = relationship(back_populates="department")

    def __repr__(self):
        return f'{{department: id: {self.id}, name: {self.name}, create_time: {self.create_time}}}'


class Employee(Base):
    __tablename__ = 'employee'

    id: Mapped[int_pk]
    dep_id: Mapped[int] = mapped_column(ForeignKey("department.id"))
    name: Mapped[required_unique_name]
    birthday: Mapped[date] = mapped_column(nullable=False)

    # 定义一个属性 将该属性指向Department对象(relationship():关联关系字段)
    # 并不是指向数据库的某个字段 而是指向内存中的对象
    # 默认 lazy=True:懒惰的,分开查询。lazy=False:利用join一次查询,效率高
    # backref="employees":在department中隐藏(隐式定义关联)
    # back_populates="employees":显示定义关联关系,department中也需要写出关联语句与
    department: Mapped[Department] = relationship(lazy=False, back_populates="employees")

    def __repr__(self):
        return f'{{employee: id: {self.id}, dep_id: {self.dep_id}, name: {self.name}, birthday: {self.birthday}}}'


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
  • 19
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值