这是一个从头开始到在可重现的 Docker 容器中使用 PostgreSQL 工作的 Django 的示例,以及在没有找到可重现/有用的示例的情况下通过各种方法的最小/最大值。我只是想到了类似的事情,所以我创建它只是为了好玩,如果有帮助,请随意使用它。 :)
从 Docker Compose 开始,我创建了 2 个容器 - 一个用于 Django,一个用于 PostgreSQL,并为其设置了一些默认值,例如密码、连接性等,并挂载当前工作目录以覆盖文件系统以便能够编辑按需而不需要重建。
示例docker-compose.yml 用于测试:
version: "3.7"
services:
my-postgres:
image: postgres:alpine
environment:
POSTGRES_PASSWORD: password
django:
build:
context: "."
dockerfile: Dockerfile
environment:
ENGINE: "django.db.backends.postgresql_psycopg2"
USER: postgres
PASSWORD: password
HOST: "my-postgres"
PORT: 5432
NAME: postgres
volumes:
- .:/tmp
对于客户端,需要有一个编译器(除非你有不同的包)、头文件、共享对象(库)。对于 Alpine,您还需要 musl-dev 用于 limits.h 和其他标头 + 共享对象。
使用Dockerfile:
FROM python:alpine
RUN apk add postgresql postgresql-dev gcc musl-dev
WORKDIR /tmp
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . ./
WORKDIR /tmp/app
ENTRYPOINT python manage.py runserver
requirements.txt
asgiref==3.3.1
Django==3.1.6
pytz==2021.1
sqlparse==0.4.1
psycopg2==2.8.6
Tree
在当前目录中发出了django-admin 命令,这就是为什么您看到app/app 结构可能看起来很奇怪。这是因为django-admin 命令中的项目命名为app。
.
├── app
│ ├── app
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ └── pg
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
如何运行:
docker-compose build
docker-compose up -d
docker-compose logs -f # to check the logs
docker-compose exec django python manage.py shell # to play in REPL
docker-compose exec django sh # to play in shell
修改后的文件:
settings.py:
# modified
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pg'
]
from os import environ
DATABASES = {
'default': {
item: environ.get(item)
for item in ["ENGINE", "NAME", "USER", "PASSWORD", "HOST", "PORT"]
}
}
# modified end
pg 应用程序
它是一个单独的 Django 应用程序,通过创建的manage.py 文件在一个空的 Django 项目中从头开始创建:
django-admin startproject app
cd app
python manage.py startapp pg
# edit models.py before migrations step (of course)
python manage.py makemigrations pg
python manage.py migrate
pg/models.py:
from django.db import models
from django.contrib.postgres.fields import ArrayField
class MyModel(models.Model):
array = ArrayField(models.IntegerField())
def __str__(self):
return f"<My Model ({self.id})>: {self.array}"
Insert
就好像一个普通的Django模型一样:
>>> from pg import models
>>> models.MyModel.objects.all()
<QuerySet []>
>>> models.MyModel.objects.create(array=[1,5,9])
<MyModel: MyModel object (1)>
>>> models.MyModel.objects.create(array=[2,1,0])
<MyModel: MyModel object (2)>
>>> models.MyModel.objects.all()
<QuerySet [<MyModel: <My Model (1)>: [1, 5, 9]>, <MyModel: <My Model (2)>: [2, 1, 0]>]>
Min/Max
可以通过多种方式完成,具体取决于您是要利用 Python 还是聚合
>>> # single object min/max, uses Django i.e. your machine
>>> min(models.MyModel.objects.get(id=1).array)
1
>>> max(models.MyModel.objects.get(id=1).array)
9
>>> # sum min/max, same machine
>>> min([sum(item.array) for item in models.MyModel.objects.all()])
3
>>> max([sum(item.array) for item in models.MyModel.objects.all()])
15
Aggregating
>>> from django.db.models import Min, Max
>>> models.MyModel.objects.aggregate(Min("array"))
{'array__min': [1, 5, 9]}
>>> models.MyModel.objects.aggregate(Max("array"))
{'array__max': [2, 1, 0]}
通过 Django 本身执行数组项似乎相当有问题,但有一点 raw query 没有问题(至少使用 min()):
from django.db.models.expressions import RawSQL
>>> models.MyModel.objects.annotate(max=RawSQL(
"select (select max(x) from unnest(pg_mymodel.array) x)",
params=[]
)).values("max")
<QuerySet [{'max': 9}, {'max': 2}]>
即使是单个项目:
>>> models.MyModel.objects.filter(id=2).annotate(max=RawSQL(
"select (select max(x) from unnest(pg_mymodel.array) x)",
params=[]
)).values("max")
<QuerySet [{'max': 2}]>
根据您的用例,利用 PostgreSQL 进行繁重的工作(准备数据)或只是从数据库中提取原始数据而无需大量编辑为“原始”,然后例如通过多处理将数据处理成您想要的形状,利用您的机器进行繁重的计算。
如果你真的不喜欢原始查询,你可以create your own aggregating Expression。尽管有时使用预制数据创建 SQL 视图(可以通过迁移创建)、为此构建模型并通过 ORM 提取数据更容易/更快。使用最适合这项工作的工具,但如果不需要性能,请不要在上面花费太多时间。