mirror of https://github.com/snachodog/mybuddy.git
Update to Django 5.x (#746)
This commit is contained in:
parent
9b603a9e84
commit
49d8f2b340
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]
|
||||
python-version: [ '3.10', '3.11', '3.12' ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
|
|
2
Pipfile
2
Pipfile
|
@ -6,7 +6,7 @@ name = "pypi"
|
|||
[packages]
|
||||
boto3 = "*"
|
||||
dj-database-url = "*"
|
||||
django = "~=4.0"
|
||||
django = "~=5.0"
|
||||
django-axes = "*"
|
||||
django-filter = "*"
|
||||
django-imagekit = "*"
|
||||
|
|
|
@ -316,8 +316,8 @@ class FeedingAPITestCase(TestBase.BabyBuddyAPITestCaseBase):
|
|||
{
|
||||
"id": 3,
|
||||
"child": 1,
|
||||
"start": "2017-11-18T19:00:00-05:00",
|
||||
"end": "2017-11-18T19:15:00-05:00",
|
||||
"start": "2017-11-18T09:00:00-05:00",
|
||||
"end": "2017-11-18T09:15:00-05:00",
|
||||
"duration": "00:15:00",
|
||||
"type": "formula",
|
||||
"method": "bottle",
|
||||
|
@ -335,7 +335,7 @@ class FeedingAPITestCase(TestBase.BabyBuddyAPITestCaseBase):
|
|||
|
||||
def test_get_with_iso_filter(self):
|
||||
response = self.client.get(
|
||||
self.endpoint, {"start_min": "2017-11-18T11:30:00-05:00"}
|
||||
self.endpoint, {"start_min": "2017-11-18T04:00:00-05:00"}
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["count"], 3)
|
||||
|
|
|
@ -249,8 +249,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-18T14:00:00-05:00",
|
||||
"end": "2017-11-18T14:30:00-05:00",
|
||||
"start": "2017-11-18T09:00:00Z",
|
||||
"end": "2017-11-18T09:30:00Z",
|
||||
"duration": "00:30:00",
|
||||
"type": "breast milk",
|
||||
"method": "left breast",
|
||||
|
@ -263,8 +263,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-18T16:30:00-05:00",
|
||||
"end": "2017-11-18T17:00:00-05:00",
|
||||
"start": "2017-11-18T11:30:00Z",
|
||||
"end": "2017-11-18T12:00:00Z",
|
||||
"duration": "00:30:00",
|
||||
"type": "breast milk",
|
||||
"method": "right breast",
|
||||
|
@ -277,8 +277,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-18T19:00:00-05:00",
|
||||
"end": "2017-11-18T19:15:00-05:00",
|
||||
"start": "2017-11-18T14:00:00Z",
|
||||
"end": "2017-11-18T14:15:00Z",
|
||||
"duration": "00:15:00",
|
||||
"type": "formula",
|
||||
"method": "bottle",
|
||||
|
@ -292,8 +292,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-17T19:00:00-05:00",
|
||||
"end": "2017-11-17T19:15:00-05:00",
|
||||
"start": "2017-11-17T14:00:00Z",
|
||||
"end": "2017-11-17T14:15:00Z",
|
||||
"duration": "00:15:00",
|
||||
"type": "formula",
|
||||
"method": "bottle",
|
||||
|
@ -307,8 +307,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-11T19:00:00-05:00",
|
||||
"end": "2017-11-11T19:15:00-05:00",
|
||||
"start": "2017-11-11T14:00:00Z",
|
||||
"end": "2017-11-11T14:15:00Z",
|
||||
"duration": "00:15:00",
|
||||
"type": "formula",
|
||||
"method": "bottle",
|
||||
|
@ -322,8 +322,8 @@
|
|||
"fields":
|
||||
{
|
||||
"child": 1,
|
||||
"start": "2017-11-11T00:00:00-05:00",
|
||||
"end": "2017-11-11T00:15:00-05:00",
|
||||
"start": "2017-11-11T05:00:00Z",
|
||||
"end": "2017-11-11T05:15:00Z",
|
||||
"duration": "00:15:00",
|
||||
"type": "formula",
|
||||
"method": "bottle",
|
||||
|
|
|
@ -2,7 +2,6 @@ from os import getenv
|
|||
from time import time
|
||||
from functools import wraps
|
||||
|
||||
import pytz
|
||||
from urllib.parse import urlunsplit, urlsplit
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -55,8 +54,8 @@ class UserTimezoneMiddleware:
|
|||
user = request.user
|
||||
if hasattr(user, "settings") and user.settings.timezone:
|
||||
try:
|
||||
timezone.activate(pytz.timezone(user.settings.timezone))
|
||||
except pytz.UnknownTimeZoneError:
|
||||
timezone.activate(user.settings.timezone)
|
||||
except ValueError:
|
||||
pass
|
||||
return self.get_response(request)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytz
|
||||
import zoneinfo
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
|
@ -63,7 +63,9 @@ class Settings(models.Model):
|
|||
verbose_name=_("Language"),
|
||||
)
|
||||
timezone = models.CharField(
|
||||
choices=tuple(zip(pytz.common_timezones, pytz.common_timezones)),
|
||||
choices=sorted(
|
||||
tuple(zip(zoneinfo.available_timezones(), zoneinfo.available_timezones()))
|
||||
),
|
||||
default=timezone.get_default_timezone_name(),
|
||||
max_length=100,
|
||||
verbose_name=_("Timezone"),
|
||||
|
|
|
@ -20,7 +20,7 @@ DEBUG = bool(strtobool(os.environ.get("DEBUG") or "False"))
|
|||
|
||||
|
||||
# Applications
|
||||
# https://docs.djangoproject.com/en/4.0/ref/applications/
|
||||
# https://docs.djangoproject.com/en/5.0/ref/applications/
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"api",
|
||||
|
@ -48,7 +48,7 @@ INSTALLED_APPS = [
|
|||
]
|
||||
|
||||
# Middleware
|
||||
# https://docs.djangoproject.com/en/4.0/ref/middleware/
|
||||
# https://docs.djangoproject.com/en/5.0/ref/middleware/
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
|
@ -69,13 +69,13 @@ MIDDLEWARE = [
|
|||
|
||||
|
||||
# URL dispatcher
|
||||
# https://docs.djangoproject.com/en/4.0/topics/http/urls/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/http/urls/
|
||||
|
||||
ROOT_URLCONF = "babybuddy.urls"
|
||||
|
||||
|
||||
# Templates
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-TEMPLATES
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#std:setting-TEMPLATES
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ TEMPLATES = [
|
|||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
|
||||
|
||||
config = {
|
||||
"ENGINE": os.getenv("DB_ENGINE") or "django.db.backends.sqlite3",
|
||||
|
@ -118,7 +118,7 @@ DATABASES = {"default": config}
|
|||
|
||||
|
||||
# Cache
|
||||
# https://docs.djangoproject.com/en/4.0/topics/cache/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/cache/
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
|
@ -129,13 +129,13 @@ CACHES = {
|
|||
|
||||
|
||||
# WGSI
|
||||
# https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
|
||||
# https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
|
||||
|
||||
WSGI_APPLICATION = "babybuddy.wsgi.application"
|
||||
|
||||
|
||||
# Authentication
|
||||
# https://docs.djangoproject.com/en/4.0/topics/auth/default/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/auth/default/
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"axes.backends.AxesBackend",
|
||||
|
@ -158,14 +158,14 @@ if REVERSE_PROXY_AUTH:
|
|||
|
||||
|
||||
# Timezone
|
||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/timezones/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/i18n/timezones/
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/i18n/
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
@ -199,18 +199,26 @@ LANGUAGES = [
|
|||
|
||||
|
||||
# Format localization
|
||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/formatting/
|
||||
|
||||
USE_L10N = True
|
||||
# https://docs.djangoproject.com/en/5.0/topics/i18n/formatting/
|
||||
|
||||
FORMAT_MODULE_PATH = ["babybuddy.formats"]
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||
# http://whitenoise.evans.io/en/stable/django.html
|
||||
# Storage
|
||||
# https://docs.djangoproject.com/en/5.0/ref/files/storage/
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#std-setting-STORAGES
|
||||
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
STORAGES = {
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
||||
# http://whitenoise.evans.io/en/stable/django.html
|
||||
|
||||
STATICFILES_FINDERS = [
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
|
@ -225,7 +233,7 @@ WHITENOISE_ROOT = os.path.join(BASE_DIR, "static", "babybuddy", "root")
|
|||
|
||||
|
||||
# Media files (User uploaded content)
|
||||
# https://docs.djangoproject.com/en/4.0/topics/files/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/files/
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
|
@ -240,11 +248,11 @@ AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY") or None
|
|||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL") or None
|
||||
|
||||
if AWS_STORAGE_BUCKET_NAME:
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
STORAGES["default"]["BACKEND"] = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
|
||||
|
||||
# Email
|
||||
# https://docs.djangoproject.com/en/4.0/topics/email/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/email/
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
EMAIL_SUBJECT_PREFIX = "[Baby Buddy] "
|
||||
|
@ -263,17 +271,17 @@ if os.environ.get("EMAIL_HOST"):
|
|||
|
||||
# Security
|
||||
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#secure-proxy-ssl-header
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#secure-proxy-ssl-header
|
||||
if os.environ.get("SECURE_PROXY_SSL_HEADER"):
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
# https://docs.djangoproject.com/en/4.0/topics/http/sessions/#settings
|
||||
# https://docs.djangoproject.com/en/5.0/topics/http/sessions/#settings
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SECURE = bool(
|
||||
strtobool(os.environ.get("SESSION_COOKIE_SECURE") or "False")
|
||||
)
|
||||
|
||||
# https://docs.djangoproject.com/en/4.0/ref/csrf/#settings
|
||||
# https://docs.djangoproject.com/en/5.0/ref/csrf/#settings
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
CSRF_COOKIE_SECURE = bool(strtobool(os.environ.get("CSRF_COOKIE_SECURE") or "False"))
|
||||
CSRF_FAILURE_VIEW = "babybuddy.views.csrf_failure"
|
||||
|
@ -282,7 +290,7 @@ CSRF_TRUSTED_ORIGINS = list(
|
|||
)
|
||||
|
||||
|
||||
# https://docs.djangoproject.com/en/4.0/topics/auth/passwords/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/auth/passwords/
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
|
@ -349,7 +357,7 @@ AXES_LOCKOUT_URL = "/login/lock"
|
|||
ROLLING_SESSION_REFRESH = 86400
|
||||
|
||||
# Set default auto field for models.
|
||||
# See https://docs.djangoproject.com/en/4.0/releases/3.2/#customizing-type-of-auto-created-primary-keys
|
||||
# See https://docs.djangoproject.com/en/5.0/releases/3.2/#customizing-type-of-auto-created-primary-keys
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ SECRET_KEY = "CISECRETKEYIGUESS"
|
|||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
||||
|
||||
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
STORAGES["staticfiles"][
|
||||
"BACKEND"
|
||||
] = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
from .base import *
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
|
||||
# https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
|
||||
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY") or "DEVELOPMENT!!"
|
||||
DEBUG = bool(strtobool(os.environ.get("DEBUG") or "True"))
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
||||
#
|
||||
# Comment out STATICFILES_STORAGE and uncomment DEBUG = False to test with
|
||||
# production static files.
|
||||
# Comment out STORAGES["staticfiles"]["BACKEND"] and uncomment DEBUG = False to
|
||||
# test with production static files.
|
||||
|
||||
# DEBUG = False
|
||||
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
STORAGES["staticfiles"][
|
||||
"BACKEND"
|
||||
] = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
|
||||
|
||||
# Django Rest Framework
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from .development import *
|
||||
|
||||
# CSRF configuration
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS
|
||||
# https://www.gitpod.io/docs/environment-variables/#default-environment-variables
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
|
|
|
@ -8,7 +8,7 @@ SECRET_KEY = ""
|
|||
ALLOWED_HOSTS = [""]
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
|
@ -18,7 +18,7 @@ DATABASES = {
|
|||
}
|
||||
|
||||
# Media files
|
||||
# https://docs.djangoproject.com/en/4.0/topics/files/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/files/
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "../data/media")
|
||||
|
||||
|
@ -26,8 +26,8 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "../data/media")
|
|||
# After setting up SSL, uncomment the settings below for enhanced security of
|
||||
# application cookies.
|
||||
#
|
||||
# See https://docs.djangoproject.com/en/4.0/topics/http/sessions/#settings
|
||||
# See https://docs.djangoproject.com/en/4.0/ref/csrf/#settings
|
||||
# See https://docs.djangoproject.com/en/5.0/topics/http/sessions/#settings
|
||||
# See https://docs.djangoproject.com/en/5.0/ref/csrf/#settings
|
||||
|
||||
# SESSION_COOKIE_SECURE = True
|
||||
# CSRF_COOKIE_SECURE = True
|
||||
|
|
|
@ -3,15 +3,15 @@ from .base import *
|
|||
SECRET_KEY = "TESTS"
|
||||
|
||||
# Password hasher configuration
|
||||
# See https://docs.djangoproject.com/en/4.0/ref/settings/#password-hashers
|
||||
# See https://docs.djangoproject.com/en/4.0/topics/testing/overview/#password-hashing
|
||||
# See https://docs.djangoproject.com/en/5.0/ref/settings/#password-hashers
|
||||
# See https://docs.djangoproject.com/en/5.0/topics/testing/overview/#password-hashing
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||
]
|
||||
|
||||
# Email
|
||||
# https://docs.djangoproject.com/en/4.0/topics/email/
|
||||
# https://docs.djangoproject.com/en/5.0/topics/email/
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||
|
||||
|
|
|
@ -65,8 +65,7 @@ class FormsTestCase(TestCase):
|
|||
page = self.c.post("/user/password/", params)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(
|
||||
page,
|
||||
"form",
|
||||
page.context["form"],
|
||||
"old_password",
|
||||
"Your old password was entered incorrectly. " "Please enter it again.",
|
||||
)
|
||||
|
@ -75,7 +74,9 @@ class FormsTestCase(TestCase):
|
|||
page = self.c.post("/user/password/", params)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(
|
||||
page, "form", "new_password2", "The two password fields didn’t match."
|
||||
page.context["form"],
|
||||
"new_password2",
|
||||
"The two password fields didn’t match.",
|
||||
)
|
||||
|
||||
params["new_password2"] = "mynewpassword"
|
||||
|
@ -101,7 +102,7 @@ class FormsTestCase(TestCase):
|
|||
|
||||
page = self.c.post("/users/{}/delete/".format(new_user.id))
|
||||
self.assertEqual(page.status_code, 302)
|
||||
self.assertQuerysetEqual(
|
||||
self.assertQuerySetEqual(
|
||||
get_user_model().objects.filter(username="username"), []
|
||||
)
|
||||
|
||||
|
@ -212,7 +213,9 @@ class FormsTestCase(TestCase):
|
|||
|
||||
page = self.c.post("/user/settings/", params)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(page, "user_form", "email", "Enter a valid email address.")
|
||||
self.assertFormError(
|
||||
page.context["user_form"], "email", "Enter a valid email address."
|
||||
)
|
||||
|
||||
def test_user_settings_language(self):
|
||||
self.c.login(**self.credentials)
|
||||
|
|
|
@ -210,7 +210,7 @@ class ChildFormsTestCase(FormsTestCaseBase):
|
|||
)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(
|
||||
page, "form", "confirm_name", "Name does not match child name."
|
||||
page.context["form"], "confirm_name", "Name does not match child name."
|
||||
)
|
||||
|
||||
params["confirm_name"] = str(self.child)
|
||||
|
@ -798,7 +798,9 @@ class ValidationsTestCase(FormsTestCaseBase):
|
|||
|
||||
page = self.c.post("/weight/{}/".format(entry.id), params, follow=True)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(page, "form", "date", "Date can not be in the future.")
|
||||
self.assertFormError(
|
||||
page.context["form"], "date", "Date can not be in the future."
|
||||
)
|
||||
|
||||
def test_validate_duration(self):
|
||||
end = timezone.localtime() - timezone.timedelta(minutes=10)
|
||||
|
@ -813,14 +815,14 @@ class ValidationsTestCase(FormsTestCaseBase):
|
|||
page = self.c.post("/tummy-time/add/", params, follow=True)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(
|
||||
page, "form", None, "Start time must come before end time."
|
||||
page.context["form"], None, "Start time must come before end time."
|
||||
)
|
||||
|
||||
start = end - timezone.timedelta(weeks=53)
|
||||
params["start"] = self.localtime_string(start)
|
||||
page = self.c.post("/tummy-time/add/", params, follow=True)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(page, "form", None, "Duration too long.")
|
||||
self.assertFormError(page.context["form"], None, "Duration too long.")
|
||||
|
||||
def test_validate_time(self):
|
||||
future = timezone.localtime() + timezone.timedelta(hours=1)
|
||||
|
@ -833,7 +835,9 @@ class ValidationsTestCase(FormsTestCaseBase):
|
|||
|
||||
page = self.c.post("/tummy-time/add/", params, follow=True)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(page, "form", "end", "Date/time can not be in the future.")
|
||||
self.assertFormError(
|
||||
page.context["form"], "end", "Date/time can not be in the future."
|
||||
)
|
||||
|
||||
def test_validate_unique_period(self):
|
||||
entry = models.TummyTime.objects.create(
|
||||
|
@ -854,7 +858,9 @@ class ValidationsTestCase(FormsTestCaseBase):
|
|||
page = self.c.post("/tummy-time/add/", params, follow=True)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(
|
||||
page, "form", None, "Another entry intersects the specified time period."
|
||||
page.context["form"],
|
||||
None,
|
||||
"Another entry intersects the specified time period.",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ class ImportTestCase(TestCase):
|
|||
).save()
|
||||
|
||||
def get_dataset(self, model_name):
|
||||
file = open(self.base_path + model_name + ".csv")
|
||||
return tablib.Dataset().load(file.read())
|
||||
with open(self.base_path + model_name + ".csv", "r") as f:
|
||||
data = f.read()
|
||||
return tablib.Dataset().load(data)
|
||||
|
||||
def import_data(self, model, count):
|
||||
dataset = self.get_dataset(model._meta.model_name)
|
||||
|
@ -86,7 +87,7 @@ class ImportTestCase(TestCase):
|
|||
]
|
||||
for pk, tags in tests:
|
||||
entry = models.Temperature.objects.get(pk=pk)
|
||||
self.assertQuerysetEqual(entry.tags.names(), tags, ordered=False)
|
||||
self.assertQuerySetEqual(entry.tags.names(), tags, ordered=False)
|
||||
|
||||
def test_temperature(self):
|
||||
self.import_data(models.Temperature, 23)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytz
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
@ -28,7 +26,7 @@ class TemplateTagsTestCase(TestCase):
|
|||
|
||||
# Ensure timezone matches the one defined by fixtures.
|
||||
user_timezone = Settings.objects.first().timezone
|
||||
timezone.activate(pytz.timezone(user_timezone))
|
||||
timezone.activate(user_timezone)
|
||||
|
||||
# Test file data uses a basis date of 2017-11-18.
|
||||
date = timezone.localtime().strptime("2017-11-18", "%Y-%m-%d")
|
||||
|
@ -160,9 +158,11 @@ class TemplateTagsTestCase(TestCase):
|
|||
|
||||
def test_card_feeding_recent(self):
|
||||
data = cards.card_feeding_recent(self.context, self.child, self.date)
|
||||
|
||||
self.assertEqual(data["type"], "feeding")
|
||||
self.assertFalse(data["empty"])
|
||||
self.assertFalse(data["hide_empty"])
|
||||
|
||||
# most recent day
|
||||
self.assertEqual(data["feedings"][0]["total"], 2.5)
|
||||
self.assertEqual(data["feedings"][0]["count"], 3)
|
||||
|
@ -273,7 +273,7 @@ class TemplateTagsTestCase(TestCase):
|
|||
},
|
||||
{
|
||||
"type": "duration",
|
||||
"stat": timezone.timedelta(days=1, seconds=46980),
|
||||
"stat": timezone.timedelta(days=1, seconds=39780),
|
||||
"title": "Feeding frequency",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ information and steps below to set up a local development environment for Baby B
|
|||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+, pip, pipenv
|
||||
- Python 3.10+, pip, pipenv
|
||||
- NodeJS 18.x and NPM 8.x (NVM recommended)
|
||||
- Gulp
|
||||
- Possibly `libpq-dev`
|
||||
|
|
|
@ -117,14 +117,14 @@ requirements are Python, a web server, an application server, and a database.
|
|||
|
||||
### Requirements
|
||||
|
||||
- Python 3.8+, pip, pipenv
|
||||
- Python 3.10+, pip, pipenv
|
||||
- Web server ([nginx](http://nginx.org/), [Apache](http://httpd.apache.org/), etc.)
|
||||
- Application server ([uwsgi](http://projects.unbit.it/uwsgi), [gunicorn](http://gunicorn.org/), etc.)
|
||||
- Database (See [Django's databases documentation](https://docs.djangoproject.com/en/4.2/ref/databases/)).
|
||||
|
||||
### Example deployment
|
||||
|
||||
*This example assumes a 1 GB VPS instance with Ubuntu 20.04.* It uses Python 3.8,
|
||||
*This example assumes a 1 GB VPS instance with Ubuntu 20.04.* It uses Python 3.10,
|
||||
nginx, uwsgi and sqlite. It should be sufficient for a few users (e.g., two parents
|
||||
and any number of children).
|
||||
|
||||
|
|
|
@ -202,6 +202,7 @@ function test(cb) {
|
|||
let command = [
|
||||
'run',
|
||||
'python',
|
||||
'-Wa',
|
||||
'manage.py',
|
||||
'test',
|
||||
'--settings=babybuddy.settings.test',
|
||||
|
|
|
@ -23,8 +23,8 @@ class SleepPatternTestCase(TestCase):
|
|||
|
||||
models.Sleep.objects.create(
|
||||
child=c,
|
||||
start=dt.datetime(2000, 1, 1, 0, 0, tzinfo=timezone.utc),
|
||||
end=dt.datetime(2000, 1, 1, 0, 1, tzinfo=timezone.utc),
|
||||
start=dt.datetime(2000, 1, 1, 0, 0, tzinfo=dt.timezone.utc),
|
||||
end=dt.datetime(2000, 1, 1, 0, 1, tzinfo=dt.timezone.utc),
|
||||
)
|
||||
|
||||
sleep_pattern(models.Sleep.objects.order_by("start"))
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
-i https://pypi.python.org/simple
|
||||
annotated-types==0.6.0; python_version >= '3.8'
|
||||
asgiref==3.7.2; python_version >= '3.7'
|
||||
boto3==1.33.10; python_version >= '3.7'
|
||||
botocore==1.33.10; python_version >= '3.7'
|
||||
boto3==1.34.14; python_version >= '3.8'
|
||||
botocore==1.34.14; python_version >= '3.8'
|
||||
defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||
diff-match-patch==20230430; python_version >= '3.7'
|
||||
dj-database-url==2.1.0
|
||||
django==4.2.8; python_version >= '3.8'
|
||||
django==5.0.1; python_version >= '3.10'
|
||||
django-appconf==1.0.6; python_version >= '3.7'
|
||||
django-axes==6.1.1; python_version >= '3.7'
|
||||
django-axes==6.3.0; python_version >= '3.7'
|
||||
django-dbsettings==1.3.0
|
||||
django-filter==23.5; python_version >= '3.7'
|
||||
django-imagekit==5.0.0
|
||||
django-import-export==3.3.3; python_version >= '3.8'
|
||||
django-qr-code==3.1.1; python_version >= '3.7'
|
||||
django-import-export==3.3.5; python_version >= '3.8'
|
||||
django-qr-code==4.0.0; python_version >= '3.7'
|
||||
django-storages==1.14.2; python_version >= '3.7'
|
||||
django-taggit==5.0.1; python_version >= '3.8'
|
||||
django-widget-tweaks==1.5.0; python_version >= '3.8'
|
||||
djangorestframework==3.14.0; python_version >= '3.6'
|
||||
et-xmlfile==1.1.0; python_version >= '3.6'
|
||||
faker==20.1.0; python_version >= '3.8'
|
||||
faker==22.0.0; python_version >= '3.8'
|
||||
gunicorn==21.2.0; python_version >= '3.5'
|
||||
jmespath==1.0.1; python_version >= '3.7'
|
||||
markuppy==1.14
|
||||
|
@ -27,23 +27,23 @@ odfpy==1.4.1
|
|||
openpyxl==3.1.2
|
||||
packaging==23.2; python_version >= '3.7'
|
||||
pilkit==3.0
|
||||
pillow==10.1.0; python_version >= '3.8'
|
||||
pillow==10.2.0; python_version >= '3.8'
|
||||
plotly==5.18.0; python_version >= '3.6'
|
||||
psycopg2-binary==2.9.9; python_version >= '3.7'
|
||||
pydantic==2.5.2; python_version >= '3.7'
|
||||
pydantic-core==2.14.5; python_version >= '3.7'
|
||||
pydantic==2.5.3; python_version >= '3.7'
|
||||
pydantic-core==2.14.6; python_version >= '3.7'
|
||||
python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||
python-dotenv==1.0.0; python_version >= '3.8'
|
||||
pytz==2023.3.post1
|
||||
pyyaml==6.0.1; python_version >= '3.6'
|
||||
s3transfer==0.8.2; python_version >= '3.7'
|
||||
s3transfer==0.10.0; python_version >= '3.8'
|
||||
segno==1.6.0; python_version >= '3.5'
|
||||
setuptools==69.0.2; python_version >= '3.8'
|
||||
setuptools==69.0.3; python_version >= '3.8'
|
||||
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||
sqlparse==0.4.4; python_version >= '3.5'
|
||||
tablib[html,ods,xls,xlsx,yaml]==3.5.0; python_version >= '3.8'
|
||||
tenacity==8.2.3; python_version >= '3.7'
|
||||
typing-extensions==4.8.0; python_version >= '3.8'
|
||||
typing-extensions==4.9.0; python_version >= '3.8'
|
||||
uritemplate==4.1.1; python_version >= '3.6'
|
||||
urllib3==2.0.7; python_version >= '3.10'
|
||||
whitenoise==6.6.0; python_version >= '3.8'
|
||||
|
|
Loading…
Reference in New Issue