mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
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:
parent
676bb02f6e
commit
d36cf358f8
@ -591,11 +591,6 @@ db_options = db_config.get('OPTIONS', db_config.get('options', {}))
|
|||||||
|
|
||||||
# Specific options for postgres backend
|
# Specific options for postgres backend
|
||||||
if 'postgres' in db_engine: # pragma: no cover
|
if 'postgres' in db_engine: # pragma: no cover
|
||||||
from psycopg2.extensions import (
|
|
||||||
ISOLATION_LEVEL_READ_COMMITTED,
|
|
||||||
ISOLATION_LEVEL_SERIALIZABLE,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Connection timeout
|
# Connection timeout
|
||||||
if 'connect_timeout' not in db_options:
|
if 'connect_timeout' not in db_options:
|
||||||
# The DB server is in the same data center, it should not take very
|
# 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(
|
serializable = get_boolean_setting(
|
||||||
'INVENTREE_DB_ISOLATION_SERIALIZABLE', 'database.serializable', False
|
'INVENTREE_DB_ISOLATION_SERIALIZABLE', 'database.serializable', False
|
||||||
)
|
)
|
||||||
db_options['isolation_level'] = (
|
db_options['isolation_level'] = 4 if serializable else 2
|
||||||
ISOLATION_LEVEL_SERIALIZABLE
|
|
||||||
if serializable
|
|
||||||
else ISOLATION_LEVEL_READ_COMMITTED
|
|
||||||
)
|
|
||||||
|
|
||||||
# Specific options for MySql / MariaDB backend
|
# Specific options for MySql / MariaDB backend
|
||||||
elif 'mysql' in db_engine: # pragma: no cover
|
elif 'mysql' in db_engine: # pragma: no cover
|
||||||
@ -963,7 +954,6 @@ TIME_ZONE = get_setting('INVENTREE_TIMEZONE', 'timezone', 'UTC')
|
|||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
# Do not use native timezone support in "test" mode
|
# Do not use native timezone support in "test" mode
|
||||||
# It generates a *lot* of cruft in the logs
|
# It generates a *lot* of cruft in the logs
|
||||||
|
@ -25,7 +25,7 @@ class HTMLAPITests(InvenTreeTestCase):
|
|||||||
url = reverse('api-part-list')
|
url = reverse('api-part-list')
|
||||||
|
|
||||||
# Check JSON response
|
# 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)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_build_api(self):
|
def test_build_api(self):
|
||||||
@ -33,7 +33,7 @@ class HTMLAPITests(InvenTreeTestCase):
|
|||||||
url = reverse('api-build-list')
|
url = reverse('api-build-list')
|
||||||
|
|
||||||
# Check JSON response
|
# 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)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_stock_api(self):
|
def test_stock_api(self):
|
||||||
@ -41,7 +41,7 @@ class HTMLAPITests(InvenTreeTestCase):
|
|||||||
url = reverse('api-stock-list')
|
url = reverse('api-stock-list')
|
||||||
|
|
||||||
# Check JSON response
|
# 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)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_company_list(self):
|
def test_company_list(self):
|
||||||
@ -49,7 +49,7 @@ class HTMLAPITests(InvenTreeTestCase):
|
|||||||
url = reverse('api-company-list')
|
url = reverse('api-company-list')
|
||||||
|
|
||||||
# Check JSON response
|
# 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)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_not_found(self):
|
def test_not_found(self):
|
||||||
|
@ -15,7 +15,9 @@ class MiddlewareTests(InvenTreeTestCase):
|
|||||||
|
|
||||||
def check_path(self, url, code=200, **kwargs):
|
def check_path(self, url, code=200, **kwargs):
|
||||||
"""Helper function to run a request."""
|
"""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)
|
self.assertEqual(response.status_code, code)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ class BuildResource(InvenTreeResource):
|
|||||||
notes = Field(attribute='notes')
|
notes = Field(attribute='notes')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Build)
|
||||||
class BuildAdmin(ImportExportModelAdmin):
|
class BuildAdmin(ImportExportModelAdmin):
|
||||||
"""Class for managing the Build model via the admin interface"""
|
"""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 BuildItemAdmin(admin.ModelAdmin):
|
||||||
"""Class for managing the BuildItem model via the admin interface."""
|
"""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 BuildLineAdmin(admin.ModelAdmin):
|
||||||
"""Class for managing the BuildLine model via the admin interface"""
|
"""Class for managing the BuildLine model via the admin interface"""
|
||||||
|
|
||||||
@ -112,8 +115,3 @@ class BuildLineAdmin(admin.ModelAdmin):
|
|||||||
'build__reference',
|
'build__reference',
|
||||||
'bom_item__sub_part__name',
|
'bom_item__sub_part__name',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Build, BuildAdmin)
|
|
||||||
admin.site.register(BuildItem, BuildItemAdmin)
|
|
||||||
admin.site.register(BuildLine, BuildLineAdmin)
|
|
||||||
|
@ -3,12 +3,6 @@
|
|||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import mptt.fields
|
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):
|
class Migration(migrations.Migration):
|
||||||
@ -49,5 +43,4 @@ class Migration(migrations.Migration):
|
|||||||
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
|
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
migrations.RunPython(update_tree, reverse_code=migrations.RunPython.noop),
|
|
||||||
]
|
]
|
||||||
|
@ -57,6 +57,4 @@ class Migration(migrations.Migration):
|
|||||||
('build', '0028_builditem_bom_item'),
|
('build', '0028_builditem_bom_item'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
migrations.RunPython(assign_bom_items, reverse_code=migrations.RunPython.noop),
|
|
||||||
]
|
|
||||||
|
@ -13,7 +13,7 @@ import math
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
from typing import Any, Callable, Dict, List, Tuple, TypedDict, Union
|
from typing import Any, Callable, Dict, List, Tuple, TypedDict, Union
|
||||||
@ -2850,7 +2850,12 @@ class NotificationMessage(models.Model):
|
|||||||
|
|
||||||
def age(self):
|
def age(self):
|
||||||
"""Age of the message in seconds."""
|
"""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
|
return delta.seconds
|
||||||
|
|
||||||
def age_human(self):
|
def age_human(self):
|
||||||
|
@ -33,6 +33,7 @@ class CompanyResource(InvenTreeResource):
|
|||||||
clean_model_instances = True
|
clean_model_instances = True
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Company)
|
||||||
class CompanyAdmin(ImportExportModelAdmin):
|
class CompanyAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the Company model."""
|
"""Admin class for the Company model."""
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ class SupplierPriceBreakInline(admin.TabularInline):
|
|||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SupplierPart)
|
||||||
class SupplierPartAdmin(ImportExportModelAdmin):
|
class SupplierPartAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the SupplierPart model."""
|
"""Admin class for the SupplierPart model."""
|
||||||
|
|
||||||
@ -105,6 +107,7 @@ class ManufacturerPartResource(InvenTreeResource):
|
|||||||
manufacturer_name = Field(attribute='manufacturer__name', readonly=True)
|
manufacturer_name = Field(attribute='manufacturer__name', readonly=True)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ManufacturerPart)
|
||||||
class ManufacturerPartAdmin(ImportExportModelAdmin):
|
class ManufacturerPartAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for ManufacturerPart model."""
|
"""Admin class for ManufacturerPart model."""
|
||||||
|
|
||||||
@ -117,6 +120,7 @@ class ManufacturerPartAdmin(ImportExportModelAdmin):
|
|||||||
autocomplete_fields = ('part', 'manufacturer')
|
autocomplete_fields = ('part', 'manufacturer')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ManufacturerPartAttachment)
|
||||||
class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin):
|
class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for ManufacturerPartAttachment model."""
|
"""Admin class for ManufacturerPartAttachment model."""
|
||||||
|
|
||||||
@ -137,6 +141,7 @@ class ManufacturerPartParameterResource(InvenTreeResource):
|
|||||||
clean_model_instance = True
|
clean_model_instance = True
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ManufacturerPartParameter)
|
||||||
class ManufacturerPartParameterAdmin(ImportExportModelAdmin):
|
class ManufacturerPartParameterAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for ManufacturerPartParameter model."""
|
"""Admin class for ManufacturerPartParameter model."""
|
||||||
|
|
||||||
@ -173,6 +178,7 @@ class SupplierPriceBreakResource(InvenTreeResource):
|
|||||||
MPN = Field(attribute='part__MPN', readonly=True)
|
MPN = Field(attribute='part__MPN', readonly=True)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SupplierPriceBreak)
|
||||||
class SupplierPriceBreakAdmin(ImportExportModelAdmin):
|
class SupplierPriceBreakAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the SupplierPriceBreak model."""
|
"""Admin class for the SupplierPriceBreak model."""
|
||||||
|
|
||||||
@ -197,6 +203,7 @@ class AddressResource(InvenTreeResource):
|
|||||||
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
|
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Address)
|
||||||
class AddressAdmin(ImportExportModelAdmin):
|
class AddressAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the Address model."""
|
"""Admin class for the Address model."""
|
||||||
|
|
||||||
@ -221,6 +228,7 @@ class ContactResource(InvenTreeResource):
|
|||||||
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
|
company = Field(attribute='company', widget=widgets.ForeignKeyWidget(Company))
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Contact)
|
||||||
class ContactAdmin(ImportExportModelAdmin):
|
class ContactAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the Contact model."""
|
"""Admin class for the Contact model."""
|
||||||
|
|
||||||
@ -229,15 +237,3 @@ class ContactAdmin(ImportExportModelAdmin):
|
|||||||
list_display = ('company', 'name', 'role', 'email', 'phone')
|
list_display = ('company', 'name', 'role', 'email', 'phone')
|
||||||
|
|
||||||
search_fields = ['company', 'name', 'email']
|
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)
|
|
||||||
|
@ -1362,8 +1362,8 @@ class OrderCalendarExport(ICalFeed):
|
|||||||
return super().__call__(request, *args, **kwargs)
|
return super().__call__(request, *args, **kwargs)
|
||||||
|
|
||||||
# No login yet - check in headers
|
# No login yet - check in headers
|
||||||
if 'HTTP_AUTHORIZATION' in request.META:
|
if 'authorization' in request.headers:
|
||||||
auth = request.META['HTTP_AUTHORIZATION'].split()
|
auth = request.headers['authorization'].split()
|
||||||
if len(auth) == 2:
|
if len(auth) == 2:
|
||||||
# NOTE: We are only support basic authentication for now.
|
# NOTE: We are only support basic authentication for now.
|
||||||
#
|
#
|
||||||
|
@ -78,7 +78,14 @@ class TotalPriceMixin(models.Model):
|
|||||||
"""Update the total_price field when saved."""
|
"""Update the total_price field when saved."""
|
||||||
# Recalculate total_price for this order
|
# Recalculate total_price for this order
|
||||||
self.update_total_price(commit=False)
|
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(
|
total_price = InvenTreeModelMoneyField(
|
||||||
null=True,
|
null=True,
|
||||||
@ -136,6 +143,10 @@ class TotalPriceMixin(models.Model):
|
|||||||
|
|
||||||
total = Money(0, target_currency)
|
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
|
# order items
|
||||||
for line in self.lines.all():
|
for line in self.lines.all():
|
||||||
if not line.price:
|
if not line.price:
|
||||||
|
@ -634,7 +634,7 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}),
|
reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}),
|
||||||
format='json',
|
format='json',
|
||||||
HTTP_AUTHORIZATION=f'basic {base64_token}',
|
headers={'authorization': f'basic {base64_token}'},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
@ -57,7 +57,8 @@ class PurchaseOrderTests(OrderViewTestCase):
|
|||||||
def test_po_export(self):
|
def test_po_export(self):
|
||||||
"""Export PurchaseOrder."""
|
"""Export PurchaseOrder."""
|
||||||
response = self.client.get(
|
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)
|
# Response should be streaming-content (file download)
|
||||||
|
@ -245,7 +245,9 @@ def annotate_variant_quantity(subquery: Q, reference: str = 'quantity'):
|
|||||||
Subquery(
|
Subquery(
|
||||||
subquery.annotate(
|
subquery.annotate(
|
||||||
total=Func(F(reference), function='SUM', output_field=FloatField())
|
total=Func(F(reference), function='SUM', output_field=FloatField())
|
||||||
).values('total')
|
)
|
||||||
|
.values('total')
|
||||||
|
.order_by()
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
output_field=FloatField(),
|
output_field=FloatField(),
|
||||||
@ -270,7 +272,9 @@ def annotate_category_parts():
|
|||||||
Subquery(
|
Subquery(
|
||||||
subquery.annotate(
|
subquery.annotate(
|
||||||
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
||||||
).values('total')
|
)
|
||||||
|
.values('total')
|
||||||
|
.order_by()
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
output_field=IntegerField(),
|
output_field=IntegerField(),
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
# Generated by Django 2.2.5 on 2019-09-08 04:04
|
# Generated by Django 2.2.5 on 2019-09-08 04:04
|
||||||
|
|
||||||
from django.db import migrations
|
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):
|
class Migration(migrations.Migration):
|
||||||
@ -18,6 +11,4 @@ class Migration(migrations.Migration):
|
|||||||
('part', '0019_auto_20190908_0404'),
|
('part', '0019_auto_20190908_0404'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
migrations.RunPython(update_tree)
|
|
||||||
]
|
|
||||||
|
@ -2,13 +2,6 @@
|
|||||||
|
|
||||||
from django.db import migrations, models
|
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):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
@ -43,6 +36,4 @@ class Migration(migrations.Migration):
|
|||||||
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
|
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
|
|
||||||
migrations.RunPython(update_tree, reverse_code=migrations.RunPython.noop)
|
|
||||||
]
|
]
|
||||||
|
@ -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 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.
|
If not, it is considered "orphaned" and will be deleted.
|
||||||
"""
|
"""
|
||||||
|
_new = False
|
||||||
if self.pk:
|
if self.pk:
|
||||||
try:
|
try:
|
||||||
previous = Part.objects.get(pk=self.pk)
|
previous = Part.objects.get(pk=self.pk)
|
||||||
@ -470,6 +471,8 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
|||||||
previous.image.delete(save=False)
|
previous.image.delete(save=False)
|
||||||
except Part.DoesNotExist:
|
except Part.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
_new = True
|
||||||
|
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
|
|
||||||
@ -478,6 +481,10 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
|||||||
except InvalidMove:
|
except InvalidMove:
|
||||||
raise ValidationError({'variant_of': _('Invalid choice for parent part')})
|
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):
|
def __str__(self):
|
||||||
"""Return a string representation of the Part (for use in the admin interface)."""
|
"""Return a string representation of the Part (for use in the admin interface)."""
|
||||||
return f'{self.full_name} - {self.description}'
|
return f'{self.full_name} - {self.description}'
|
||||||
@ -827,6 +834,12 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
|||||||
# Run custom validation for the name field
|
# Run custom validation for the name field
|
||||||
self.validate_name()
|
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:
|
if self.trackable:
|
||||||
for part in self.get_used_in():
|
for part in self.get_used_in():
|
||||||
if not part.trackable:
|
if not part.trackable:
|
||||||
|
@ -108,7 +108,7 @@ class PartDetailTest(PartViewTestCase):
|
|||||||
"""Test downloading a BOM for a valid part."""
|
"""Test downloading a BOM for a valid part."""
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse('api-bom-download', args=(1,)),
|
reverse('api-bom-download', args=(1,)),
|
||||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
headers={'x-requested-with': 'XMLHttpRequest'},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertIn('streaming_content', dir(response))
|
self.assertIn('streaming_content', dir(response))
|
||||||
|
@ -106,7 +106,6 @@ class InvenTreePluginTests(TestCase):
|
|||||||
LICENSE = 'MIT'
|
LICENSE = 'MIT'
|
||||||
|
|
||||||
cls.plugin_name = NameInvenTreePlugin()
|
cls.plugin_name = NameInvenTreePlugin()
|
||||||
cls.plugin_sample = SampleIntegrationPlugin()
|
|
||||||
|
|
||||||
class VersionInvenTreePlugin(InvenTreePlugin):
|
class VersionInvenTreePlugin(InvenTreePlugin):
|
||||||
NAME = 'Version'
|
NAME = 'Version'
|
||||||
@ -140,7 +139,7 @@ class InvenTreePluginTests(TestCase):
|
|||||||
|
|
||||||
# is_sample
|
# is_sample
|
||||||
self.assertEqual(self.plugin.is_sample, False)
|
self.assertEqual(self.plugin.is_sample, False)
|
||||||
self.assertEqual(self.plugin_sample.is_sample, True)
|
self.assertEqual(SampleIntegrationPlugin().is_sample, True)
|
||||||
|
|
||||||
# slug
|
# slug
|
||||||
self.assertEqual(self.plugin.slug, '')
|
self.assertEqual(self.plugin.slug, '')
|
||||||
|
@ -15,31 +15,30 @@ from .models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(
|
||||||
|
BillOfMaterialsReport,
|
||||||
|
BuildReport,
|
||||||
|
PurchaseOrderReport,
|
||||||
|
ReturnOrderReport,
|
||||||
|
SalesOrderReport,
|
||||||
|
StockLocationReport,
|
||||||
|
TestReport,
|
||||||
|
)
|
||||||
class ReportTemplateAdmin(admin.ModelAdmin):
|
class ReportTemplateAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for the various reporting models."""
|
"""Admin class for the various reporting models."""
|
||||||
|
|
||||||
list_display = ('name', 'description', 'template', 'filters', 'enabled', 'revision')
|
list_display = ('name', 'description', 'template', 'filters', 'enabled', 'revision')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ReportSnippet)
|
||||||
class ReportSnippetAdmin(admin.ModelAdmin):
|
class ReportSnippetAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for the ReportSnippet model."""
|
"""Admin class for the ReportSnippet model."""
|
||||||
|
|
||||||
list_display = ('id', 'snippet', 'description')
|
list_display = ('id', 'snippet', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ReportAsset)
|
||||||
class ReportAssetAdmin(admin.ModelAdmin):
|
class ReportAssetAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for the ReportAsset model."""
|
"""Admin class for the ReportAsset model."""
|
||||||
|
|
||||||
list_display = ('id', 'asset', 'description')
|
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)
|
|
||||||
|
@ -85,6 +85,7 @@ class LocationInline(admin.TabularInline):
|
|||||||
model = StockLocation
|
model = StockLocation
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockLocation)
|
||||||
class LocationAdmin(ImportExportModelAdmin):
|
class LocationAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for Location."""
|
"""Admin class for Location."""
|
||||||
|
|
||||||
@ -99,6 +100,7 @@ class LocationAdmin(ImportExportModelAdmin):
|
|||||||
autocomplete_fields = ['parent']
|
autocomplete_fields = ['parent']
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockLocationType)
|
||||||
class LocationTypeAdmin(admin.ModelAdmin):
|
class LocationTypeAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for StockLocationType."""
|
"""Admin class for StockLocationType."""
|
||||||
|
|
||||||
@ -268,6 +270,7 @@ class StockItemResource(InvenTreeResource):
|
|||||||
StockItem.objects.rebuild()
|
StockItem.objects.rebuild()
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockItem)
|
||||||
class StockItemAdmin(ImportExportModelAdmin):
|
class StockItemAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for StockItem."""
|
"""Admin class for StockItem."""
|
||||||
|
|
||||||
@ -292,6 +295,7 @@ class StockItemAdmin(ImportExportModelAdmin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockItemAttachment)
|
||||||
class StockAttachmentAdmin(admin.ModelAdmin):
|
class StockAttachmentAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for StockAttachment."""
|
"""Admin class for StockAttachment."""
|
||||||
|
|
||||||
@ -300,6 +304,7 @@ class StockAttachmentAdmin(admin.ModelAdmin):
|
|||||||
autocomplete_fields = ['stock_item']
|
autocomplete_fields = ['stock_item']
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockItemTracking)
|
||||||
class StockTrackingAdmin(ImportExportModelAdmin):
|
class StockTrackingAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for StockTracking."""
|
"""Admin class for StockTracking."""
|
||||||
|
|
||||||
@ -308,17 +313,10 @@ class StockTrackingAdmin(ImportExportModelAdmin):
|
|||||||
autocomplete_fields = ['item']
|
autocomplete_fields = ['item']
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StockItemTestResult)
|
||||||
class StockItemTestResultAdmin(admin.ModelAdmin):
|
class StockItemTestResultAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for StockItemTestResult."""
|
"""Admin class for StockItemTestResult."""
|
||||||
|
|
||||||
list_display = ('stock_item', 'test', 'result', 'value')
|
list_display = ('stock_item', 'test', 'result', 'value')
|
||||||
|
|
||||||
autocomplete_fields = ['stock_item']
|
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)
|
|
||||||
|
@ -30,7 +30,9 @@ def annotate_location_items(filter: Q = None):
|
|||||||
Subquery(
|
Subquery(
|
||||||
subquery.annotate(
|
subquery.annotate(
|
||||||
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
||||||
).values('total')
|
)
|
||||||
|
.values('total')
|
||||||
|
.order_by()
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
output_field=IntegerField(),
|
output_field=IntegerField(),
|
||||||
@ -50,7 +52,9 @@ def annotate_child_items():
|
|||||||
Subquery(
|
Subquery(
|
||||||
child_stock_query.annotate(
|
child_stock_query.annotate(
|
||||||
count=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
count=Func(F('pk'), function='COUNT', output_field=IntegerField())
|
||||||
).values('count')
|
)
|
||||||
|
.values('count')
|
||||||
|
.order_by()
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
output_field=IntegerField(),
|
output_field=IntegerField(),
|
||||||
|
@ -2,13 +2,6 @@
|
|||||||
|
|
||||||
from django.db import migrations
|
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):
|
class Migration(migrations.Migration):
|
||||||
@ -19,6 +12,4 @@ class Migration(migrations.Migration):
|
|||||||
('stock', '0011_auto_20190908_0404'),
|
('stock', '0011_auto_20190908_0404'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
migrations.RunPython(update_tree)
|
|
||||||
]
|
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
# Generated by Django 2.2.9 on 2020-02-17 11:09
|
# Generated by Django 2.2.9 on 2020-02-17 11:09
|
||||||
|
|
||||||
from django.db import migrations
|
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):
|
class Migration(migrations.Migration):
|
||||||
@ -18,6 +11,4 @@ class Migration(migrations.Migration):
|
|||||||
('stock', '0021_auto_20200215_2232'),
|
('stock', '0021_auto_20200215_2232'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
migrations.RunPython(update_stock_item_tree)
|
|
||||||
]
|
|
||||||
|
@ -107,7 +107,8 @@ class StockLocationManager(TreeManager):
|
|||||||
|
|
||||||
- Joins the StockLocationType by default for speedier icon access
|
- 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):
|
class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||||
|
@ -13,6 +13,7 @@ from users.models import ApiToken, Owner, RuleSet
|
|||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ApiToken)
|
||||||
class ApiTokenAdmin(admin.ModelAdmin):
|
class ApiTokenAdmin(admin.ModelAdmin):
|
||||||
"""Admin class for the ApiToken model."""
|
"""Admin class for the ApiToken model."""
|
||||||
|
|
||||||
@ -288,6 +289,7 @@ class InvenTreeUserAdmin(UserAdmin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Owner)
|
||||||
class OwnerAdmin(admin.ModelAdmin):
|
class OwnerAdmin(admin.ModelAdmin):
|
||||||
"""Custom admin interface for the Owner model."""
|
"""Custom admin interface for the Owner model."""
|
||||||
|
|
||||||
@ -299,7 +301,3 @@ admin.site.register(Group, RoleGroupAdmin)
|
|||||||
|
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User, InvenTreeUserAdmin)
|
admin.site.register(User, InvenTreeUserAdmin)
|
||||||
|
|
||||||
admin.site.register(Owner, OwnerAdmin)
|
|
||||||
|
|
||||||
admin.site.register(ApiToken, ApiTokenAdmin)
|
|
||||||
|
@ -262,7 +262,7 @@ class GetAuthToken(APIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Add some metadata about the request
|
# 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_addr', request.META.get('REMOTE_ADDR', ''))
|
||||||
token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))
|
token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))
|
||||||
token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))
|
token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))
|
||||||
|
@ -10,7 +10,7 @@ asgiref==3.7.2
|
|||||||
# django
|
# django
|
||||||
build==1.0.3
|
build==1.0.3
|
||||||
# via pip-tools
|
# via pip-tools
|
||||||
certifi==2023.7.22
|
certifi==2023.11.17
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# requests
|
# requests
|
||||||
@ -33,13 +33,13 @@ coverage[toml]==5.5
|
|||||||
# coveralls
|
# coveralls
|
||||||
coveralls==2.1.2
|
coveralls==2.1.2
|
||||||
# via -r requirements-dev.in
|
# via -r requirements-dev.in
|
||||||
cryptography==41.0.6
|
cryptography==41.0.7
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# pdfminer-six
|
# pdfminer-six
|
||||||
distlib==0.3.7
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
django==3.2.23
|
django==4.2.9
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# django-slowtests
|
# django-slowtests
|
||||||
@ -53,7 +53,7 @@ filelock==3.13.1
|
|||||||
# via virtualenv
|
# via virtualenv
|
||||||
identify==2.5.31
|
identify==2.5.31
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
idna==3.4
|
idna==3.6
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# requests
|
# requests
|
||||||
@ -61,7 +61,7 @@ importlib-metadata==6.8.0
|
|||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# build
|
# build
|
||||||
isort==5.12.0
|
isort==5.13.2
|
||||||
# via -r requirements-dev.in
|
# via -r requirements-dev.in
|
||||||
nodeenv==1.8.0
|
nodeenv==1.8.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
@ -69,13 +69,13 @@ packaging==23.2
|
|||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# build
|
# build
|
||||||
pdfminer-six==20221105
|
pdfminer-six==20231228
|
||||||
# via -r requirements-dev.in
|
# via -r requirements-dev.in
|
||||||
pip-tools==7.3.0
|
pip-tools==7.3.0
|
||||||
# via -r requirements-dev.in
|
# via -r requirements-dev.in
|
||||||
platformdirs==3.11.0
|
platformdirs==4.1.0
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pre-commit==3.5.0
|
pre-commit==3.6.0
|
||||||
# via -r requirements-dev.in
|
# via -r requirements-dev.in
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
# via
|
# via
|
||||||
@ -83,10 +83,6 @@ pycparser==2.21
|
|||||||
# cffi
|
# cffi
|
||||||
pyproject-hooks==1.0.0
|
pyproject-hooks==1.0.0
|
||||||
# via build
|
# via build
|
||||||
pytz==2023.3.post1
|
|
||||||
# via
|
|
||||||
# -c requirements.txt
|
|
||||||
# django
|
|
||||||
pyyaml==6.0.1
|
pyyaml==6.0.1
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
@ -106,20 +102,20 @@ tomli==2.0.1
|
|||||||
# build
|
# build
|
||||||
# pip-tools
|
# pip-tools
|
||||||
# pyproject-hooks
|
# pyproject-hooks
|
||||||
typing-extensions==4.8.0
|
typing-extensions==4.9.0
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# asgiref
|
# asgiref
|
||||||
# django-test-migrations
|
# django-test-migrations
|
||||||
urllib3==2.0.7
|
urllib3==2.1.0
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# requests
|
# requests
|
||||||
virtualenv==20.24.6
|
virtualenv==20.25.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
wheel==0.41.3
|
wheel==0.42.0
|
||||||
# via pip-tools
|
# via pip-tools
|
||||||
zipp==3.16.0
|
zipp==3.16.2
|
||||||
# via
|
# via
|
||||||
# -c requirements.txt
|
# -c requirements.txt
|
||||||
# importlib-metadata
|
# importlib-metadata
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Please keep this list sorted - if you pin a version provide a reason
|
# 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
|
coreapi # API documentation for djangorestframework
|
||||||
cryptography>=40.0.0,!=40.0.2 # Core cryptographic functionality
|
cryptography>=40.0.0,!=40.0.2 # Core cryptographic functionality
|
||||||
django-allauth # SSO for external providers via OpenID
|
django-allauth # SSO for external providers via OpenID
|
||||||
@ -13,11 +13,13 @@ django-filter # Extended filtering options
|
|||||||
django-flags # Feature flags
|
django-flags # Feature flags
|
||||||
django-formtools # Form wizard tools
|
django-formtools # Form wizard tools
|
||||||
django-ical # iCal export for calendar views
|
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-maintenance-mode # Shut down application while reloading etc.
|
||||||
django-markdownify # Markdown rendering
|
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-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-redis>=5.0.0 # Redis integration
|
||||||
django-q2 # Background task scheduling
|
django-q2 # Background task scheduling
|
||||||
django-q-sentry # sentry.io integration for django-q
|
django-q-sentry # sentry.io integration for django-q
|
||||||
|
@ -5,14 +5,16 @@
|
|||||||
# pip-compile --output-file=requirements.txt requirements.in
|
# pip-compile --output-file=requirements.txt requirements.in
|
||||||
#
|
#
|
||||||
asgiref==3.7.2
|
asgiref==3.7.2
|
||||||
# via django
|
# via
|
||||||
|
# django
|
||||||
|
# django-cors-headers
|
||||||
async-timeout==4.0.3
|
async-timeout==4.0.3
|
||||||
# via redis
|
# via redis
|
||||||
attrs==23.1.0
|
attrs==23.2.0
|
||||||
# via
|
# via
|
||||||
# jsonschema
|
# jsonschema
|
||||||
# referencing
|
# referencing
|
||||||
babel==2.13.1
|
babel==2.14.0
|
||||||
# via py-moneyed
|
# via py-moneyed
|
||||||
backoff==2.2.1
|
backoff==2.2.1
|
||||||
# via
|
# via
|
||||||
@ -25,7 +27,7 @@ bleach[css]==6.1.0
|
|||||||
# django-markdownify
|
# django-markdownify
|
||||||
brotli==1.1.0
|
brotli==1.1.0
|
||||||
# via fonttools
|
# via fonttools
|
||||||
certifi==2023.7.22
|
certifi==2023.11.17
|
||||||
# via
|
# via
|
||||||
# requests
|
# requests
|
||||||
# sentry-sdk
|
# sentry-sdk
|
||||||
@ -39,7 +41,7 @@ coreapi==2.3.3
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
coreschema==0.0.4
|
coreschema==0.0.4
|
||||||
# via coreapi
|
# via coreapi
|
||||||
cryptography==41.0.6
|
cryptography==41.0.7
|
||||||
# via
|
# via
|
||||||
# -r requirements.in
|
# -r requirements.in
|
||||||
# djangorestframework-simplejwt
|
# djangorestframework-simplejwt
|
||||||
@ -59,7 +61,7 @@ diff-match-patch==20230430
|
|||||||
# via django-import-export
|
# via django-import-export
|
||||||
dj-rest-auth==5.0.2
|
dj-rest-auth==5.0.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django==3.2.23
|
django==4.2.9
|
||||||
# via
|
# via
|
||||||
# -r requirements.in
|
# -r requirements.in
|
||||||
# dj-rest-auth
|
# dj-rest-auth
|
||||||
@ -76,7 +78,6 @@ django==3.2.23
|
|||||||
# django-js-asset
|
# django-js-asset
|
||||||
# django-markdownify
|
# django-markdownify
|
||||||
# django-money
|
# django-money
|
||||||
# django-mptt
|
|
||||||
# django-otp
|
# django-otp
|
||||||
# django-picklefield
|
# django-picklefield
|
||||||
# django-q2
|
# django-q2
|
||||||
@ -101,7 +102,7 @@ django-allauth-2fa==0.11.1
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-cleanup==8.0.0
|
django-cleanup==8.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-cors-headers==4.3.0
|
django-cors-headers==4.3.1
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-crispy-forms==1.14.0
|
django-crispy-forms==1.14.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
@ -109,17 +110,17 @@ django-dbbackup==4.0.2
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-error-report-2==0.4.2
|
django-error-report-2==0.4.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-filter==23.3
|
django-filter==23.5
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-flags==5.0.13
|
django-flags==5.0.13
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-formtools==2.4.1
|
django-formtools==2.5.1
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-ical==1.9.2
|
django-ical==1.9.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-import-export==3.3.1
|
django-import-export==3.3.5
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-js-asset==2.1.0
|
django-js-asset==2.2.0
|
||||||
# via django-mptt
|
# via django-mptt
|
||||||
django-maintenance-mode==0.21.0
|
django-maintenance-mode==0.21.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
@ -127,9 +128,9 @@ django-markdownify==0.9.3
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-money==3.2.0
|
django-money==3.2.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-mptt==0.11.0
|
django-mptt==0.16.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-otp==1.2.4
|
django-otp==1.3.0
|
||||||
# via django-allauth-2fa
|
# via django-allauth-2fa
|
||||||
django-picklefield==3.1
|
django-picklefield==3.1
|
||||||
# via django-q2
|
# via django-q2
|
||||||
@ -141,7 +142,7 @@ django-recurrence==1.11.1
|
|||||||
# via django-ical
|
# via django-ical
|
||||||
django-redis==5.4.0
|
django-redis==5.4.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-sesame==3.2.1
|
django-sesame==3.2.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-sql-utils==0.7.0
|
django-sql-utils==0.7.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
@ -149,11 +150,11 @@ django-sslserver==0.22
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-stdimage==6.0.2
|
django-stdimage==6.0.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-taggit==4.0.0
|
django-taggit==5.0.1
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-user-sessions==2.0.0
|
django-user-sessions==2.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-weasyprint==2.2.1
|
django-weasyprint==2.2.2
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-xforwardedfor-middleware==2.0
|
django-xforwardedfor-middleware==2.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
@ -163,15 +164,15 @@ djangorestframework==3.14.0
|
|||||||
# dj-rest-auth
|
# dj-rest-auth
|
||||||
# djangorestframework-simplejwt
|
# djangorestframework-simplejwt
|
||||||
# drf-spectacular
|
# drf-spectacular
|
||||||
djangorestframework-simplejwt[crypto]==5.3.0
|
djangorestframework-simplejwt[crypto]==5.3.1
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
drf-spectacular==0.26.5
|
drf-spectacular==0.27.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
dulwich==0.21.6
|
dulwich==0.21.7
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
et-xmlfile==1.1.0
|
et-xmlfile==1.1.0
|
||||||
# via openpyxl
|
# via openpyxl
|
||||||
feedparser==6.0.10
|
feedparser==6.0.11
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
fonttools[woff]==4.44.0
|
fonttools[woff]==4.44.0
|
||||||
# via
|
# via
|
||||||
@ -189,7 +190,7 @@ html5lib==1.1
|
|||||||
# via weasyprint
|
# via weasyprint
|
||||||
icalendar==5.0.11
|
icalendar==5.0.11
|
||||||
# via django-ical
|
# via django-ical
|
||||||
idna==3.4
|
idna==3.6
|
||||||
# via requests
|
# via requests
|
||||||
importlib-metadata==6.8.0
|
importlib-metadata==6.8.0
|
||||||
# via
|
# via
|
||||||
@ -202,9 +203,9 @@ itypes==1.2.0
|
|||||||
# via coreapi
|
# via coreapi
|
||||||
jinja2==3.1.3
|
jinja2==3.1.3
|
||||||
# via coreschema
|
# via coreschema
|
||||||
jsonschema==4.19.2
|
jsonschema==4.20.0
|
||||||
# via drf-spectacular
|
# via drf-spectacular
|
||||||
jsonschema-specifications==2023.7.1
|
jsonschema-specifications==2023.12.1
|
||||||
# via jsonschema
|
# via jsonschema
|
||||||
markdown==3.5.1
|
markdown==3.5.1
|
||||||
# via django-markdownify
|
# via django-markdownify
|
||||||
@ -277,7 +278,7 @@ opentelemetry-util-http==0.43b0
|
|||||||
# opentelemetry-instrumentation-wsgi
|
# opentelemetry-instrumentation-wsgi
|
||||||
packaging==23.2
|
packaging==23.2
|
||||||
# via gunicorn
|
# via gunicorn
|
||||||
pdf2image==1.16.3
|
pdf2image==1.17.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
pillow==10.2.0
|
pillow==10.2.0
|
||||||
# via
|
# via
|
||||||
@ -316,13 +317,12 @@ python-dateutil==2.8.2
|
|||||||
# icalendar
|
# icalendar
|
||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
python-fsutil==0.12.0
|
python-fsutil==0.13.0
|
||||||
# via django-maintenance-mode
|
# via django-maintenance-mode
|
||||||
python3-openid==3.2.0
|
python3-openid==3.2.0
|
||||||
# via django-allauth
|
# via django-allauth
|
||||||
pytz==2023.3.post1
|
pytz==2023.3.post1
|
||||||
# via
|
# via
|
||||||
# django
|
|
||||||
# django-dbbackup
|
# django-dbbackup
|
||||||
# djangorestframework
|
# djangorestframework
|
||||||
# icalendar
|
# icalendar
|
||||||
@ -339,11 +339,11 @@ rapidfuzz==0.7.6
|
|||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
redis==5.0.1
|
redis==5.0.1
|
||||||
# via django-redis
|
# via django-redis
|
||||||
referencing==0.30.2
|
referencing==0.32.1
|
||||||
# via
|
# via
|
||||||
# jsonschema
|
# jsonschema
|
||||||
# jsonschema-specifications
|
# jsonschema-specifications
|
||||||
regex==2023.10.3
|
regex==2023.12.25
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
# via
|
# via
|
||||||
@ -353,11 +353,11 @@ requests==2.31.0
|
|||||||
# requests-oauthlib
|
# requests-oauthlib
|
||||||
requests-oauthlib==1.3.1
|
requests-oauthlib==1.3.1
|
||||||
# via django-allauth
|
# via django-allauth
|
||||||
rpds-py==0.12.0
|
rpds-py==0.16.2
|
||||||
# via
|
# via
|
||||||
# jsonschema
|
# jsonschema
|
||||||
# referencing
|
# referencing
|
||||||
sentry-sdk==1.34.0
|
sentry-sdk==1.39.2
|
||||||
# via
|
# via
|
||||||
# -r requirements.in
|
# -r requirements.in
|
||||||
# django-q-sentry
|
# django-q-sentry
|
||||||
@ -381,9 +381,10 @@ tinycss2==1.2.1
|
|||||||
# bleach
|
# bleach
|
||||||
# cssselect2
|
# cssselect2
|
||||||
# weasyprint
|
# weasyprint
|
||||||
typing-extensions==4.8.0
|
typing-extensions==4.9.0
|
||||||
# via
|
# via
|
||||||
# asgiref
|
# asgiref
|
||||||
|
# drf-spectacular
|
||||||
# opentelemetry-sdk
|
# opentelemetry-sdk
|
||||||
# py-moneyed
|
# py-moneyed
|
||||||
# qrcode
|
# qrcode
|
||||||
@ -391,12 +392,12 @@ uritemplate==4.1.1
|
|||||||
# via
|
# via
|
||||||
# coreapi
|
# coreapi
|
||||||
# drf-spectacular
|
# drf-spectacular
|
||||||
urllib3==2.0.7
|
urllib3==2.1.0
|
||||||
# via
|
# via
|
||||||
# dulwich
|
# dulwich
|
||||||
# requests
|
# requests
|
||||||
# sentry-sdk
|
# sentry-sdk
|
||||||
weasyprint==60.1
|
weasyprint==60.2
|
||||||
# via
|
# via
|
||||||
# -r requirements.in
|
# -r requirements.in
|
||||||
# django-weasyprint
|
# django-weasyprint
|
||||||
@ -415,7 +416,7 @@ xlrd==2.0.1
|
|||||||
# via tablib
|
# via tablib
|
||||||
xlwt==1.3.0
|
xlwt==1.3.0
|
||||||
# via tablib
|
# via tablib
|
||||||
zipp==3.16.0
|
zipp==3.16.2
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
zopfli==0.2.3
|
zopfli==0.2.3
|
||||||
# via fonttools
|
# via fonttools
|
||||||
|
Loading…
Reference in New Issue
Block a user