DailyNotes
                                
                                
                                
                                    DailyNotes copied to clipboard
                            
                            
                            
                        [Question] Postgress database support
I've tried to use an Postgress database for DialyNotes as database engine, because sqlalchemy does support it. But using the following connection string wont work, what i am doing wrong? DATABASE_URI = username:password@host:port/database_name https://www.geeksforgeeks.org/connecting-postgresql-with-sqlalchemy-in-python/
I have a similar issue. I have:
DATABASE_URI=postgresql://postgres:postgres@postgres:5432
and DailyNotes appears to connect. But since tables schemas have not been set up I get these errors:
dailynotes_1  | Traceback (most recent call last):
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1900, in _execute_context
dailynotes_1  |     self.dialect.do_execute(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
dailynotes_1  |     cursor.execute(statement, parameters)
dailynotes_1  | psycopg2.errors.UndefinedTable: relation "note" does not exist
dailynotes_1  | LINE 2: FROM note
dailynotes_1  |              ^
dailynotes_1  |
dailynotes_1  |
dailynotes_1  | The above exception was the direct cause of the following exception:
dailynotes_1  |
dailynotes_1  | Traceback (most recent call last):
dailynotes_1  |   File "./verify_data_migrations.py", line 30, in <module>
dailynotes_1  |     main()
dailynotes_1  |   File "./verify_data_migrations.py", line 13, in main
dailynotes_1  |     first_note = Note.query.first()
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2823, in first
dailynotes_1  |     return self.limit(1)._iter().first()
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2907, in _iter
dailynotes_1  |     result = self.session.execute(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1712, in execute
dailynotes_1  |     result = conn._execute_20(statement, params or {}, execution_options)
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1705, in _execute_20
dailynotes_1  |     return meth(self, args_10style, kwargs_10style, execution_options)
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 333, in _execute_on_connection
dailynotes_1  |     return connection._execute_clauseelement(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1572, in _execute_clauseelement
dailynotes_1  |     ret = self._execute_context(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1943, in _execute_context
dailynotes_1  |     self._handle_dbapi_exception(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2124, in _handle_dbapi_exception
dailynotes_1  |     util.raise_(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
dailynotes_1  |     raise exception
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1900, in _execute_context
dailynotes_1  |     self.dialect.do_execute(
dailynotes_1  |   File "/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
dailynotes_1  |     cursor.execute(statement, parameters)
dailynotes_1  | sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "note" does not exist
dailynotes_1  | LINE 2: FROM note
dailynotes_1  |              ^
dailynotes_1  |
dailynotes_1  | [SQL: SELECT note.uuid AS note_uuid, note.user_id AS note_user_id, note.data AS note_data, note.title AS note_title, note.date AS note_date, note.is_date AS note_is_date
dailynotes_1  | FROM note
dailynotes_1  |  LIMIT %(param_1)s]
dailynotes_1  | [parameters: {'param_1': 1}]
dailynotes_1  | (Background on this error at: https://sqlalche.me/e/14/f405)
It appears we need some sql script that'll initialize the tables, I believe, according to the model classes in app/models.py.
I spent a few hours trying to get this to work.  I instantiated the latest Postgres Docker container (postgres:14.4-alpine3.16) with this file /docker-entrypoint-initdb.d/init.sql  which will execute those SQL commands on first startup.
CREATE TABLE user_account (
        uuid CHAR(32) NOT NULL,
        username VARCHAR(64) NOT NULL,
        password_hash VARCHAR(128) NOT NULL,
        auto_save BOOLEAN,
        PRIMARY KEY (uuid),
        UNIQUE (username)
);
CREATE UNIQUE INDEX ix_user_uuid ON user_account (uuid);
CREATE TABLE IF NOT EXISTS "note" (
        uuid CHAR(32) NOT NULL,
        user_id CHAR(32) NOT NULL,
        data VARCHAR,
        title VARCHAR(128) NOT NULL,
        date TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
        is_date BOOLEAN,
        PRIMARY KEY (uuid),
        FOREIGN KEY(user_id) REFERENCES user_account (uuid)
);
CREATE UNIQUE INDEX ix_note_uuid ON note (uuid);
CREATE TABLE meta (
        uuid CHAR(32) NOT NULL,
        user_id CHAR(32) NOT NULL,
        note_id CHAR(32) NOT NULL,
        name VARCHAR,
        name_compare VARCHAR,
        kind VARCHAR,
        PRIMARY KEY (uuid),
        FOREIGN KEY(note_id) REFERENCES note (uuid),
        FOREIGN KEY(user_id) REFERENCES user_account (uuid)
);
CREATE UNIQUE INDEX ix_meta_uuid ON meta (uuid);
But there are a number of issues.  First the user table needed to be renamed to user_account because USER is a Postgres keyword.  This caused ripple effects in the code.  I thought by adding into the model:
class User(db.Model):
  __tablename__ = 'user_account'
  # ...
I also needed to update
class GUID(TypeDecorator):
  cache_ok = True
  # ...
That didn't work, even after updating a few ForeignKey calls in the same file.
I also ran into a ton more issues when trying to put this behind an Nginx reverse proxy.  The DailyNotes project doesn't use the BASE_URL properly in all places, and I never got it fully working.
I don't have enough time to continue debugging this. Which is unfortunate because it looked promising for my use cases, and was looking forward to adding features for my use cases.
Yeah, I need to dig into why other databases aren't working properly, but SQLite has worked perfectly for me, so I haven't done it yet.
What issues are you having running it behind a reverse proxy?
My initial assessment is that the static files are not being served under $BASE_URL.  They get served under /.
My Docker Compose script:
---
version: "3.8"
services:
  postgres:
    image: "${IMAGE_POSTGRES}"
    environment:
      PGPORT: "${POSTGRES_PORT}"
      POSTGRES_DB: "${POSTGRES_DATABASE}"
      POSTGRES_USER: "${POSTGRES_USERNAME}"
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
    logging:
      driver: syslog
      options:
        tag: "{{.Name}}/{{.ID}}"
    restart: unless-stopped
    volumes:
      - ./.volumes/postgres/:/var/lib/postgresql/data/
      - ./services/postgres/:/docker-entrypoint-initdb.d/:ro
  pgadmin:
    image: "${IMAGE_PGADMIN}"
    depends_on:
      - postgres
    environment:
      PGADMIN_LISTEN_PORT: "${PGADMIN_PORT}"
      PGADMIN_DEFAULT_EMAIL: "${PGADMIN_DEFAULT_EMAIL}"
      PGADMIN_DEFAULT_PASSWORD: "${PGADMIN_DEFAULT_PASSWORD}"
      PGADMIN_BASEURL: "${PGADMIN_BASEURL}"
    logging:
      driver: syslog
      options:
        tag: "{{.Name}}/{{.ID}}"
    restart: unless-stopped
    volumes:
      - ./services/pgadmin/servers.json:/pgadmin4/servers.json:ro
  dailynotes:
    build:
      context: ./services/DailyNotes
    depends_on:
      - postgres
    environment:
      BASE_URL: "${DAILYNOTES_BASE_URL}"
      DATABASE_URI: "${DAILYNOTES_DATABASE_URI}"
    logging:
      driver: syslog
      options:
        tag: "{{.Name}}/{{.ID}}"
    ports:
      - ${DAILYNOTES_PORT}:5000
    volumes:
      - ./.volumes/dailynotes:/app/config
  nginx:
    image: "${IMAGE_NGINX}"
    depends_on:
      - postgres
      - pgadmin
      - dailynotes
    environment:
      PGADMIN_PORT: "${PGADMIN_PORT}"
      DAILYNOTES_BASE_URL: "${DAILYNOTES_BASE_URL}"
      PGADMIN_BASEURL: "${PGADMIN_BASEURL}"
    logging:
      driver: syslog
      options:
        tag: "{{.Name}}/{{.ID}}"
    ports:
      - "443:443"
      - "80:80"
    restart: unless-stopped
    volumes:
      - ./services/nginx/default.conf.template:/etc/nginx/templates/default.conf.template:ro
The Nginx config:
log_format ssl_client_logger
    '$remote_addr [$ssl_client_s_dn] $remote_user [$time_local]'
    ' "$request" $status $body_bytes_sent "$http_referer"'
    ' "$http_user_agent"'
    ' "$upstream_response_time"'
    ;
server {
    listen 80;
    server_name nonsecure.local.denizen.net;
    # Route all logs to the container's /dev/stdout which is captured by Docker
    # Compose and sent to the hosts syslog server.
    access_log /dev/stdout ssl_client_logger;
    error_log /dev/stdout info;
    location ${PGADMIN_BASEURL}/ {
        proxy_pass http://pgadmin:${PGADMIN_PORT};
        proxy_http_version 1.1;
        proxy_set_header Connection         "upgrade";
        proxy_set_header Host               $http_host;
        proxy_set_header Upgrade            $http_upgrade;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_set_header X-Nginx-Proxy      true;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Script-Name      ${PGADMIN_BASEURL};
        proxy_redirect off;
    }
    location ${DAILYNOTES_BASE_URL} {
        proxy_pass http://dailynotes:5000;
        proxy_http_version 1.1;
        proxy_set_header Connection         "upgrade";
        proxy_set_header Host               $http_host;
        proxy_set_header Upgrade            $http_upgrade;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_set_header X-Nginx-Proxy      true;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_redirect off;
    }
}
My Docker Compose .env file:
IMAGE_NGINX=nginx:1.23.1-alpine
IMAGE_PGADMIN=dpage/pgadmin4:6.14
IMAGE_POSTGRES=postgres:14.4-alpine3.16
################################################################################
# Postgres Configuration.
# The port to bind Postgres to inside the container.
POSTGRES_PORT=5432
# The database for Daily Notes.
POSTGRES_DATABASE=dailynotes
# The username+password credentials for the database.
#       The password should be changed in production!
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=postgres
################################################################################
# pgAdmin Configuration.
# The port to bind pgAdmin to INSIDE and OUTSIDE the container.
PGADMIN_PORT=5050
# Initial "admin" user.
#       The password should be changed in production!
[email protected]
PGADMIN_DEFAULT_PASSWORD=p@55w0rd
# Set the backend URI.
#       This is "BASEURL" variable that should not contain a trailing slash!
PGADMIN_BASEURL=/pgadmin
################################################################################
# Daily Notes.
# The poinr to bind Daily Notes to OUTSIDE the container.
DAILYNOTES_PORT=5000
# Set the backend URI.
#       This is "BASEURL" variable that MUST contain a trailing slash!
DAILYNOTES_BASE_URL=/dailynotes/
# THe URI to the Postgres SQL database.
DAILYNOTES_DATABASE_URI=postgresql://postgres:postgres@postgres:5432
# The database encryption key.
DAILYNOTES_DB_ENCRYPTION_KEY=0123456789ABCDEF
# Prevent signups??
DAILYNOTES_PREVENT_SIGNUPS=False
################################################################################
# Nginx Configuration.
# nothing yet.
                                    
                                    
                                    
                                
I'll have to look at that and see what's going on