34
loading...
This website collects cookies to deliver better user experience
heroku login
heroku git:remote -a herokuappname
heroku psql
Whoops there I forgot to set my Windows code page, hence why the Warning appeared. If you also encountered this, when opening command prompt for the first time, type in the code below before doing anything since it will mess up your queries
chcp 1252
\d
exit
### ADD THIS ###
import dj_database_url
### ADD THIS ###
DATABASE_URL = 'postgres://<insert your URI code>'
### CHANGE THIS ###
DATABASES = {
'default': dj_database_url.config(),
}
### ADD THIS ###
DATABASES['default'] = dj_database_url.config()
DATABASES['default'] = dj_database_url.config(default=DATABASE_URL)
### COMMENT ###
"""
Django settings for vlnxHobby project.
Generated by 'django-admin startproject' using Django 3.2.7.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
### ADD THIS ###
import dj_database_url
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
PRODUCTION = os.environ.get('DATABASE_URL') != None
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'secret'
# 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',
'home',
]
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',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
ROOT_URLCONF = 'vlnxHobby.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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 = 'vlnxHobby.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
### ADD THIS ###
DATABASE_URL = 'postgres://<insert your URI code>'
### CHANGE THIS ###
DATABASES = {
'default': dj_database_url.config(),
}
### ADD THIS ###
DATABASES['default'] = dj_database_url.config()
DATABASES['default'] = dj_database_url.config(default=DATABASE_URL)
if PRODUCTION:
DATABASES['default'] = dj_database_url.config()
# Password validation
# https://docs.djangoproject.com/en/3.2/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/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')
As seen from the Database Settings on Heroku, the Credentials are not permanent and from time-to-time will update on itself, changing the URI. My solution right now is static and does not auto-update the URI, or that's what I think. If you suddenly can't connect to the database, the first thing you should do is to check and match the DATABASE_URL on settings.py with the URI on Heroku
heroku login
heroku git:remote -a herokuappname
heroku psql
heroku psql
(env) D:\Projects\heroku-hobby\vlnxHobby>heroku psql
» Warning: heroku update available from 7.53.0 to 7.59.2.
--> Connecting to postgresql-rectangular-05497
psql (14.1, server 13.5 (Ubuntu 13.5-1.pgdg20.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
vlnx-hobby::DATABASE=> CREATE SCHEMA UserSystem;
CREATE SCHEMA
vlnx-hobby::DATABASE=> SET search_path TO UserSystem;
SET
vlnx-hobby::DATABASE=>
vlnx-hobby::DATABASE=> CREATE TABLE USER_PROFILE(
vlnx-hobby::DATABASE(> email VARCHAR(50),
vlnx-hobby::DATABASE(> password VARCHAR(50) NOT NULL,
vlnx-hobby::DATABASE(> fname VARCHAR(50) NOT NULL,
vlnx-hobby::DATABASE(> PRIMARY KEY (email)
vlnx-hobby::DATABASE(> );
CREATE TABLE
vlnx-hobby::DATABASE=>
vlnx-hobby::DATABASE=> CREATE TABLE MESSAGES(
vlnx-hobby::DATABASE(> id Varchar(50),
vlnx-hobby::DATABASE(> email Varchar(50) NOT NULL,
vlnx-hobby::DATABASE(> title Varchar(50) NOT NULL,
vlnx-hobby::DATABASE(> content text NOT NULL,
vlnx-hobby::DATABASE(> PRIMARY KEY (id),
vlnx-hobby::DATABASE(> FOREIGN KEY (email) REFERENCES USER_PROFILE(email)
vlnx-hobby::DATABASE(> ON UPDATE CASCADE ON DELETE CASCADE
vlnx-hobby::DATABASE(> );
CREATE TABLE
vlnx-hobby::DATABASE=>
vlnx-hobby::DATABASE=> INSERT INTO USER_PROFILE VALUES
vlnx-hobby::DATABASE-> ('[email protected]','123abc','Andi'),
vlnx-hobby::DATABASE-> ('[email protected]','456abc','Peko'),
vlnx-hobby::DATABASE-> ('[email protected]','789abc','Krow');
INSERT 0 3
vlnx-hobby::DATABASE=>
vlnx-hobby::DATABASE=> INSERT INTO MESSAGES VALUES
vlnx-hobby::DATABASE-> ('1','[email protected]','Hello World','This is my first message'),
vlnx-hobby::DATABASE-> ('2','[email protected]','Second Message','This is my second message'),
vlnx-hobby::DATABASE-> ('3','[email protected]','ATTN','Qapla'),
vlnx-hobby::DATABASE-> ('4','[email protected]','My Only Message','This is my only message');
INSERT 0 4
vlnx-hobby::DATABASE=>
set search_path to userSystem
SELECT * FROM USER_PROFILE;
vlnx-hobby::DATABASE=> SELECT * FROM USER_PROFILE;
email | password | fname
----------------------+----------+-------
[email protected] | 123abc | Andi
[email protected] | 456abc | Peko
[email protected] | 789abc | Krow
(3 rows)
vlnx-hobby::DATABASE=>
from django.db import connection
from collections import namedtuple
def namedtuplefetchall(cursor):
"Return all rows from a cursor as a namedtuple"
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
def index(request):
cursor = connection.cursor()
try:
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT FNAME FROM USER_PROFILE")
result = namedtuplefetchall(cursor)
except Exception as e:
print(e)
finally:
cursor.close()
return render(request, 'home/index.html', {'result': result})
cursor = connection.cursor()
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT * FROM USER_PROFILE")
result = namedtuplefetchall(cursor)
Personal tip:
You can try printing the result to see what it actually contains to give you a better understanding of the content
cursor.close()
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'home/style.css' %}">
<title>Hello</title>
</head>
<body>
<h1>Hello World</h1>
{% for res in result %}
<p>Name: {{ res.fname }}</p>
{% endfor %}
</body>
</html>
Notes:
Sometimes you'll be getting UnboundLocalError. This is because the result variable is inside the Try Except Finally blocks. You can solve this by initiating the variable first above the Try Except Finally blocks.
from django.shortcuts import render
from django.db import connection
from collections import namedtuple
# Create your views here.
# Function to return every row of data from query
def namedtuplefetchall(cursor):
"Return all rows from a cursor as a namedtuple"
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
def index(request):
cursor = connection.cursor()
result = []
try:
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT FNAME FROM USER_PROFILE")
result = namedtuplefetchall(cursor)
except Exception as e:
print(e)
finally:
cursor.close()
return render(request, 'home/index.html', {'result': result})
from django import forms
class LoginForm(forms.Form):
email = forms.CharField(label='E-Mail Address', max_length=50)
password = forms.CharField(label='Password', max_length=50)
from django.urls import path
from . import views
app_name = 'home'
urlpatterns = [
path('', views.index, name='index'),
path('login', views.login, name='login'),
path('viewMessage', views.loggedInView, name='login'),
path('logout', views.logout, name='login'),
]
from django.http.response import HttpResponseNotFound, HttpResponseRedirect
from django.shortcuts import render
from django.db import connection
from collections import namedtuple
from .forms import *
# Create your views here.
# Function to return every row of data from query
def namedtuplefetchall(cursor):
"Return all rows from a cursor as a namedtuple"
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
def index(request):
cursor = connection.cursor()
result = []
try:
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT FNAME FROM USER_PROFILE")
result = namedtuplefetchall(cursor)
except Exception as e:
print(e)
finally:
cursor.close()
return render(request, 'home/index.html', {'result': result})
def login(request):
result = []
# Define login form
MyLoginForm = LoginForm(request.POST)
# Form submission
if (MyLoginForm.is_valid() and request.method == 'POST'):
# Get data from form
email = MyLoginForm.cleaned_data['email']
password = MyLoginForm.cleaned_data['password']
# Run SQL QUERY
try:
cursor = connection.cursor()
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT * FROM USER_PROFILE AS ADM WHERE ADM.email ='" + email + "' AND ADM.PASSWORD = '" + password + "'")
result = cursor.fetchone()
if(result == None):
return HttpResponseNotFound("The user does not exist")
# Redirect the cursor towards public so it can access Django basic features
cursor.execute("SET SEARCH_PATH TO public")
request.session['email'] = [email, password, result]
except Exception as e:
print(e)
cursor.close()
finally:
# Don't forget to close
cursor.close()
return HttpResponseRedirect('/viewMessage')
else:
MyLoginForm = LoginForm()
return render(request, 'home/login.html', {'form' : MyLoginForm})
# Function to test logged in result
def loggedInView(request):
if request.session.has_key('email'):
cursor = connection.cursor()
result = []
try:
cursor.execute("SET SEARCH_PATH TO USERSYSTEM")
cursor.execute("SELECT * FROM MESSAGES WHERE EMAIL = '"+ request.session['email'][0] +"'")
result = namedtuplefetchall(cursor)
except Exception as e:
print(e)
finally:
cursor.close()
return render(request, 'home/loggedin.html', {"result" : result})
else:
return HttpResponseRedirect('/login')
# Function to log out the user
def logout(request):
try:
del request.session['email']
except:
pass
return HttpResponseRedirect('/login')
cursor.fetchone()
request.session['key'] = value
IMPORTANT NOTE
Currently, our cursor is pointed towards our schema which is userSystem. This means that Django is unable to interact with its basic table, and that also means we can't really put anything such as user and session. That is why, after executing the SQL query, I pointed back the cursor towards the public schema so Django can access them back again.
cursor.execute("SET SEARCH_PATH TO public")
cursor.execute("SELECT * FROM MESSAGES WHERE EMAIL = '"+ request.session['email'][0] +"'")
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'home/style.css' %}">
<title>Hello</title>
</head>
<body>
<h1>Login Form</h1>
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'home/style.css' %}">
<title>Hello</title>
</head>
<body>
<h1>Hello World</h1>
{% for res in result %}
<h3>Title: {{ res.title }}</h3>
<p>Sender: {{ res.email }}</p>
<p>Name: {{ res.content }}</p>
{% endfor %}
</body>
</html>
del request.session['email']