Bump to Dj 4.x (#6173)

* bump to dj >4.2

* switch to experimental git release

* bump django-import_export

* bump mptt

* replace is_ajax, which was removed
https://docs.djangoproject.com/en/3.1/releases/3.1/#id2

* Save before accessing values in m2m/fk fields

* move plugin init

* use dev version of django for fix

* update deps

* fix deps

* use django smaller 4.2

* fix reqs

* fix merge

* remove moved code

* another merge fix

* fix ajax call

* fix refs

* change python min v

* fix deps

* bump deps

* fix deps

* pin pillow

* dj 4.1 upgrades

* make diff smaller

* bump all deps

* drop down to py3.9

* bump versions

* merge fix

* fix diff

* more bumping

* diff cleanup

* bump deps

* fix reqs

* use accurate state for model migrations
using apps the historically correct state is used

* try import

* added more logs

* add try here too

* clean up rebuilds

* Dj 4.2 (#161)

* autochanges

* bump

* fix diff

* fix diff

* bump deps

* fix req

* remove select_related to test error influence

* switch to mptt fork

* fix reqs for upstream

* move tracking ensureance into save

* optimize check frequency

* use psycopg instead of psycopg2

* fix header

* just use the values

* switch to dj < 4.2

* fix req

* another req fix

* switch to 4.2 again

* fix merge error

* Check for null pk in calculate_total_price

Cannot access self.lines if pk is Null

* use patched mptt

* try psycopg2 again

* Remove tree rebuild from migrations

* Prevent notify_users if importing or migrating

* Add order_by() to subquery annotations

- Ref: https://stackoverflow.com/a/629691

* Update stock filters

- Append order_by()

* fix error if running without timezones in testing

* add logging to figure this out

* remove tz from self.creation if TZ is off

* add tz?

* move around?

* only run the test i am trying to figure out
not reproducible on my machine

* only run the test i am trying to figure out
not reproducible on my machine

* run all tests again

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
Matthias Mair 2024-02-06 02:30:50 +00:00 committed by GitHub
parent 676bb02f6e
commit d36cf358f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 151 additions and 178 deletions

View File

@ -591,11 +591,6 @@ db_options = db_config.get('OPTIONS', db_config.get('options', {}))
# Specific options for postgres backend
if 'postgres' in db_engine: # pragma: no cover
from psycopg2.extensions import (
ISOLATION_LEVEL_READ_COMMITTED,
ISOLATION_LEVEL_SERIALIZABLE,
)
# Connection timeout
if 'connect_timeout' not in db_options:
# The DB server is in the same data center, it should not take very
@ -659,11 +654,7 @@ if 'postgres' in db_engine: # pragma: no cover
serializable = get_boolean_setting(
'INVENTREE_DB_ISOLATION_SERIALIZABLE', 'database.serializable', False
)
db_options['isolation_level'] = (
ISOLATION_LEVEL_SERIALIZABLE
if serializable
else ISOLATION_LEVEL_READ_COMMITTED
)
db_options['isolation_level'] = 4 if serializable else 2
# Specific options for MySql / MariaDB backend
elif 'mysql' in db_engine: # pragma: no cover
@ -963,7 +954,6 @@ TIME_ZONE = get_setting('INVENTREE_TIMEZONE', 'timezone', 'UTC')
USE_I18N = True
USE_L10N = True
# Do not use native timezone support in "test" mode
# It generates a *lot* of cruft in the logs

View File

@ -25,7 +25,7 @@ class HTMLAPITests(InvenTreeTestCase):
url = reverse('api-part-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
response = self.client.get(url, headers={'accept': 'application/json'})
self.assertEqual(response.status_code, 200)
def test_build_api(self):
@ -33,7 +33,7 @@ class HTMLAPITests(InvenTreeTestCase):
url = reverse('api-build-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
response = self.client.get(url, headers={'accept': 'application/json'})
self.assertEqual(response.status_code, 200)
def test_stock_api(self):
@ -41,7 +41,7 @@ class HTMLAPITests(InvenTreeTestCase):
url = reverse('api-stock-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
response = self.client.get(url, headers={'accept': 'application/json'})
self.assertEqual(response.status_code, 200)
def test_company_list(self):
@ -49,7 +49,7 @@ class HTMLAPITests(InvenTreeTestCase):
url = reverse('api-company-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
response = self.client.get(url, headers={'accept': 'application/json'})
self.assertEqual(response.status_code, 200)
def test_not_found(self):

View File

@ -15,7 +15,9 @@ class MiddlewareTests(InvenTreeTestCase):
def check_path(self, url, code=200, **kwargs):
"""Helper function to run a request."""
response = self.client.get(url, HTTP_ACCEPT='application/json', **kwargs)
response = self.client.get(
url, headers={'accept': 'application/json'}, **kwargs
)
self.assertEqual(response.status_code, code)
return response

View File

@ -51,6 +51,7 @@ class BuildResource(InvenTreeResource):
notes = Field(attribute='notes')
@admin.register(Build)
class BuildAdmin(ImportExportModelAdmin):
"""Class for managing the Build model via the admin interface"""
@ -83,6 +84,7 @@ class BuildAdmin(ImportExportModelAdmin):
]
@admin.register(BuildItem)
class BuildItemAdmin(admin.ModelAdmin):
"""Class for managing the BuildItem model via the admin interface."""
@ -98,6 +100,7 @@ class BuildItemAdmin(admin.ModelAdmin):
]
@admin.register(BuildLine)
class BuildLineAdmin(admin.ModelAdmin):
"""Class for managing the BuildLine model via the admin interface"""
@ -112,8 +115,3 @@ class BuildLineAdmin(admin.ModelAdmin):
'build__reference',
'bom_item__sub_part__name',
]
admin.site.register(Build, BuildAdmin)
admin.site.register(BuildItem, BuildItemAdmin)
admin.site.register(BuildLine, BuildLineAdmin)

View File

@ -3,12 +3,6 @@
from django.db import migrations, models
import django.db.models.deletion
import mptt.fields
from build.models import Build
def update_tree(apps, schema_editor):
# Update the Build MPTT model
Build.objects.rebuild()
class Migration(migrations.Migration):
@ -49,5 +43,4 @@ class Migration(migrations.Migration):
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
preserve_default=False,
),
migrations.RunPython(update_tree, reverse_code=migrations.RunPython.noop),
]

View File

@ -57,6 +57,4 @@ class Migration(migrations.Migration):
('build', '0028_builditem_bom_item'),
]
operations = [
migrations.RunPython(assign_bom_items, reverse_code=migrations.RunPython.noop),
]
operations = []

View File

@ -13,7 +13,7 @@ import math
import os
import re
import uuid
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from enum import Enum
from secrets import compare_digest
from typing import Any, Callable, Dict, List, Tuple, TypedDict, Union
@ -2850,7 +2850,12 @@ class NotificationMessage(models.Model):
def age(self):
"""Age of the message in seconds."""
delta = now() - self.creation
# Add timezone information if TZ is enabled (in production mode mostly)
delta = now() - (
self.creation.replace(tzinfo=timezone.utc)
if settings.USE_TZ
else self.creation
)
return delta.seconds
def age_human(self):

View File

@ -33,6 +33,7 @@ class CompanyResource(InvenTreeResource):
clean_model_instances = True
@admin.register(Company)
class CompanyAdmin(ImportExportModelAdmin):
"""Admin class for the Company model."""
@ -69,6 +70,7 @@ class SupplierPriceBreakInline(admin.TabularInline):
model = SupplierPriceBreak
@admin.register(SupplierPart)
class SupplierPartAdmin(ImportExportModelAdmin):
"""Admin class for the SupplierPart model."""
@ -105,6 +107,7 @@ class ManufacturerPartResource(InvenTreeResource):
manufacturer_name = Field(attribute='manufacturer__name', readonly=True)
@admin.register(ManufacturerPart)
class ManufacturerPartAdmin(ImportExportModelAdmin):
"""Admin class for ManufacturerPart model."""
@ -117,6 +120,7 @@ class ManufacturerPartAdmin(ImportExportModelAdmin):
autocomplete_fields = ('part', 'manufacturer')
@admin.register(ManufacturerPartAttachment)
class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin):
"""Admin class for ManufacturerPartAttachment model."""
@ -137,6 +141,7 @@ class ManufacturerPartParameterResource(InvenTreeResource):
clean_model_instance = True
@admin.register(ManufacturerPartParameter)
class ManufacturerPartParameterAdmin(ImportExportModelAdmin):
"""Admin class for ManufacturerPartParameter model."""
@ -173,6 +178,7 @@ class SupplierPriceBreakResource(InvenTreeResource):
MPN = Field(attribute='part__MPN', readonly=True)
@admin.register(SupplierPriceBreak)
class SupplierPriceBreakAdmin(ImportExportModelAdmin):
"""Admin class for the SupplierPriceBreak model."""
@ -197,6 +203,7 @@ class AddressResource(InvenTreeResource):
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
@admin.register(Address)
class AddressAdmin(ImportExportModelAdmin):
"""Admin class for the Address model."""
@ -221,6 +228,7 @@ class ContactResource(InvenTreeResource):
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
@admin.register(Contact)
class ContactAdmin(ImportExportModelAdmin):
"""Admin class for the Contact model."""
@ -229,15 +237,3 @@ class ContactAdmin(ImportExportModelAdmin):
list_display = ('company', 'name', 'role', 'email', 'phone')
search_fields = ['company', 'name', 'email']
admin.site.register(Company, CompanyAdmin)
admin.site.register(SupplierPart, SupplierPartAdmin)
admin.site.register(SupplierPriceBreak, SupplierPriceBreakAdmin)
admin.site.register(ManufacturerPart, ManufacturerPartAdmin)
admin.site.register(ManufacturerPartAttachment, ManufacturerPartAttachmentAdmin)
admin.site.register(ManufacturerPartParameter, ManufacturerPartParameterAdmin)
admin.site.register(Address, AddressAdmin)
admin.site.register(Contact, ContactAdmin)

View File

@ -1362,8 +1362,8 @@ class OrderCalendarExport(ICalFeed):
return super().__call__(request, *args, **kwargs)
# No login yet - check in headers
if 'HTTP_AUTHORIZATION' in request.META:
auth = request.META['HTTP_AUTHORIZATION'].split()
if 'authorization' in request.headers:
auth = request.headers['authorization'].split()
if len(auth) == 2:
# NOTE: We are only support basic authentication for now.
#

View File

@ -78,7 +78,14 @@ class TotalPriceMixin(models.Model):
"""Update the total_price field when saved."""
# Recalculate total_price for this order
self.update_total_price(commit=False)
super().save(*args, **kwargs)
if hasattr(self, '_SAVING_TOTAL_PRICE') and self._SAVING_TOTAL_PRICE:
# Avoid recursion on save
return super().save(*args, **kwargs)
self._SAVING_TOTAL_PRICE = True
# Save the object as we can not access foreign/m2m fields before saving
self.update_total_price(commit=True)
total_price = InvenTreeModelMoneyField(
null=True,
@ -136,6 +143,10 @@ class TotalPriceMixin(models.Model):
total = Money(0, target_currency)
# Check if the order has been saved (otherwise we can't calculate the total price)
if self.pk is None:
return total
# order items
for line in self.lines.all():
if not line.price:

View File

@ -634,7 +634,7 @@ class PurchaseOrderTest(OrderTest):
response = self.client.get(
reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}),
format='json',
HTTP_AUTHORIZATION=f'basic {base64_token}',
headers={'authorization': f'basic {base64_token}'},
)
self.assertEqual(response.status_code, 200)

View File

@ -57,7 +57,8 @@ class PurchaseOrderTests(OrderViewTestCase):
def test_po_export(self):
"""Export PurchaseOrder."""
response = self.client.get(
reverse('po-export', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest'
reverse('po-export', args=(1,)),
headers={'x-requested-with': 'XMLHttpRequest'},
)
# Response should be streaming-content (file download)

View File

@ -245,7 +245,9 @@ def annotate_variant_quantity(subquery: Q, reference: str = 'quantity'):
Subquery(
subquery.annotate(
total=Func(F(reference), function='SUM', output_field=FloatField())
).values('total')
)
.values('total')
.order_by()
),
0,
output_field=FloatField(),
@ -270,7 +272,9 @@ def annotate_category_parts():
Subquery(
subquery.annotate(
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
).values('total')
)
.values('total')
.order_by()
),
0,
output_field=IntegerField(),

View File

@ -1,13 +1,6 @@
# Generated by Django 2.2.5 on 2019-09-08 04:04
from django.db import migrations
from part import models
def update_tree(apps, schema_editor):
# Update the PartCategory MPTT model
models.PartCategory.objects.rebuild()
class Migration(migrations.Migration):
@ -18,6 +11,4 @@ class Migration(migrations.Migration):
('part', '0019_auto_20190908_0404'),
]
operations = [
migrations.RunPython(update_tree)
]
operations = []

View File

@ -2,13 +2,6 @@
from django.db import migrations, models
from part.models import Part
def update_tree(apps, schema_editor):
# Update the MPTT for Part model
Part.objects.rebuild()
class Migration(migrations.Migration):
@ -43,6 +36,4 @@ class Migration(migrations.Migration):
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
preserve_default=False,
),
migrations.RunPython(update_tree, reverse_code=migrations.RunPython.noop)
]

View File

@ -452,6 +452,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
If the part image has been updated, then check if the "old" (previous) image is still used by another part.
If not, it is considered "orphaned" and will be deleted.
"""
_new = False
if self.pk:
try:
previous = Part.objects.get(pk=self.pk)
@ -470,6 +471,8 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
previous.image.delete(save=False)
except Part.DoesNotExist:
pass
else:
_new = True
self.full_clean()
@ -478,6 +481,10 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
except InvalidMove:
raise ValidationError({'variant_of': _('Invalid choice for parent part')})
if _new:
# Only run if the check was not run previously (due to not existing in the database)
self.ensure_trackable()
def __str__(self):
"""Return a string representation of the Part (for use in the admin interface)."""
return f'{self.full_name} - {self.description}'
@ -827,6 +834,12 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
# Run custom validation for the name field
self.validate_name()
if self.pk:
# Only run if the part already exists in the database
self.ensure_trackable()
def ensure_trackable(self):
"""Ensure that trackable is set correctly downline."""
if self.trackable:
for part in self.get_used_in():
if not part.trackable:

View File

@ -108,7 +108,7 @@ class PartDetailTest(PartViewTestCase):
"""Test downloading a BOM for a valid part."""
response = self.client.get(
reverse('api-bom-download', args=(1,)),
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
headers={'x-requested-with': 'XMLHttpRequest'},
)
self.assertEqual(response.status_code, 200)
self.assertIn('streaming_content', dir(response))

View File

@ -106,7 +106,6 @@ class InvenTreePluginTests(TestCase):
LICENSE = 'MIT'
cls.plugin_name = NameInvenTreePlugin()
cls.plugin_sample = SampleIntegrationPlugin()
class VersionInvenTreePlugin(InvenTreePlugin):
NAME = 'Version'
@ -140,7 +139,7 @@ class InvenTreePluginTests(TestCase):
# is_sample
self.assertEqual(self.plugin.is_sample, False)
self.assertEqual(self.plugin_sample.is_sample, True)
self.assertEqual(SampleIntegrationPlugin().is_sample, True)
# slug
self.assertEqual(self.plugin.slug, '')

View File

@ -15,31 +15,30 @@ from .models import (
)
@admin.register(
BillOfMaterialsReport,
BuildReport,
PurchaseOrderReport,
ReturnOrderReport,
SalesOrderReport,
StockLocationReport,
TestReport,
)
class ReportTemplateAdmin(admin.ModelAdmin):
"""Admin class for the various reporting models."""
list_display = ('name', 'description', 'template', 'filters', 'enabled', 'revision')
@admin.register(ReportSnippet)
class ReportSnippetAdmin(admin.ModelAdmin):
"""Admin class for the ReportSnippet model."""
list_display = ('id', 'snippet', 'description')
@admin.register(ReportAsset)
class ReportAssetAdmin(admin.ModelAdmin):
"""Admin class for the ReportAsset model."""
list_display = ('id', 'asset', 'description')
admin.site.register(ReportSnippet, ReportSnippetAdmin)
admin.site.register(ReportAsset, ReportAssetAdmin)
admin.site.register(StockLocationReport, ReportTemplateAdmin)
admin.site.register(TestReport, ReportTemplateAdmin)
admin.site.register(BuildReport, ReportTemplateAdmin)
admin.site.register(BillOfMaterialsReport, ReportTemplateAdmin)
admin.site.register(PurchaseOrderReport, ReportTemplateAdmin)
admin.site.register(ReturnOrderReport, ReportTemplateAdmin)
admin.site.register(SalesOrderReport, ReportTemplateAdmin)

View File

@ -85,6 +85,7 @@ class LocationInline(admin.TabularInline):
model = StockLocation
@admin.register(StockLocation)
class LocationAdmin(ImportExportModelAdmin):
"""Admin class for Location."""
@ -99,6 +100,7 @@ class LocationAdmin(ImportExportModelAdmin):
autocomplete_fields = ['parent']
@admin.register(StockLocationType)
class LocationTypeAdmin(admin.ModelAdmin):
"""Admin class for StockLocationType."""
@ -268,6 +270,7 @@ class StockItemResource(InvenTreeResource):
StockItem.objects.rebuild()
@admin.register(StockItem)
class StockItemAdmin(ImportExportModelAdmin):
"""Admin class for StockItem."""
@ -292,6 +295,7 @@ class StockItemAdmin(ImportExportModelAdmin):
]
@admin.register(StockItemAttachment)
class StockAttachmentAdmin(admin.ModelAdmin):
"""Admin class for StockAttachment."""
@ -300,6 +304,7 @@ class StockAttachmentAdmin(admin.ModelAdmin):
autocomplete_fields = ['stock_item']
@admin.register(StockItemTracking)
class StockTrackingAdmin(ImportExportModelAdmin):
"""Admin class for StockTracking."""
@ -308,17 +313,10 @@ class StockTrackingAdmin(ImportExportModelAdmin):
autocomplete_fields = ['item']
@admin.register(StockItemTestResult)
class StockItemTestResultAdmin(admin.ModelAdmin):
"""Admin class for StockItemTestResult."""
list_display = ('stock_item', 'test', 'result', 'value')
autocomplete_fields = ['stock_item']
admin.site.register(StockLocation, LocationAdmin)
admin.site.register(StockLocationType, LocationTypeAdmin)
admin.site.register(StockItem, StockItemAdmin)
admin.site.register(StockItemTracking, StockTrackingAdmin)
admin.site.register(StockItemAttachment, StockAttachmentAdmin)
admin.site.register(StockItemTestResult, StockItemTestResultAdmin)

View File

@ -30,7 +30,9 @@ def annotate_location_items(filter: Q = None):
Subquery(
subquery.annotate(
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
).values('total')
)
.values('total')
.order_by()
),
0,
output_field=IntegerField(),
@ -50,7 +52,9 @@ def annotate_child_items():
Subquery(
child_stock_query.annotate(
count=Func(F('pk'), function='COUNT', output_field=IntegerField())
).values('count')
)
.values('count')
.order_by()
),
0,
output_field=IntegerField(),

View File

@ -2,13 +2,6 @@
from django.db import migrations
from stock import models
def update_tree(apps, schema_editor):
# Update the StockLocation MPTT model
models.StockLocation.objects.rebuild()
class Migration(migrations.Migration):
@ -19,6 +12,4 @@ class Migration(migrations.Migration):
('stock', '0011_auto_20190908_0404'),
]
operations = [
migrations.RunPython(update_tree)
]
operations = []

View File

@ -1,13 +1,6 @@
# Generated by Django 2.2.9 on 2020-02-17 11:09
from django.db import migrations
from stock import models
def update_stock_item_tree(apps, schema_editor):
# Update the StockItem MPTT model
models.StockItem.objects.rebuild()
class Migration(migrations.Migration):
@ -18,6 +11,4 @@ class Migration(migrations.Migration):
('stock', '0021_auto_20200215_2232'),
]
operations = [
migrations.RunPython(update_stock_item_tree)
]
operations = []

View File

@ -107,7 +107,8 @@ class StockLocationManager(TreeManager):
- Joins the StockLocationType by default for speedier icon access
"""
return super().get_queryset().select_related('location_type')
# return super().get_queryset().select_related("location_type")
return super().get_queryset()
class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):

View File

@ -13,6 +13,7 @@ from users.models import ApiToken, Owner, RuleSet
User = get_user_model()
@admin.register(ApiToken)
class ApiTokenAdmin(admin.ModelAdmin):
"""Admin class for the ApiToken model."""
@ -288,6 +289,7 @@ class InvenTreeUserAdmin(UserAdmin):
)
@admin.register(Owner)
class OwnerAdmin(admin.ModelAdmin):
"""Custom admin interface for the Owner model."""
@ -299,7 +301,3 @@ admin.site.register(Group, RoleGroupAdmin)
admin.site.unregister(User)
admin.site.register(User, InvenTreeUserAdmin)
admin.site.register(Owner, OwnerAdmin)
admin.site.register(ApiToken, ApiTokenAdmin)

View File

@ -262,7 +262,7 @@ class GetAuthToken(APIView):
)
# Add some metadata about the request
token.set_metadata('user_agent', request.META.get('HTTP_USER_AGENT', ''))
token.set_metadata('user_agent', request.headers.get('user-agent', ''))
token.set_metadata('remote_addr', request.META.get('REMOTE_ADDR', ''))
token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))
token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))

View File

@ -10,7 +10,7 @@ asgiref==3.7.2
# django
build==1.0.3
# via pip-tools
certifi==2023.7.22
certifi==2023.11.17
# via
# -c requirements.txt
# requests
@ -33,13 +33,13 @@ coverage[toml]==5.5
# coveralls
coveralls==2.1.2
# via -r requirements-dev.in
cryptography==41.0.6
cryptography==41.0.7
# via
# -c requirements.txt
# pdfminer-six
distlib==0.3.7
distlib==0.3.8
# via virtualenv
django==3.2.23
django==4.2.9
# via
# -c requirements.txt
# django-slowtests
@ -53,7 +53,7 @@ filelock==3.13.1
# via virtualenv
identify==2.5.31
# via pre-commit
idna==3.4
idna==3.6
# via
# -c requirements.txt
# requests
@ -61,7 +61,7 @@ importlib-metadata==6.8.0
# via
# -c requirements.txt
# build
isort==5.12.0
isort==5.13.2
# via -r requirements-dev.in
nodeenv==1.8.0
# via pre-commit
@ -69,13 +69,13 @@ packaging==23.2
# via
# -c requirements.txt
# build
pdfminer-six==20221105
pdfminer-six==20231228
# via -r requirements-dev.in
pip-tools==7.3.0
# via -r requirements-dev.in
platformdirs==3.11.0
platformdirs==4.1.0
# via virtualenv
pre-commit==3.5.0
pre-commit==3.6.0
# via -r requirements-dev.in
pycparser==2.21
# via
@ -83,10 +83,6 @@ pycparser==2.21
# cffi
pyproject-hooks==1.0.0
# via build
pytz==2023.3.post1
# via
# -c requirements.txt
# django
pyyaml==6.0.1
# via
# -c requirements.txt
@ -106,20 +102,20 @@ tomli==2.0.1
# build
# pip-tools
# pyproject-hooks
typing-extensions==4.8.0
typing-extensions==4.9.0
# via
# -c requirements.txt
# asgiref
# django-test-migrations
urllib3==2.0.7
urllib3==2.1.0
# via
# -c requirements.txt
# requests
virtualenv==20.24.6
virtualenv==20.25.0
# via pre-commit
wheel==0.41.3
wheel==0.42.0
# via pip-tools
zipp==3.16.0
zipp==3.16.2
# via
# -c requirements.txt
# importlib-metadata

View File

@ -1,5 +1,5 @@
# Please keep this list sorted - if you pin a version provide a reason
Django>=3.2.14,<4 # Django package
Django<5.0 # Django package
coreapi # API documentation for djangorestframework
cryptography>=40.0.0,!=40.0.2 # Core cryptographic functionality
django-allauth # SSO for external providers via OpenID
@ -13,11 +13,13 @@ django-filter # Extended filtering options
django-flags # Feature flags
django-formtools # Form wizard tools
django-ical # iCal export for calendar views
django-import-export>=3.3.1 # Data import / export for admin interface
django-import-export # Data import / export for admin interface
django-maintenance-mode # Shut down application while reloading etc.
django-markdownify # Markdown rendering
django-mptt # Modified Preorder Tree Traversal
django-markdownify # Markdown rendering
django-money>=3.0.0,<3.3.0 # Django app for currency management # FIXED 2023-10-31 3.3.0 breaks due to https://github.com/django-money/django-money/issues/731
django-mptt==0.11.0 # Modified Preorder Tree Traversal
django-mptt # Modified Preorder Tree Traversal
django-redis>=5.0.0 # Redis integration
django-q2 # Background task scheduling
django-q-sentry # sentry.io integration for django-q

View File

@ -5,14 +5,16 @@
# pip-compile --output-file=requirements.txt requirements.in
#
asgiref==3.7.2
# via django
# via
# django
# django-cors-headers
async-timeout==4.0.3
# via redis
attrs==23.1.0
attrs==23.2.0
# via
# jsonschema
# referencing
babel==2.13.1
babel==2.14.0
# via py-moneyed
backoff==2.2.1
# via
@ -25,7 +27,7 @@ bleach[css]==6.1.0
# django-markdownify
brotli==1.1.0
# via fonttools
certifi==2023.7.22
certifi==2023.11.17
# via
# requests
# sentry-sdk
@ -39,7 +41,7 @@ coreapi==2.3.3
# via -r requirements.in
coreschema==0.0.4
# via coreapi
cryptography==41.0.6
cryptography==41.0.7
# via
# -r requirements.in
# djangorestframework-simplejwt
@ -59,7 +61,7 @@ diff-match-patch==20230430
# via django-import-export
dj-rest-auth==5.0.2
# via -r requirements.in
django==3.2.23
django==4.2.9
# via
# -r requirements.in
# dj-rest-auth
@ -76,7 +78,6 @@ django==3.2.23
# django-js-asset
# django-markdownify
# django-money
# django-mptt
# django-otp
# django-picklefield
# django-q2
@ -101,7 +102,7 @@ django-allauth-2fa==0.11.1
# via -r requirements.in
django-cleanup==8.0.0
# via -r requirements.in
django-cors-headers==4.3.0
django-cors-headers==4.3.1
# via -r requirements.in
django-crispy-forms==1.14.0
# via -r requirements.in
@ -109,17 +110,17 @@ django-dbbackup==4.0.2
# via -r requirements.in
django-error-report-2==0.4.2
# via -r requirements.in
django-filter==23.3
django-filter==23.5
# via -r requirements.in
django-flags==5.0.13
# via -r requirements.in
django-formtools==2.4.1
django-formtools==2.5.1
# via -r requirements.in
django-ical==1.9.2
# via -r requirements.in
django-import-export==3.3.1
django-import-export==3.3.5
# via -r requirements.in
django-js-asset==2.1.0
django-js-asset==2.2.0
# via django-mptt
django-maintenance-mode==0.21.0
# via -r requirements.in
@ -127,9 +128,9 @@ django-markdownify==0.9.3
# via -r requirements.in
django-money==3.2.0
# via -r requirements.in
django-mptt==0.11.0
django-mptt==0.16.0
# via -r requirements.in
django-otp==1.2.4
django-otp==1.3.0
# via django-allauth-2fa
django-picklefield==3.1
# via django-q2
@ -141,7 +142,7 @@ django-recurrence==1.11.1
# via django-ical
django-redis==5.4.0
# via -r requirements.in
django-sesame==3.2.1
django-sesame==3.2.2
# via -r requirements.in
django-sql-utils==0.7.0
# via -r requirements.in
@ -149,11 +150,11 @@ django-sslserver==0.22
# via -r requirements.in
django-stdimage==6.0.2
# via -r requirements.in
django-taggit==4.0.0
django-taggit==5.0.1
# via -r requirements.in
django-user-sessions==2.0.0
# via -r requirements.in
django-weasyprint==2.2.1
django-weasyprint==2.2.2
# via -r requirements.in
django-xforwardedfor-middleware==2.0
# via -r requirements.in
@ -163,15 +164,15 @@ djangorestframework==3.14.0
# dj-rest-auth
# djangorestframework-simplejwt
# drf-spectacular
djangorestframework-simplejwt[crypto]==5.3.0
djangorestframework-simplejwt[crypto]==5.3.1
# via -r requirements.in
drf-spectacular==0.26.5
drf-spectacular==0.27.0
# via -r requirements.in
dulwich==0.21.6
dulwich==0.21.7
# via -r requirements.in
et-xmlfile==1.1.0
# via openpyxl
feedparser==6.0.10
feedparser==6.0.11
# via -r requirements.in
fonttools[woff]==4.44.0
# via
@ -189,7 +190,7 @@ html5lib==1.1
# via weasyprint
icalendar==5.0.11
# via django-ical
idna==3.4
idna==3.6
# via requests
importlib-metadata==6.8.0
# via
@ -202,9 +203,9 @@ itypes==1.2.0
# via coreapi
jinja2==3.1.3
# via coreschema
jsonschema==4.19.2
jsonschema==4.20.0
# via drf-spectacular
jsonschema-specifications==2023.7.1
jsonschema-specifications==2023.12.1
# via jsonschema
markdown==3.5.1
# via django-markdownify
@ -277,7 +278,7 @@ opentelemetry-util-http==0.43b0
# opentelemetry-instrumentation-wsgi
packaging==23.2
# via gunicorn
pdf2image==1.16.3
pdf2image==1.17.0
# via -r requirements.in
pillow==10.2.0
# via
@ -316,13 +317,12 @@ python-dateutil==2.8.2
# icalendar
python-dotenv==1.0.0
# via -r requirements.in
python-fsutil==0.12.0
python-fsutil==0.13.0
# via django-maintenance-mode
python3-openid==3.2.0
# via django-allauth
pytz==2023.3.post1
# via
# django
# django-dbbackup
# djangorestframework
# icalendar
@ -339,11 +339,11 @@ rapidfuzz==0.7.6
# via -r requirements.in
redis==5.0.1
# via django-redis
referencing==0.30.2
referencing==0.32.1
# via
# jsonschema
# jsonschema-specifications
regex==2023.10.3
regex==2023.12.25
# via -r requirements.in
requests==2.31.0
# via
@ -353,11 +353,11 @@ requests==2.31.0
# requests-oauthlib
requests-oauthlib==1.3.1
# via django-allauth
rpds-py==0.12.0
rpds-py==0.16.2
# via
# jsonschema
# referencing
sentry-sdk==1.34.0
sentry-sdk==1.39.2
# via
# -r requirements.in
# django-q-sentry
@ -381,9 +381,10 @@ tinycss2==1.2.1
# bleach
# cssselect2
# weasyprint
typing-extensions==4.8.0
typing-extensions==4.9.0
# via
# asgiref
# drf-spectacular
# opentelemetry-sdk
# py-moneyed
# qrcode
@ -391,12 +392,12 @@ uritemplate==4.1.1
# via
# coreapi
# drf-spectacular
urllib3==2.0.7
urllib3==2.1.0
# via
# dulwich
# requests
# sentry-sdk
weasyprint==60.1
weasyprint==60.2
# via
# -r requirements.in
# django-weasyprint
@ -415,7 +416,7 @@ xlrd==2.0.1
# via tablib
xlwt==1.3.0
# via tablib
zipp==3.16.0
zipp==3.16.2
# via importlib-metadata
zopfli==0.2.3
# via fonttools