From d133d2abffafc12670ef045c40fb7e45385ef123 Mon Sep 17 00:00:00 2001
From: Raphael Michel
Date: Sat, 12 Dec 2015 13:08:33 +0100
Subject: [PATCH] Removed CleanerVersion layer [backwards-incompatible!]
---
doc/development/models.rst | 20 --
src/pretix/base/exporter.py | 26 +-
src/pretix/base/forms/__init__.py | 40 ---
src/pretix/base/migrations/0001_initial.py | 316 +++++++-----------
.../migrations/0002_auto_20151021_1412.py | 19 --
.../migrations/0002_auto_20151212_1123.py | 23 ++
.../base/migrations/0003_event_is_public.py | 19 --
.../migrations/0004_auto_20151024_0848.py | 24 --
.../migrations/0005_auto_20151206_1652.py | 24 --
src/pretix/base/models/__init__.py | 4 +-
src/pretix/base/models/base.py | 61 +---
src/pretix/base/models/event.py | 17 +-
src/pretix/base/models/items.py | 76 ++---
src/pretix/base/models/orders.py | 72 ++--
src/pretix/base/models/organizer.py | 12 +-
src/pretix/base/payment.py | 8 +-
src/pretix/base/services/cart.py | 38 +--
src/pretix/base/services/export.py | 2 +-
src/pretix/base/services/locking.py | 8 +-
src/pretix/base/services/orders.py | 15 +-
src/pretix/base/services/stats.py | 35 +-
src/pretix/base/services/tickets.py | 2 +-
src/pretix/base/settings.py | 10 +-
src/pretix/control/forms/__init__.py | 34 +-
src/pretix/control/forms/event.py | 6 +-
src/pretix/control/forms/item.py | 48 +--
src/pretix/control/forms/orders.py | 4 +-
src/pretix/control/forms/organizer.py | 4 +-
src/pretix/control/middleware.py | 8 +-
src/pretix/control/permissions.py | 4 +-
.../templates/pretixcontrol/item/base.html | 10 +-
.../pretixcontrol/items/categories.html | 8 +-
.../templates/pretixcontrol/items/index.html | 8 +-
.../pretixcontrol/items/questions.html | 4 +-
.../templates/pretixcontrol/items/quota.html | 4 +-
.../templates/pretixcontrol/items/quotas.html | 6 +-
.../templates/pretixcontrol/orders/index.html | 4 +-
.../pretixcontrol/orders/overview.html | 10 +-
src/pretix/control/urls.py | 28 +-
src/pretix/control/views/event.py | 20 +-
src/pretix/control/views/item.py | 118 ++++---
src/pretix/control/views/main.py | 4 +-
src/pretix/control/views/orders.py | 22 +-
src/pretix/control/views/organizer.py | 4 +-
.../multidomain/migrations/0001_initial.py | 9 +-
.../migrations/0002_auto_20151018_1007.py | 24 --
src/pretix/multidomain/models.py | 3 +-
src/pretix/plugins/banktransfer/hbci.py | 2 +-
src/pretix/plugins/banktransfer/views.py | 7 +-
src/pretix/plugins/paypal/payment.py | 1 -
src/pretix/plugins/paypal/views.py | 6 +-
src/pretix/plugins/pretixdroid/views.py | 6 +-
src/pretix/plugins/sendmail/views.py | 2 +-
src/pretix/plugins/statistics/views.py | 20 +-
src/pretix/plugins/stripe/payment.py | 9 +-
src/pretix/plugins/stripe/views.py | 4 +-
.../plugins/ticketoutputpdf/ticketoutput.py | 4 +-
src/pretix/presale/checkoutflow.py | 10 +-
src/pretix/presale/forms/checkout.py | 4 +-
src/pretix/presale/middleware.py | 6 +-
.../event/checkout_questions.html | 4 +-
.../pretixpresale/event/fragment_cart.html | 8 +-
.../templates/pretixpresale/event/index.html | 8 +-
.../pretixpresale/event/order_modify.html | 4 +-
src/pretix/presale/views/__init__.py | 8 +-
src/pretix/presale/views/cart.py | 8 +-
src/pretix/presale/views/event.py | 3 +-
src/pretix/presale/views/order.py | 13 +-
src/pretix/presale/views/organizer.py | 2 +-
src/pretix/presale/views/questions.py | 4 +-
src/requirements/production.txt | 2 -
src/tests/base/test_locking.py | 4 +-
src/tests/base/test_models.py | 27 +-
src/tests/base/test_settings.py | 29 +-
src/tests/control/test_events.py | 8 -
src/tests/control/test_items.py | 63 ++--
src/tests/control/test_orders.py | 46 +--
src/tests/control/test_permissions.py | 36 +-
src/tests/plugins/banktransfer/test_import.py | 4 +-
src/tests/plugins/test_pretixdroid.py | 4 +-
src/tests/presale/test_cart.py | 62 ++--
src/tests/presale/test_checkout.py | 68 ++--
src/tests/presale/test_event.py | 8 +-
src/tests/presale/test_orders.py | 30 +-
src/tests/testdummy/ticketoutput.py | 2 +-
85 files changed, 712 insertions(+), 1089 deletions(-)
delete mode 100644 src/pretix/base/migrations/0002_auto_20151021_1412.py
create mode 100644 src/pretix/base/migrations/0002_auto_20151212_1123.py
delete mode 100644 src/pretix/base/migrations/0003_event_is_public.py
delete mode 100644 src/pretix/base/migrations/0004_auto_20151024_0848.py
delete mode 100644 src/pretix/base/migrations/0005_auto_20151206_1652.py
delete mode 100644 src/pretix/multidomain/migrations/0002_auto_20151018_1007.py
diff --git a/doc/development/models.rst b/doc/development/models.rst
index d4c1ed9f19..4105490d89 100644
--- a/doc/development/models.rst
+++ b/doc/development/models.rst
@@ -8,26 +8,6 @@ Pretix provides the following data(base) models. Every model and every model met
documented here is considered private and should not be used by third-party plugins, as it may change
without advance notice.
-.. IMPORTANT::
- pretix's models are built with `cleanerversion`_, which extends the default Django ORM by adding versioning
- information to the database. There are basically three things you absolutely need to know about cleanerversion:
-
- * When querying the database, make sure you only get the current versions::
-
- queryset = Model.objects.current.filter(…)
-
- * Before you modify an object, clone it::
-
- obj = Model.objects.current.get(identity=1) # Prefer identities over primary keys
- obj = obj.clone() # Saves the old version to the database and creates the new one
- obj.foo = 'bar'
- obj.save()
-
- * Beware of batch operations, use ``queryset.update()``, ``queryset.delete()`` etc. only if
- you know what you're doing.
-
- There is one exception: The ``User`` model is a classic Django model!
-
User model
----------
diff --git a/src/pretix/base/exporter.py b/src/pretix/base/exporter.py
index 2be7444d34..b66a447b24 100644
--- a/src/pretix/base/exporter.py
+++ b/src/pretix/base/exporter.py
@@ -87,13 +87,13 @@ class JSONExporter(BaseExporter):
},
'categories': [
{
- 'id': category.identity,
+ 'id': category.id,
'name': str(category.name)
- } for category in self.event.categories.current.all()
+ } for category in self.event.categories.all()
],
'items': [
{
- 'id': item.identity,
+ 'id': item.id,
'name': str(item.name),
'category': item.category_id,
'price': item.default_price,
@@ -101,20 +101,20 @@ class JSONExporter(BaseExporter):
'active': item.active,
'variations': [
{
- 'id': variation.identity,
+ 'id': variation.id,
'active': variation.active,
'price': variation.default_price if variation.default_price is not None else item.default_price,
'name': str(variation)
- } for variation in item.variations.current.all()
+ } for variation in item.variations.all()
]
- } for item in self.event.items.current.all().prefetch_related('variations')
+ } for item in self.event.items.all().prefetch_related('variations')
],
'questions': [
{
- 'id': question.identity,
+ 'id': question.id,
'question': str(question.question),
'type': question.type
- } for question in self.event.questions.current.all()
+ } for question in self.event.questions.all()
],
'orders': [
{
@@ -126,7 +126,7 @@ class JSONExporter(BaseExporter):
'total': order.total,
'positions': [
{
- 'id': position.identity,
+ 'id': position.id,
'item': position.item_id,
'variation': position.variation_id,
'price': position.price,
@@ -137,19 +137,19 @@ class JSONExporter(BaseExporter):
'answer': answer.answer
} for answer in position.answers.all()
]
- } for position in order.positions.current.all()
+ } for position in order.positions.all()
]
} for order in
- self.event.orders.current.all().prefetch_related('positions', 'positions__answers').select_related(
+ self.event.orders.all().prefetch_related('positions', 'positions__answers').select_related(
'user')
],
'quotas': [
{
- 'id': quota.identity,
+ 'id': quota.id,
'size': quota.size,
'items': [item.id for item in quota.items.all()],
'variations': [variation.id for variation in quota.variations.all()],
- } for quota in self.event.quotas.current.all().prefetch_related('items', 'variations')
+ } for quota in self.event.quotas.all().prefetch_related('items', 'variations')
]
}
}
diff --git a/src/pretix/base/forms/__init__.py b/src/pretix/base/forms/__init__.py
index e8dd49ec8d..339b3fe379 100644
--- a/src/pretix/base/forms/__init__.py
+++ b/src/pretix/base/forms/__init__.py
@@ -5,11 +5,9 @@ from django import forms
from django.core.files import File
from django.core.files.storage import default_storage
from django.core.files.uploadedfile import UploadedFile
-from django.db import models
from django.forms.models import BaseModelForm, ModelFormMetaclass
from django.utils import six
from django.utils.translation import ugettext_lazy as _
-from versions.models import Versionable
from pretix.base.i18n import I18nFormField
from pretix.base.models import Event
@@ -30,44 +28,6 @@ class BaseI18nModelForm(BaseModelForm):
field.widget.enabled_langcodes = event.settings.get('locales')
-class VersionedBaseModelForm(BaseI18nModelForm):
- """
- This is a helperclass to construct VersionedModelForm
- """
- def __init__(self, *args, **kwargs):
- instance = kwargs.get('instance', None)
- self.original_instance = copy.copy(instance) if instance else None
- super().__init__(*args, **kwargs)
-
- def save(self, commit=True):
- if self.instance.pk is not None and isinstance(self.instance, Versionable):
- if self.has_changed() and self.original_instance:
- new = self.instance
- old = self.original_instance
- clone = old.clone()
- for f in type(self.instance)._meta.get_fields():
- if f.name not in (
- 'id', 'identity', 'version_start_date', 'version_end_date',
- 'version_birth_date'
- ) and not isinstance(f, (
- models.ManyToOneRel, models.ManyToManyRel, models.ManyToManyField
- )):
- setattr(clone, f.name, getattr(new, f.name))
- self.instance = clone
- return super().save(commit)
-
-
-class VersionedModelForm(six.with_metaclass(ModelFormMetaclass, VersionedBaseModelForm)):
- """
- This is a modified version of I18nModelForm which differs from I18nModelForm in
- only one way: It executes the .clone() method of an object before saving it back to
- the database, if the model is a sub-class of versions.models.Versionable. You can
- safely use this as a base class for all your model forms, it will work out correctly
- with both versioned and non-versioned models.
- """
- pass
-
-
class I18nModelForm(six.with_metaclass(ModelFormMetaclass, BaseI18nModelForm)):
"""
This is a modified version of Django's ModelForm which differs from ModelForm in
diff --git a/src/pretix/base/migrations/0001_initial.py b/src/pretix/base/migrations/0001_initial.py
index 79df631421..91e65ce6c5 100644
--- a/src/pretix/base/migrations/0001_initial.py
+++ b/src/pretix/base/migrations/0001_initial.py
@@ -5,12 +5,23 @@ import uuid
import django.core.validators
import django.db.models.deletion
-import versions.models
from django.conf import settings
+from django.contrib.auth.hashers import make_password
from django.db import migrations, models
import pretix.base.i18n
-import pretix.base.models
+import pretix.base.models.base
+import pretix.base.models.items
+import pretix.base.models.orders
+
+
+def initial_user(apps, schema_editor):
+ User = apps.get_model("pretixbase", "User")
+ user = User(email='admin@localhost')
+ user.is_staff = True
+ user.is_superuser = True
+ user.password = make_password('admin')
+ user.save()
class Migration(migrations.Migration):
@@ -23,20 +34,20 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='User',
fields=[
- ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('password', models.CharField(verbose_name='password', max_length=128)),
- ('last_login', models.DateTimeField(verbose_name='last login', null=True, blank=True)),
- ('is_superuser', models.BooleanField(default=False, verbose_name='superuser status', help_text='Designates that this user has all permissions without explicitly assigning them.')),
- ('email', models.EmailField(unique=True, verbose_name='E-mail', blank=True, db_index=True, max_length=254, null=True)),
- ('givenname', models.CharField(verbose_name='Given name', null=True, max_length=255, blank=True)),
- ('familyname', models.CharField(verbose_name='Family name', null=True, max_length=255, blank=True)),
- ('is_active', models.BooleanField(default=True, verbose_name='Is active')),
- ('is_staff', models.BooleanField(default=False, verbose_name='Is site admin')),
+ ('last_login', models.DateTimeField(verbose_name='last login', blank=True, null=True)),
+ ('is_superuser', models.BooleanField(verbose_name='superuser status', default=False, help_text='Designates that this user has all permissions without explicitly assigning them.')),
+ ('email', models.EmailField(max_length=254, blank=True, unique=True, verbose_name='E-mail', null=True, db_index=True)),
+ ('givenname', models.CharField(verbose_name='Given name', max_length=255, blank=True, null=True)),
+ ('familyname', models.CharField(verbose_name='Family name', max_length=255, blank=True, null=True)),
+ ('is_active', models.BooleanField(verbose_name='Is active', default=True)),
+ ('is_staff', models.BooleanField(verbose_name='Is site admin', default=False)),
('date_joined', models.DateTimeField(verbose_name='Date joined', auto_now_add=True)),
- ('locale', models.CharField(default='en', verbose_name='Language', choices=[('en', 'English'), ('de', 'German'), ('de-informal', 'German (informal)')], max_length=50)),
- ('timezone', models.CharField(default='UTC', verbose_name='Timezone', max_length=100)),
- ('groups', models.ManyToManyField(related_query_name='user', verbose_name='groups', help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', blank=True, related_name='user_set', to='auth.Group')),
- ('user_permissions', models.ManyToManyField(related_query_name='user', verbose_name='user permissions', help_text='Specific permissions for this user.', blank=True, related_name='user_set', to='auth.Permission')),
+ ('locale', models.CharField(verbose_name='Language', default='en', choices=[('en', 'English'), ('de', 'German'), ('de-informal', 'German (informal)')], max_length=50)),
+ ('timezone', models.CharField(verbose_name='Timezone', default='UTC', max_length=100)),
+ ('groups', models.ManyToManyField(to='auth.Group', blank=True, related_query_name='user', verbose_name='groups', help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set')),
+ ('user_permissions', models.ManyToManyField(to='auth.Permission', blank=True, related_query_name='user', verbose_name='user permissions', help_text='Specific permissions for this user.', related_name='user_set')),
],
options={
'verbose_name': 'User',
@@ -47,17 +58,17 @@ class Migration(migrations.Migration):
name='CachedFile',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
- ('expires', models.DateTimeField(null=True, blank=True)),
- ('date', models.DateTimeField(null=True, blank=True)),
+ ('expires', models.DateTimeField(blank=True, null=True)),
+ ('date', models.DateTimeField(blank=True, null=True)),
('filename', models.CharField(max_length=255)),
('type', models.CharField(max_length=255)),
- ('file', models.FileField(upload_to=pretix.base.models.cachedfile_name, null=True, blank=True)),
+ ('file', models.FileField(blank=True, null=True, upload_to=pretix.base.models.base.cachedfile_name)),
],
),
migrations.CreateModel(
name='CachedTicket',
fields=[
- ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('provider', models.CharField(max_length=255)),
('cachedfile', models.ForeignKey(to='pretixbase.CachedFile')),
],
@@ -65,39 +76,32 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='CartPosition',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
- ('session', models.CharField(verbose_name='Session', null=True, max_length=255, blank=True)),
- ('price', models.DecimalField(decimal_places=2, verbose_name='Price', max_digits=10)),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
+ ('cart_id', models.CharField(verbose_name='Cart ID (e.g. session key)', max_length=255, blank=True, null=True)),
+ ('price', models.DecimalField(verbose_name='Price', max_digits=10, decimal_places=2)),
('datetime', models.DateTimeField(verbose_name='Date', auto_now_add=True)),
('expires', models.DateTimeField(verbose_name='Expiration date')),
- ('attendee_name', models.CharField(verbose_name='Attendee name', null=True, help_text='Empty, if this product is not an admission ticket', max_length=255, blank=True)),
+ ('attendee_name', models.CharField(verbose_name='Attendee name', max_length=255, blank=True, null=True, help_text='Empty, if this product is not an admission ticket')),
],
options={
'verbose_name': 'Cart position',
'verbose_name_plural': 'Cart positions',
},
- bases=(pretix.base.models.ObjectWithAnswers, models.Model),
+ bases=(pretix.base.models.orders.ObjectWithAnswers, models.Model),
),
migrations.CreateModel(
name='Event',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', pretix.base.i18n.I18nCharField(verbose_name='Name', max_length=200)),
- ('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9.-]+$', message='The slug may only contain letters, numbers, dots and dashes.')])),
- ('currency', models.CharField(default='EUR', verbose_name='Default currency', max_length=10)),
+ ('slug', models.SlugField(verbose_name='Slug', validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')], help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.')),
+ ('currency', models.CharField(verbose_name='Default currency', default='EUR', max_length=10)),
('date_from', models.DateTimeField(verbose_name='Event start time')),
- ('date_to', models.DateTimeField(verbose_name='Event end time', null=True, blank=True)),
- ('presale_end', models.DateTimeField(verbose_name='End of presale', help_text='No products will be sold after this date.', null=True, blank=True)),
- ('presale_start', models.DateTimeField(verbose_name='Start of presale', help_text='No products will be sold before this date.', null=True, blank=True)),
- ('plugins', models.TextField(verbose_name='Plugins', null=True, blank=True)),
+ ('date_to', models.DateTimeField(verbose_name='Event end time', blank=True, null=True)),
+ ('is_public', models.BooleanField(verbose_name='Visible in public lists', default=False, help_text="If selected, this event may show up on the ticket system's start page or an organization profile.")),
+ ('presale_end', models.DateTimeField(verbose_name='End of presale', help_text='No products will be sold after this date.', blank=True, null=True)),
+ ('presale_start', models.DateTimeField(verbose_name='Start of presale', help_text='No products will be sold before this date.', blank=True, null=True)),
+ ('plugins', models.TextField(verbose_name='Plugins', blank=True, null=True)),
],
options={
'verbose_name': 'Event',
@@ -108,7 +112,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='EventLock',
fields=[
- ('event', models.CharField(serialize=False, max_length=36, primary_key=True)),
+ ('event', models.CharField(max_length=36, primary_key=True, serialize=False)),
('date', models.DateTimeField(auto_now=True)),
('token', models.UUIDField(default=uuid.uuid4)),
],
@@ -116,18 +120,14 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='EventPermission',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
- ('can_change_settings', models.BooleanField(default=True, verbose_name='Can change event settings')),
- ('can_change_items', models.BooleanField(default=True, verbose_name='Can change product settings')),
- ('can_view_orders', models.BooleanField(default=True, verbose_name='Can view orders')),
- ('can_change_permissions', models.BooleanField(default=True, verbose_name='Can change permissions')),
- ('can_change_orders', models.BooleanField(default=True, verbose_name='Can change orders')),
- ('event', versions.models.VersionedForeignKey(to='pretixbase.Event')),
- ('user', models.ForeignKey(related_name='event_perms', to=settings.AUTH_USER_MODEL)),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
+ ('can_change_settings', models.BooleanField(verbose_name='Can change event settings', default=True)),
+ ('can_change_items', models.BooleanField(verbose_name='Can change product settings', default=True)),
+ ('can_view_orders', models.BooleanField(verbose_name='Can view orders', default=True)),
+ ('can_change_permissions', models.BooleanField(verbose_name='Can change permissions', default=True)),
+ ('can_change_orders', models.BooleanField(verbose_name='Can change orders', default=True)),
+ ('event', models.ForeignKey(to='pretixbase.Event', related_name='user_perms')),
+ ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_perms')),
],
options={
'verbose_name': 'Event permission',
@@ -137,35 +137,26 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='EventSetting',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('key', models.CharField(max_length=255)),
('value', models.TextField()),
- ('object', versions.models.VersionedForeignKey(related_name='setting_objects', to='pretixbase.Event')),
+ ('object', models.ForeignKey(to='pretixbase.Event', related_name='setting_objects')),
],
- options={
- 'abstract': False,
- },
),
migrations.CreateModel(
name='Item',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', pretix.base.i18n.I18nCharField(verbose_name='Item name', max_length=255)),
- ('active', models.BooleanField(default=True, verbose_name='Active')),
- ('description', pretix.base.i18n.I18nTextField(verbose_name='Description', help_text='This is shown below the product name in lists.', null=True, blank=True)),
- ('default_price', models.DecimalField(decimal_places=2, verbose_name='Default price', max_digits=7, null=True)),
- ('tax_rate', models.DecimalField(decimal_places=2, verbose_name='Taxes included in percent', max_digits=7, null=True, blank=True)),
- ('admission', models.BooleanField(default=False, verbose_name='Is an admission ticket', help_text='Whether or not buying this product allows a person to enter your event')),
+ ('active', models.BooleanField(verbose_name='Active', default=True)),
+ ('description', pretix.base.i18n.I18nTextField(verbose_name='Description', help_text='This is shown below the product name in lists.', blank=True, null=True)),
+ ('default_price', models.DecimalField(verbose_name='Default price', max_digits=7, decimal_places=2, null=True)),
+ ('tax_rate', models.DecimalField(verbose_name='Taxes included in percent', max_digits=7, blank=True, null=True, decimal_places=2)),
+ ('admission', models.BooleanField(verbose_name='Is an admission ticket', default=False, help_text='Whether or not buying this product allows a person to enter your event')),
('position', models.IntegerField(default=0)),
- ('picture', models.ImageField(upload_to=pretix.base.models.itempicture_upload_to, verbose_name='Product picture', null=True, blank=True)),
+ ('picture', models.ImageField(verbose_name='Product picture', blank=True, null=True, upload_to=pretix.base.models.items.itempicture_upload_to)),
+ ('available_from', models.DateTimeField(verbose_name='Available from', help_text='This product will not be sold before the given date.', blank=True, null=True)),
+ ('available_until', models.DateTimeField(verbose_name='Available until', help_text='This product will not be sold after the given date.', blank=True, null=True)),
],
options={
'verbose_name': 'Product',
@@ -176,32 +167,24 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='ItemCategory',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', pretix.base.i18n.I18nCharField(verbose_name='Category name', max_length=255)),
('position', models.IntegerField(default=0)),
- ('event', versions.models.VersionedForeignKey(related_name='categories', to='pretixbase.Event')),
+ ('event', models.ForeignKey(to='pretixbase.Event', related_name='categories')),
],
options={
'verbose_name': 'Product category',
'verbose_name_plural': 'Product categories',
- 'ordering': ('position', 'version_birth_date'),
+ 'ordering': ('position', 'id'),
},
),
migrations.CreateModel(
name='ItemVariation',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
- ('active', models.BooleanField(default=True, verbose_name='Active')),
- ('default_price', models.DecimalField(decimal_places=2, verbose_name='Default price', max_digits=7, null=True, blank=True)),
- ('item', versions.models.VersionedForeignKey(related_name='variations', to='pretixbase.Item')),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
+ ('active', models.BooleanField(verbose_name='Active', default=True)),
+ ('default_price', models.DecimalField(verbose_name='Default price', max_digits=7, blank=True, null=True, decimal_places=2)),
+ ('item', models.ForeignKey(to='pretixbase.Item', related_name='variations')),
],
options={
'verbose_name': 'Product variation',
@@ -211,25 +194,21 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Order',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('code', models.CharField(verbose_name='Order code', max_length=16)),
- ('status', models.CharField(verbose_name='Status', choices=[('n', 'pending'), ('p', 'paid'), ('e', 'expired'), ('c', 'cancelled'), ('r', 'refunded')], max_length=3)),
- ('email', models.EmailField(verbose_name='E-mail', null=True, max_length=254, blank=True)),
- ('locale', models.CharField(verbose_name='Locale', null=True, max_length=32, blank=True)),
- ('secret', models.CharField(default=pretix.base.models.generate_secret, max_length=32)),
+ ('status', models.CharField(verbose_name='Status', max_length=3, choices=[('n', 'pending'), ('p', 'paid'), ('e', 'expired'), ('c', 'cancelled'), ('r', 'refunded')])),
+ ('email', models.EmailField(verbose_name='E-mail', max_length=254, blank=True, null=True)),
+ ('locale', models.CharField(verbose_name='Locale', max_length=32, blank=True, null=True)),
+ ('secret', models.CharField(default=pretix.base.models.orders.generate_secret, max_length=32)),
('datetime', models.DateTimeField(verbose_name='Date')),
('expires', models.DateTimeField(verbose_name='Expiration date')),
- ('payment_date', models.DateTimeField(verbose_name='Payment date', null=True, blank=True)),
- ('payment_provider', models.CharField(verbose_name='Payment provider', null=True, max_length=255, blank=True)),
- ('payment_fee', models.DecimalField(decimal_places=2, default=0, verbose_name='Payment method fee', max_digits=10)),
- ('payment_info', models.TextField(verbose_name='Payment information', null=True, blank=True)),
- ('payment_manual', models.BooleanField(default=False, verbose_name='Payment state was manually modified')),
- ('total', models.DecimalField(decimal_places=2, verbose_name='Total amount', max_digits=10)),
- ('event', versions.models.VersionedForeignKey(verbose_name='Event', related_name='orders', to='pretixbase.Event')),
+ ('payment_date', models.DateTimeField(verbose_name='Payment date', blank=True, null=True)),
+ ('payment_provider', models.CharField(verbose_name='Payment provider', max_length=255, blank=True, null=True)),
+ ('payment_fee', models.DecimalField(verbose_name='Payment method fee', default=0, max_digits=10, decimal_places=2)),
+ ('payment_info', models.TextField(verbose_name='Payment information', blank=True, null=True)),
+ ('payment_manual', models.BooleanField(verbose_name='Payment state was manually modified', default=False)),
+ ('total', models.DecimalField(verbose_name='Total amount', max_digits=10, decimal_places=2)),
+ ('event', models.ForeignKey(to='pretixbase.Event', verbose_name='Event', related_name='orders')),
],
options={
'verbose_name': 'Order',
@@ -240,33 +219,25 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='OrderPosition',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
- ('price', models.DecimalField(decimal_places=2, verbose_name='Price', max_digits=10)),
- ('attendee_name', models.CharField(verbose_name='Attendee name', null=True, help_text='Empty, if this product is not an admission ticket', max_length=255, blank=True)),
- ('item', versions.models.VersionedForeignKey(verbose_name='Item', related_name='positions', to='pretixbase.Item')),
- ('order', versions.models.VersionedForeignKey(verbose_name='Order', related_name='positions', to='pretixbase.Order')),
- ('variation', versions.models.VersionedForeignKey(verbose_name='Variation', blank=True, null=True, to='pretixbase.ItemVariation')),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
+ ('price', models.DecimalField(verbose_name='Price', max_digits=10, decimal_places=2)),
+ ('attendee_name', models.CharField(verbose_name='Attendee name', max_length=255, blank=True, null=True, help_text='Empty, if this product is not an admission ticket')),
+ ('item', models.ForeignKey(to='pretixbase.Item', on_delete=django.db.models.deletion.PROTECT, verbose_name='Item', related_name='positions')),
+ ('order', models.ForeignKey(to='pretixbase.Order', on_delete=django.db.models.deletion.PROTECT, verbose_name='Order', related_name='positions')),
+ ('variation', models.ForeignKey(blank=True, to='pretixbase.ItemVariation', on_delete=django.db.models.deletion.PROTECT, verbose_name='Variation', null=True)),
],
options={
'verbose_name': 'Order position',
'verbose_name_plural': 'Order positions',
},
- bases=(pretix.base.models.ObjectWithAnswers, models.Model),
+ bases=(pretix.base.models.orders.ObjectWithAnswers, models.Model),
),
migrations.CreateModel(
name='Organizer',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', models.CharField(verbose_name='Name', max_length=200)),
- ('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9.-]+$', message='The slug may only contain letters, numbers, dots and dashes.')])),
+ ('slug', models.SlugField(verbose_name='Slug', validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')], help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.')),
],
options={
'verbose_name': 'Organizer',
@@ -277,14 +248,10 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='OrganizerPermission',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
- ('can_create_events', models.BooleanField(default=True, verbose_name='Can create events')),
- ('organizer', versions.models.VersionedForeignKey(to='pretixbase.Organizer')),
- ('user', models.ForeignKey(related_name='organizer_perms', to=settings.AUTH_USER_MODEL)),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
+ ('can_create_events', models.BooleanField(verbose_name='Can create events', default=True)),
+ ('organizer', models.ForeignKey(to='pretixbase.Organizer', related_name='user_perms')),
+ ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='organizer_perms')),
],
options={
'verbose_name': 'Organizer permission',
@@ -294,30 +261,19 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='OrganizerSetting',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('key', models.CharField(max_length=255)),
('value', models.TextField()),
- ('object', versions.models.VersionedForeignKey(related_name='setting_objects', to='pretixbase.Organizer')),
+ ('object', models.ForeignKey(to='pretixbase.Organizer', related_name='setting_objects')),
],
- options={
- 'abstract': False,
- },
),
migrations.CreateModel(
name='Property',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', pretix.base.i18n.I18nCharField(verbose_name='Property name', max_length=250)),
- ('event', versions.models.VersionedForeignKey(related_name='properties', to='pretixbase.Event')),
- ('item', versions.models.VersionedForeignKey(blank=True, related_name='properties', null=True, to='pretixbase.Item')),
+ ('event', models.ForeignKey(to='pretixbase.Event', related_name='properties')),
+ ('item', models.ForeignKey(blank=True, to='pretixbase.Item', null=True, related_name='properties')),
],
options={
'verbose_name': 'Product property',
@@ -327,34 +283,26 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='PropertyValue',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('value', pretix.base.i18n.I18nCharField(verbose_name='Value', max_length=250)),
('position', models.IntegerField(default=0)),
- ('prop', versions.models.VersionedForeignKey(related_name='values', to='pretixbase.Property')),
+ ('prop', models.ForeignKey(to='pretixbase.Property', related_name='values')),
],
options={
'verbose_name': 'Property value',
'verbose_name_plural': 'Property values',
- 'ordering': ('position', 'version_birth_date'),
+ 'ordering': ('position', 'id'),
},
),
migrations.CreateModel(
name='Question',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('question', pretix.base.i18n.I18nTextField(verbose_name='Question')),
- ('type', models.CharField(verbose_name='Question type', choices=[('N', 'Number'), ('S', 'Text (one line)'), ('T', 'Multiline text'), ('B', 'Yes/No')], max_length=5)),
- ('required', models.BooleanField(default=False, verbose_name='Required question')),
- ('event', versions.models.VersionedForeignKey(related_name='questions', to='pretixbase.Event')),
- ('items', versions.models.VersionedManyToManyField(to='pretixbase.Item', verbose_name='Products', help_text='This question will be asked to buyers of the selected products', related_name='questions', blank=True)),
+ ('type', models.CharField(verbose_name='Question type', max_length=5, choices=[('N', 'Number'), ('S', 'Text (one line)'), ('T', 'Multiline text'), ('B', 'Yes/No')])),
+ ('required', models.BooleanField(verbose_name='Required question', default=False)),
+ ('event', models.ForeignKey(to='pretixbase.Event', related_name='questions')),
+ ('items', models.ManyToManyField(verbose_name='Products', help_text='This question will be asked to buyers of the selected products', blank=True, to='pretixbase.Item', related_name='questions')),
],
options={
'verbose_name': 'Question',
@@ -364,33 +312,22 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='QuestionAnswer',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('answer', models.TextField()),
- ('cartposition', models.ForeignKey(blank=True, related_name='answers', null=True, to='pretixbase.CartPosition')),
- ('orderposition', models.ForeignKey(blank=True, related_name='answers', null=True, to='pretixbase.OrderPosition')),
- ('question', versions.models.VersionedForeignKey(related_name='answers', to='pretixbase.Question')),
+ ('cartposition', models.ForeignKey(blank=True, to='pretixbase.CartPosition', null=True, related_name='answers')),
+ ('orderposition', models.ForeignKey(blank=True, to='pretixbase.OrderPosition', null=True, related_name='answers')),
+ ('question', models.ForeignKey(to='pretixbase.Question', related_name='answers')),
],
- options={
- 'abstract': False,
- },
),
migrations.CreateModel(
name='Quota',
fields=[
- ('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
- ('identity', models.CharField(max_length=36)),
- ('version_start_date', models.DateTimeField()),
- ('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
- ('version_birth_date', models.DateTimeField()),
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', models.CharField(verbose_name='Name', max_length=200)),
- ('size', models.PositiveIntegerField(verbose_name='Total capacity')),
- ('event', versions.models.VersionedForeignKey(verbose_name='Event', related_name='quotas', to='pretixbase.Event')),
- ('items', versions.models.VersionedManyToManyField(to='pretixbase.Item', verbose_name='Item', related_name='quotas', blank=True)),
- ('variations', pretix.base.models.VariationsField(to='pretixbase.ItemVariation', verbose_name='Variations', related_name='quotas', blank=True)),
+ ('size', models.PositiveIntegerField(verbose_name='Total capacity', help_text='Leave empty for an unlimited number of tickets.', blank=True, null=True)),
+ ('event', models.ForeignKey(to='pretixbase.Event', verbose_name='Event', related_name='quotas')),
+ ('items', models.ManyToManyField(verbose_name='Item', to='pretixbase.Item', blank=True, related_name='quotas')),
+ ('variations', pretix.base.models.items.VariationsField(verbose_name='Variations', to='pretixbase.ItemVariation', blank=True, related_name='quotas')),
],
options={
'verbose_name': 'Quota',
@@ -400,51 +337,52 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='organizer',
name='permitted',
- field=models.ManyToManyField(related_name='organizers', to=settings.AUTH_USER_MODEL, through='pretixbase.OrganizerPermission'),
+ field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, through='pretixbase.OrganizerPermission', related_name='organizers'),
),
migrations.AddField(
model_name='itemvariation',
name='values',
- field=versions.models.VersionedManyToManyField(related_name='variations', to='pretixbase.PropertyValue'),
+ field=models.ForeignKey(to='pretixbase.PropertyValue', related_name='variations'),
),
migrations.AddField(
model_name='item',
name='category',
- field=versions.models.VersionedForeignKey(verbose_name='Category', blank=True, to='pretixbase.ItemCategory', related_name='items', null=True, on_delete=django.db.models.deletion.PROTECT),
+ field=models.ForeignKey(blank=True, to='pretixbase.ItemCategory', on_delete=django.db.models.deletion.PROTECT, verbose_name='Category', null=True, related_name='items'),
),
migrations.AddField(
model_name='item',
name='event',
- field=versions.models.VersionedForeignKey(verbose_name='Event', related_name='items', to='pretixbase.Event', on_delete=django.db.models.deletion.PROTECT),
+ field=models.ForeignKey(to='pretixbase.Event', on_delete=django.db.models.deletion.PROTECT, verbose_name='Event', related_name='items'),
),
migrations.AddField(
model_name='event',
name='organizer',
- field=versions.models.VersionedForeignKey(related_name='events', to='pretixbase.Organizer', on_delete=django.db.models.deletion.PROTECT),
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='pretixbase.Organizer', related_name='events'),
),
migrations.AddField(
model_name='event',
name='permitted',
- field=models.ManyToManyField(related_name='events', to=settings.AUTH_USER_MODEL, through='pretixbase.EventPermission'),
+ field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, through='pretixbase.EventPermission', related_name='events'),
),
migrations.AddField(
model_name='cartposition',
name='event',
- field=versions.models.VersionedForeignKey(verbose_name='Event', to='pretixbase.Event'),
+ field=models.ForeignKey(verbose_name='Event', to='pretixbase.Event'),
),
migrations.AddField(
model_name='cartposition',
name='item',
- field=versions.models.VersionedForeignKey(verbose_name='Item', to='pretixbase.Item'),
+ field=models.ForeignKey(verbose_name='Item', to='pretixbase.Item'),
),
migrations.AddField(
model_name='cartposition',
name='variation',
- field=versions.models.VersionedForeignKey(verbose_name='Variation', blank=True, null=True, to='pretixbase.ItemVariation'),
+ field=models.ForeignKey(blank=True, to='pretixbase.ItemVariation', verbose_name='Variation', null=True),
),
migrations.AddField(
model_name='cachedticket',
name='order',
- field=versions.models.VersionedForeignKey(to='pretixbase.Order'),
+ field=models.ForeignKey(to='pretixbase.Order'),
),
+ migrations.RunPython(initial_user),
]
diff --git a/src/pretix/base/migrations/0002_auto_20151021_1412.py b/src/pretix/base/migrations/0002_auto_20151021_1412.py
deleted file mode 100644
index 69380c7e0f..0000000000
--- a/src/pretix/base/migrations/0002_auto_20151021_1412.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('pretixbase', '0001_initial'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='quota',
- name='size',
- field=models.PositiveIntegerField(help_text='Leave empty for an unlimited number of tickets.', verbose_name='Total capacity', blank=True, null=True),
- ),
- ]
diff --git a/src/pretix/base/migrations/0002_auto_20151212_1123.py b/src/pretix/base/migrations/0002_auto_20151212_1123.py
new file mode 100644
index 0000000000..45708bd5cf
--- /dev/null
+++ b/src/pretix/base/migrations/0002_auto_20151212_1123.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('pretixbase', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='itemvariation',
+ name='values',
+ ),
+ migrations.AddField(
+ model_name='itemvariation',
+ name='values',
+ field=models.ManyToManyField(related_name='variations', to='pretixbase.PropertyValue'),
+ ),
+ ]
diff --git a/src/pretix/base/migrations/0003_event_is_public.py b/src/pretix/base/migrations/0003_event_is_public.py
deleted file mode 100644
index 3383f86723..0000000000
--- a/src/pretix/base/migrations/0003_event_is_public.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('pretixbase', '0002_auto_20151021_1412'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='event',
- name='is_public',
- field=models.BooleanField(help_text="If selected, this event may show up on the ticket system's start page or an organization profile.", default=False, verbose_name='Visible in public lists'),
- ),
- ]
diff --git a/src/pretix/base/migrations/0004_auto_20151024_0848.py b/src/pretix/base/migrations/0004_auto_20151024_0848.py
deleted file mode 100644
index 50d566d44b..0000000000
--- a/src/pretix/base/migrations/0004_auto_20151024_0848.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('pretixbase', '0003_event_is_public'),
- ]
-
- operations = [
- migrations.RenameField(
- model_name='cartposition',
- old_name='session',
- new_name='cart_id'
- ),
- migrations.AlterField(
- model_name='cartposition',
- name='cart_id',
- field=models.CharField(blank=True, verbose_name='Cart ID (e.g. session key)', max_length=255, null=True),
- ),
- ]
diff --git a/src/pretix/base/migrations/0005_auto_20151206_1652.py b/src/pretix/base/migrations/0005_auto_20151206_1652.py
deleted file mode 100644
index 9992623452..0000000000
--- a/src/pretix/base/migrations/0005_auto_20151206_1652.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('pretixbase', '0004_auto_20151024_0848'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='item',
- name='available_from',
- field=models.DateTimeField(null=True, help_text='This product will not be sold before the given date.', blank=True, verbose_name='Available from'),
- ),
- migrations.AddField(
- model_name='item',
- name='available_until',
- field=models.DateTimeField(null=True, help_text='This product will not be sold after the given date.', blank=True, verbose_name='Available to'),
- ),
- ]
diff --git a/src/pretix/base/models/__init__.py b/src/pretix/base/models/__init__.py
index b9fedaa166..de32244020 100644
--- a/src/pretix/base/models/__init__.py
+++ b/src/pretix/base/models/__init__.py
@@ -1,5 +1,5 @@
from .auth import User
-from .base import CachedFile, Versionable, cachedfile_name
+from .base import CachedFile, cachedfile_name
from .event import Event, EventLock, EventPermission, EventSetting
from .items import (
Item, ItemCategory, ItemVariation, Property, PropertyValue, Question,
@@ -12,7 +12,7 @@ from .orders import (
from .organizer import Organizer, OrganizerPermission, OrganizerSetting
__all__ = [
- 'Versionable', 'User', 'CachedFile', 'Organizer', 'OrganizerPermission', 'Event', 'EventPermission',
+ 'User', 'CachedFile', 'Organizer', 'OrganizerPermission', 'Event', 'EventPermission',
'ItemCategory', 'Item', 'Property', 'PropertyValue', 'ItemVariation', 'VariationsField', 'Question',
'Quota', 'Order', 'CachedTicket', 'QuestionAnswer', 'ObjectWithAnswers', 'OrderPosition',
'CartPosition', 'EventSetting', 'OrganizerSetting', 'EventLock', 'cachedfile_name', 'itempicture_upload_to',
diff --git a/src/pretix/base/models/base.py b/src/pretix/base/models/base.py
index 9dfc0fd4ef..3d822a2f91 100644
--- a/src/pretix/base/models/base.py
+++ b/src/pretix/base/models/base.py
@@ -1,71 +1,12 @@
-import copy
import uuid
-from datetime import datetime
-import six
from django.db import models
from django.db.models.signals import post_delete
from django.dispatch import receiver
-from versions.models import Versionable as BaseVersionable, get_utc_now
-
-
-class Versionable(BaseVersionable):
- class Meta:
- abstract = True
-
- def clone_shallow(self, forced_version_date: datetime=None):
- """
- This behaves like clone(), but misses all the Many2Many-relation-handling. This is
- a performance optimization for cases in which we have to handle the Many2Many relations
- by hand anyways.
- """
- if not self.pk: # NOQA
- raise ValueError('Instance must be saved before it can be cloned')
-
- if self.version_end_date: # NOQA
- raise ValueError('This is a historical item and can not be cloned.')
-
- if forced_version_date: # NOQA
- if not self.version_start_date <= forced_version_date <= get_utc_now():
- raise ValueError('The clone date must be between the version start date and now.')
- else:
- forced_version_date = get_utc_now()
-
- earlier_version = self
-
- later_version = copy.copy(earlier_version)
- later_version.version_end_date = None
- later_version.version_start_date = forced_version_date
-
- # set earlier_version's ID to a new UUID so the clone (later_version) can
- # get the old one -- this allows 'head' to always have the original
- # id allowing us to get at all historic foreign key relationships
- earlier_version.id = six.u(str(uuid.uuid4()))
- earlier_version.version_end_date = forced_version_date
- earlier_version.save()
-
- for field in earlier_version._meta.many_to_many:
- earlier_version.clone_relations_shallow(later_version, field.attname, forced_version_date)
-
- if hasattr(earlier_version._meta, 'many_to_many_related'):
- for rel in earlier_version._meta.many_to_many_related:
- earlier_version.clone_relations_shallow(later_version, rel.via_field_name, forced_version_date)
-
- later_version.save()
-
- return later_version
-
- def clone_relations_shallow(self, clone, manager_field_name, forced_version_date):
- # Source: the original object, where relations are currently pointing to
- source = getattr(self, manager_field_name) # returns a VersionedRelatedManager instance
- # Destination: the clone, where the cloned relations should point to
- source.through.objects.filter(**{source.source_field.attname: clone.id}).update(**{
- source.source_field.attname: self.id, 'version_end_date': forced_version_date
- })
def cachedfile_name(instance, filename: str) -> str:
- return 'cachedfiles/%s.%s' % (instance.id, filename.split('.')[-1])
+ return 'cachedfiles/%012d.%s' % (instance.id, filename.split('.')[-1])
class CachedFile(models.Model):
diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py
index d9069835f9..248ae8ed0b 100644
--- a/src/pretix/base/models/event.py
+++ b/src/pretix/base/models/event.py
@@ -9,17 +9,15 @@ from django.template.defaultfilters import date as _date
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
-from versions.models import VersionedForeignKey
from pretix.base.i18n import I18nCharField
from pretix.base.settings import SettingsProxy
from .auth import User
-from .base import Versionable
from .organizer import Organizer
-class Event(Versionable):
+class Event(models.Model):
"""
This model represents an event. An event is anything you can buy
tickets for.
@@ -46,8 +44,7 @@ class Event(Versionable):
:type plugins: str
"""
- organizer = VersionedForeignKey(Organizer, related_name="events",
- on_delete=models.PROTECT)
+ organizer = models.ForeignKey(Organizer, related_name="events", on_delete=models.PROTECT)
name = I18nCharField(
max_length=200,
verbose_name=_("Name"),
@@ -184,7 +181,7 @@ class Event(Versionable):
return locking.LockManager(self)
-class EventPermission(Versionable):
+class EventPermission(models.Model):
"""
The relation between an Event and an User who has permissions to
access an event.
@@ -203,8 +200,8 @@ class EventPermission(Versionable):
:type can_change_orders: bool
"""
- event = VersionedForeignKey(Event)
- user = models.ForeignKey(User, related_name="event_perms")
+ event = models.ForeignKey(Event, related_name="user_perms", on_delete=models.CASCADE)
+ user = models.ForeignKey(User, related_name="event_perms", on_delete=models.CASCADE)
can_change_settings = models.BooleanField(
default=True,
verbose_name=_("Can change event settings")
@@ -237,12 +234,12 @@ class EventPermission(Versionable):
}
-class EventSetting(Versionable):
+class EventSetting(models.Model):
"""
An event settings is a key-value setting which can be set for a
specific event
"""
- object = VersionedForeignKey(Event, related_name='setting_objects')
+ object = models.ForeignKey(Event, related_name='setting_objects', on_delete=models.CASCADE)
key = models.CharField(max_length=255)
value = models.TextField()
diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py
index ec707375a5..9a9b4835a0 100644
--- a/src/pretix/base/models/items.py
+++ b/src/pretix/base/models/items.py
@@ -8,16 +8,14 @@ from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from typing import List, Tuple
-from versions.models import VersionedForeignKey, VersionedManyToManyField
from pretix.base.i18n import I18nCharField, I18nTextField
from ..types import VariationDict
-from .base import Versionable
from .event import Event
-class ItemCategory(Versionable):
+class ItemCategory(models.Model):
"""
Items can be sorted into these categories.
@@ -28,7 +26,7 @@ class ItemCategory(Versionable):
:param position: An integer, used for sorting
:type position: int
"""
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
on_delete=models.CASCADE,
related_name='categories',
@@ -44,7 +42,7 @@ class ItemCategory(Versionable):
class Meta:
verbose_name = _("Product category")
verbose_name_plural = _("Product categories")
- ordering = ('position', 'version_birth_date')
+ ordering = ('position', 'id')
def __str__(self):
return str(self.name)
@@ -61,7 +59,7 @@ class ItemCategory(Versionable):
@property
def sortkey(self):
- return self.position, self.version_birth_date
+ return self.position, self.id
def __lt__(self, other) -> bool:
return self.sortkey < other.sortkey
@@ -69,12 +67,12 @@ class ItemCategory(Versionable):
def itempicture_upload_to(instance, filename: str) -> str:
return '%s/%s/item-%s.%s' % (
- instance.event.organizer.slug, instance.event.slug, instance.identity,
+ instance.event.organizer.slug, instance.event.slug, instance.id,
filename.split('.')[-1]
)
-class Item(Versionable):
+class Item(models.Model):
"""
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
Items are often also called 'products' but are named 'items' internally due to historic reasons.
@@ -104,13 +102,13 @@ class Item(Versionable):
"""
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
on_delete=models.PROTECT,
related_name="items",
verbose_name=_("Event"),
)
- category = VersionedForeignKey(
+ category = models.ForeignKey(
ItemCategory,
on_delete=models.PROTECT,
related_name="items",
@@ -222,7 +220,7 @@ class Item(Versionable):
for var in all_variations:
key = []
for v in var.values.all():
- key.append((v.prop_id, v.identity))
+ key.append((v.prop_id, v.id))
key = tuple(sorted(key))
variations_cache[key] = var
@@ -234,8 +232,8 @@ class Item(Versionable):
key = []
var = VariationDict()
for v in comb:
- key.append((v.prop.identity, v.identity))
- var[v.prop.identity] = v
+ key.append((v.prop.id, v.id))
+ var[v.prop.id] = v
key = tuple(sorted(key))
if key in variations_cache:
var['variation'] = variations_cache[key]
@@ -245,7 +243,7 @@ class Item(Versionable):
return result
def _get_all_generated_variations(self):
- propids = set([p.identity for p in self.properties.all()])
+ propids = set([p.id for p in self.properties.all()])
if len(propids) == 0:
variations = [VariationDict()]
else:
@@ -261,11 +259,11 @@ class Item(Versionable):
values = list(var.values.all())
# Make sure we don't expose stale ItemVariation objects which are
# still around altough they have an old set of properties
- if set([v.prop.identity for v in values]) != propids:
+ if set([v.prop.id for v in values]) != propids:
continue
vardict = VariationDict()
for v in values:
- vardict[v.prop.identity] = v
+ vardict[v.prop.id] = v
vardict['variation'] = var
variations.append(vardict)
return variations
@@ -325,7 +323,7 @@ class Item(Versionable):
key=lambda s: (s[0], s[1] if s[1] is not None else sys.maxsize))
-class Property(Versionable):
+class Property(models.Model):
"""
A property is a modifier which can be applied to an Item. For example
'Size' would be a property associated with the item 'T-Shirt'.
@@ -336,11 +334,11 @@ class Property(Versionable):
:type name: str
"""
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
related_name="properties"
)
- item = VersionedForeignKey(
+ item = models.ForeignKey(
Item, related_name='properties', null=True, blank=True
)
name = I18nCharField(
@@ -366,7 +364,7 @@ class Property(Versionable):
self.event.get_cache().clear()
-class PropertyValue(Versionable):
+class PropertyValue(models.Model):
"""
A value of a property. If the property would be 'T-Shirt size',
this could be 'M' or 'L'.
@@ -379,7 +377,7 @@ class PropertyValue(Versionable):
:type position: int
"""
- prop = VersionedForeignKey(
+ prop = models.ForeignKey(
Property,
on_delete=models.CASCADE,
related_name="values"
@@ -395,7 +393,7 @@ class PropertyValue(Versionable):
class Meta:
verbose_name = _("Property value")
verbose_name_plural = _("Property values")
- ordering = ("position", "version_birth_date")
+ ordering = ("position", "id")
def __str__(self):
return "%s: %s" % (self.prop.name, self.value)
@@ -412,13 +410,13 @@ class PropertyValue(Versionable):
@property
def sortkey(self) -> Tuple[int, datetime]:
- return self.position, self.version_birth_date
+ return self.position, self.id
def __lt__(self, other) -> bool:
return self.sortkey < other.sortkey
-class ItemVariation(Versionable):
+class ItemVariation(models.Model):
"""
A variation is an item combined with values for all properties
associated with the item. For example, if your item is 'T-Shirt'
@@ -444,11 +442,11 @@ class ItemVariation(Versionable):
:param default_price: This variation's default price
:type default_price: decimal.Decimal
"""
- item = VersionedForeignKey(
+ item = models.ForeignKey(
Item,
related_name='variations'
)
- values = VersionedManyToManyField(
+ values = models.ManyToManyField(
PropertyValue,
related_name='variations',
)
@@ -495,7 +493,7 @@ class ItemVariation(Versionable):
"""
vd = VariationDict()
for v in self.values.all():
- vd[v.prop.identity] = v
+ vd[v.prop.id] = v
vd['variation'] = self
return vd
@@ -507,14 +505,14 @@ class ItemVariation(Versionable):
for pair in pk.split(","):
prop, value = pair.split(":")
self.values.add(
- PropertyValue.objects.current.get(
- identity=value,
+ PropertyValue.objects.get(
+ id=value,
prop_id=prop
)
)
-class VariationsField(VersionedManyToManyField):
+class VariationsField(models.ManyToManyField):
"""
This is a ManyToManyField using the pretixcontrol.views.forms.VariationsField
form field by default.
@@ -536,12 +534,12 @@ class VariationsField(VersionedManyToManyField):
initial = defaults['initial']
if callable(initial):
initial = initial()
- defaults['initial'] = [i.identity for i in initial]
+ defaults['initial'] = [i.id for i in initial]
# Skip ManyToManyField in dependency chain
return super(RelatedField, self).formfield(**defaults)
-class Question(Versionable):
+class Question(models.Model):
"""
A question is an input field that can be used to extend a ticket
by custom information, e.g. "Attendee age". A question can allow one o several
@@ -573,7 +571,7 @@ class Question(Versionable):
(TYPE_BOOLEAN, _("Yes/No")),
)
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
related_name="questions"
)
@@ -589,7 +587,7 @@ class Question(Versionable):
default=False,
verbose_name=_("Required question")
)
- items = VersionedManyToManyField(
+ items = models.ManyToManyField(
Item,
related_name='questions',
verbose_name=_("Products"),
@@ -615,7 +613,7 @@ class Question(Versionable):
self.event.get_cache().clear()
-class Quota(Versionable):
+class Quota(models.Model):
"""
A quota is a "pool of tickets". It is there to limit the number of items
of a certain type to be sold. For example, you could have a quota of 500
@@ -666,7 +664,7 @@ class Quota(Versionable):
AVAILABILITY_RESERVED = 20
AVAILABILITY_OK = 100
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
on_delete=models.CASCADE,
related_name="quotas",
@@ -681,7 +679,7 @@ class Quota(Versionable):
null=True, blank=True,
help_text=_("Leave empty for an unlimited number of tickets.")
)
- items = VersionedManyToManyField(
+ items = models.ManyToManyField(
Item,
verbose_name=_("Item"),
related_name="quotas",
@@ -745,7 +743,7 @@ class Quota(Versionable):
def count_in_cart(self) -> int:
from pretix.base.models import CartPosition
- return CartPosition.objects.current.filter(
+ return CartPosition.objects.filter(
Q(expires__gte=now())
& self._position_lookup
).count()
@@ -753,7 +751,7 @@ class Quota(Versionable):
def count_orders(self) -> dict:
from pretix.base.models import Order, OrderPosition
- o = OrderPosition.objects.current.filter(self._position_lookup).aggregate(
+ o = OrderPosition.objects.filter(self._position_lookup).aggregate(
paid=Sum(
Case(When(order__status=Order.STATUS_PAID, then=1),
output_field=models.IntegerField())
diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py
index b9ff5c5030..bb017e57b1 100644
--- a/src/pretix/base/models/orders.py
+++ b/src/pretix/base/models/orders.py
@@ -6,9 +6,8 @@ from django.db import models
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from typing import List, Union
-from versions.models import VersionedForeignKey
-from .base import CachedFile, Versionable
+from .base import CachedFile
from .event import Event
from .items import Item, ItemVariation, Question, Quota
@@ -17,7 +16,7 @@ def generate_secret():
return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16))
-class Order(Versionable):
+class Order(models.Model):
"""
An order is created when a user clicks 'buy' on his cart. It holds
several OrderPositions and is connected to an user. It has an
@@ -83,7 +82,7 @@ class Order(Versionable):
choices=STATUS_CHOICE,
verbose_name=_("Status")
)
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
verbose_name=_("Event"),
related_name="orders"
@@ -180,13 +179,11 @@ class Order(Versionable):
def mark_refunded(self):
"""
- Mark this order as refunded. This clones the order object, sets the payment status and
- returns the cloned order object.
+ Mark this order as refunded. This sets the payment status and returns the order object.
"""
- order = self.clone()
- order.status = Order.STATUS_REFUNDED
- order.save()
- return order
+ self.status = Order.STATUS_REFUNDED
+ self.save()
+ return self
def _can_be_paid(self) -> Union[bool, str]:
error_messages = {
@@ -223,12 +220,12 @@ class Order(Versionable):
for quota in quotas:
# Lock the quota, so no other thread is allowed to perform sales covered by this
# quota while we're doing so.
- if quota.identity not in quota_cache:
- quota_cache[quota.identity] = quota
+ if quota.id not in quota_cache:
+ quota_cache[quota.id] = quota
quota.cached_availability = quota.availability()[1]
else:
# Use cached version
- quota = quota_cache[quota.identity]
+ quota = quota_cache[quota.id]
if quota.cached_availability is not None:
quota.cached_availability -= 1
if quota.cached_availability < 0:
@@ -240,12 +237,12 @@ class Order(Versionable):
class CachedTicket(models.Model):
- order = VersionedForeignKey(Order, on_delete=models.CASCADE)
+ order = models.ForeignKey(Order, on_delete=models.CASCADE)
cachedfile = models.ForeignKey(CachedFile, on_delete=models.CASCADE)
provider = models.CharField(max_length=255)
-class QuestionAnswer(Versionable):
+class QuestionAnswer(models.Model):
"""
The answer to a Question, connected to an OrderPosition or CartPosition.
@@ -268,7 +265,7 @@ class QuestionAnswer(Versionable):
'CartPosition', null=True, blank=True,
related_name='answers'
)
- question = VersionedForeignKey(
+ question = models.ForeignKey(
Question, related_name='answers'
)
answer = models.TextField()
@@ -286,14 +283,14 @@ class ObjectWithAnswers:
self.answ[a.question_id] = a.answer
self.questions = []
for q in self.item.questions.all():
- if q.identity in self.answ:
- q.answer = self.answ[q.identity]
+ if q.id in self.answ:
+ q.answer = self.answ[q.id]
else:
q.answer = ""
self.questions.append(q)
-class OrderPosition(ObjectWithAnswers, Versionable):
+class OrderPosition(ObjectWithAnswers, models.Model):
"""
An OrderPosition is one line of an order, representing one ordered items
of a specified type (or variation).
@@ -309,20 +306,23 @@ class OrderPosition(ObjectWithAnswers, Versionable):
:param attendee_name: The attendee's name, if entered.
:type attendee_name: str
"""
- order = VersionedForeignKey(
+ order = models.ForeignKey(
Order,
verbose_name=_("Order"),
- related_name='positions'
+ related_name='positions',
+ on_delete=models.PROTECT
)
- item = VersionedForeignKey(
+ item = models.ForeignKey(
Item,
verbose_name=_("Item"),
- related_name='positions'
+ related_name='positions',
+ on_delete=models.PROTECT
)
- variation = VersionedForeignKey(
+ variation = models.ForeignKey(
ItemVariation,
null=True, blank=True,
- verbose_name=_("Variation")
+ verbose_name=_("Variation"),
+ on_delete=models.PROTECT
)
price = models.DecimalField(
decimal_places=2, max_digits=10,
@@ -347,17 +347,16 @@ class OrderPosition(ObjectWithAnswers, Versionable):
order=order, item=cartpos.item, variation=cartpos.variation,
price=cartpos.price, attendee_name=cartpos.attendee_name
)
+ op.save()
for answ in cartpos.answers.all():
- answ = answ.clone()
answ.orderposition = op
answ.cartposition = None
answ.save()
- op.save()
cartpos.delete()
ops.append(op)
-class CartPosition(ObjectWithAnswers, Versionable):
+class CartPosition(ObjectWithAnswers, models.Model):
"""
A cart position is similar to a order line, except that it is not
yet part of a binding order but just placed by some user in his or
@@ -383,7 +382,7 @@ class CartPosition(ObjectWithAnswers, Versionable):
:param attendee_name: The attendee's name, if entered.
:type attendee_name: str
"""
- event = VersionedForeignKey(
+ event = models.ForeignKey(
Event,
verbose_name=_("Event")
)
@@ -391,14 +390,16 @@ class CartPosition(ObjectWithAnswers, Versionable):
max_length=255, null=True, blank=True,
verbose_name=_("Cart ID (e.g. session key)")
)
- item = VersionedForeignKey(
+ item = models.ForeignKey(
Item,
- verbose_name=_("Item")
+ verbose_name=_("Item"),
+ on_delete=models.CASCADE
)
- variation = VersionedForeignKey(
+ variation = models.ForeignKey(
ItemVariation,
null=True, blank=True,
- verbose_name=_("Variation")
+ verbose_name=_("Variation"),
+ on_delete=models.CASCADE
)
price = models.DecimalField(
decimal_places=2, max_digits=10,
@@ -421,3 +422,8 @@ class CartPosition(ObjectWithAnswers, Versionable):
class Meta:
verbose_name = _("Cart position")
verbose_name_plural = _("Cart positions")
+
+ def __str__(self):
+ return '' % (
+ self.item.id, self.variation.id if self.variation else 0, self.cart_id
+ )
diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py
index e038093cb2..3cb7433cbe 100644
--- a/src/pretix/base/models/organizer.py
+++ b/src/pretix/base/models/organizer.py
@@ -2,15 +2,13 @@ from django.core.validators import RegexValidator
from django.db import models
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
-from versions.models import VersionedForeignKey
from pretix.base.settings import SettingsProxy
from .auth import User
-from .base import Versionable
-class Organizer(Versionable):
+class Organizer(models.Model):
"""
This model represents an entity organizing events, e.g. a company, institution,
charity, person, …
@@ -72,7 +70,7 @@ class Organizer(Versionable):
return ObjectRelatedCache(self)
-class OrganizerPermission(Versionable):
+class OrganizerPermission(models.Model):
"""
The relation between an Organizer and an User who has permissions to
access an organizer profile.
@@ -86,7 +84,7 @@ class OrganizerPermission(Versionable):
:type can_create_events: bool
"""
- organizer = VersionedForeignKey(Organizer)
+ organizer = models.ForeignKey(Organizer, related_name="user_perms", on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name="organizer_perms")
can_create_events = models.BooleanField(
default=True,
@@ -104,11 +102,11 @@ class OrganizerPermission(Versionable):
}
-class OrganizerSetting(Versionable):
+class OrganizerSetting(models.Model):
"""
An event option is a key-value setting which can be set for an
organizer. It will be inherited by the events of this organizer
"""
- object = VersionedForeignKey(Organizer, related_name='setting_objects')
+ object = models.ForeignKey(Organizer, related_name='setting_objects', on_delete=models.CASCADE)
key = models.CharField(max_length=255)
value = models.TextField()
diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py
index 42af2f0a8e..d94d6eee71 100644
--- a/src/pretix/base/payment.py
+++ b/src/pretix/base/payment.py
@@ -258,9 +258,7 @@ class BasePaymentProvider:
If the payment is completed, you should call ``pretix.base.services.orders.mark_order_paid(order, provider, info)``
with ``provider`` being your :py:attr:`identifier` and ``info`` being any string
- you might want to store for later usage. Please note, that if you want to store
- something inside ``order.payment_info``, please do it after the ``mark_order_paid`` call,
- as this call does a object clone for you. Please also note that ``mark_order_paid`` might
+ you might want to store for later usage. Please note that ``mark_order_paid`` might
raise a ``Quota.QuotaExceededException`` if (and only if) the payment term of this
order is over and some of the items are sold out. You should use the exception message
to display a meaningful error to the user.
@@ -403,7 +401,7 @@ class FreeOrderProvider(BasePaymentProvider):
pass
def payment_is_valid_session(self, request: HttpRequest) -> bool:
- return CartPosition.objects.current.filter(
+ return CartPosition.objects.filter(
Q(cart_id=request.session.session_key) & Q(event=request.event)
).aggregate(sum=Sum('price'))['sum'] == 0
@@ -446,7 +444,7 @@ class FreeOrderProvider(BasePaymentProvider):
messages.success(request, _('The order has been marked as refunded.'))
def is_allowed(self, request: HttpRequest) -> bool:
- return CartPosition.objects.current.filter(
+ return CartPosition.objects.filter(
cart_id=request.session.session_key, event=request.event
).aggregate(sum=Sum('price'))['sum'] == 0
diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py
index 5c059ba476..4908597ea1 100644
--- a/src/pretix/base/services/cart.py
+++ b/src/pretix/base/services/cart.py
@@ -35,7 +35,7 @@ def _extend_existing(event: Event, cart_id: str, expiry: datetime) -> None:
# Extend this user's cart session to 30 minutes from now to ensure all items in the
# cart expire at the same time
# We can extend the reservation of items which are not yet expired without risk
- CartPosition.objects.current.filter(
+ CartPosition.objects.filter(
Q(cart_id=cart_id) & Q(event=event) & Q(expires__gt=now())
).update(expires=expiry)
@@ -44,7 +44,7 @@ def _re_add_expired_positions(items: List[CartPosition], event: Event, cart_id:
positions = set()
# For items that are already expired, we have to delete and re-add them, as they might
# be no longer available or prices might have changed. Sorry!
- expired = CartPosition.objects.current.filter(
+ expired = CartPosition.objects.filter(
Q(cart_id=cart_id) & Q(event=event) & Q(expires__lte=now())
)
for cp in expired:
@@ -55,7 +55,7 @@ def _re_add_expired_positions(items: List[CartPosition], event: Event, cart_id:
def _delete_expired(expired: List[CartPosition]) -> None:
for cp in expired:
- if cp.version_end_date is None:
+ if cp.expires <= now():
cp.delete()
@@ -66,19 +66,19 @@ def _check_date(event: Event) -> None:
raise CartError(error_messages['ended'])
-def _add_new_items(event: Event, items: List[Tuple[str, Optional[str], int]],
+def _add_new_items(event: Event, items: List[Tuple[int, Optional[int], int]],
cart_id: str, expiry: datetime) -> Optional[str]:
err = None
# Fetch items from the database
- items_query = Item.objects.current.filter(event=event, identity__in=[i[0] for i in items]).prefetch_related(
+ items_query = Item.objects.filter(event=event, id__in=[i[0] for i in items]).prefetch_related(
"quotas")
- items_cache = {i.identity: i for i in items_query}
- variations_query = ItemVariation.objects.current.filter(
+ items_cache = {i.id: i for i in items_query}
+ variations_query = ItemVariation.objects.filter(
item__event=event,
- identity__in=[i[1] for i in items if i[1] is not None]
+ id__in=[i[1] for i in items if i[1] is not None]
).select_related("item", "item__event").prefetch_related("quotas", "values", "values__prop")
- variations_cache = {v.identity: v for v in variations_query}
+ variations_cache = {v.id: v for v in variations_query}
for i in items:
# Check whether the specified items are part of what we just fetched from the database
@@ -115,7 +115,7 @@ def _add_new_items(event: Event, items: List[Tuple[str, Optional[str], int]],
for k in range(quota_ok):
if len(i) > 3 and i[2] == 1:
# Recreating
- cp = i[3].clone()
+ cp = i[3]
cp.expires = expiry
cp.price = item.default_price if variation is None else (
variation.default_price if variation.default_price is not None else item.default_price)
@@ -131,10 +131,10 @@ def _add_new_items(event: Event, items: List[Tuple[str, Optional[str], int]],
return err
-def _add_items_to_cart(event: Event, items: List[Tuple[str, Optional[str], int]], cart_id: str=None) -> None:
+def _add_items_to_cart(event: Event, items: List[Tuple[int, Optional[int], int]], cart_id: str=None) -> None:
with event.lock():
_check_date(event)
- existing = CartPosition.objects.current.filter(Q(cart_id=cart_id) & Q(event=event)).count()
+ existing = CartPosition.objects.filter(Q(cart_id=cart_id) & Q(event=event)).count()
if sum(i[2] for i in items) + existing > int(event.settings.max_items_per_order):
# TODO: i18n plurals
raise CartError(error_messages['max_items'] % event.settings.max_items_per_order)
@@ -152,7 +152,7 @@ def _add_items_to_cart(event: Event, items: List[Tuple[str, Optional[str], int]]
raise CartError(err)
-def add_items_to_cart(event: str, items: List[Tuple[str, Optional[str], int]], cart_id: str=None) -> None:
+def add_items_to_cart(event: int, items: List[Tuple[int, Optional[int], int]], cart_id: str=None) -> None:
"""
Adds a list of items to a user's cart.
:param event: The event ID in question
@@ -160,21 +160,21 @@ def add_items_to_cart(event: str, items: List[Tuple[str, Optional[str], int]], c
:param session: Session ID of a guest
:raises CartError: On any error that occured
"""
- event = Event.objects.current.get(identity=event)
+ event = Event.objects.get(id=event)
try:
_add_items_to_cart(event, items, cart_id)
except EventLock.LockTimeoutException:
raise CartError(error_messages['busy'])
-def remove_items_from_cart(event: str, items: List[Tuple[str, Optional[str], int]], cart_id: str=None) -> None:
+def remove_items_from_cart(event: int, items: List[Tuple[int, Optional[int], int]], cart_id: int=None) -> None:
"""
Removes a list of items from a user's cart.
:param event: The event ID in question
:param items: A list of tuple of the form (item id, variation id or None, number)
:param session: Session ID of a guest
"""
- event = Event.objects.current.get(identity=event)
+ event = Event.objects.get(id=event)
for item, variation, cnt in items:
cw = Q(cart_id=cart_id) & Q(item_id=item) & Q(event=event)
@@ -182,7 +182,7 @@ def remove_items_from_cart(event: str, items: List[Tuple[str, Optional[str], int
cw &= Q(variation_id=variation)
else:
cw &= Q(variation__isnull=True)
- for cp in CartPosition.objects.current.filter(cw).order_by("-price")[:cnt]:
+ for cp in CartPosition.objects.filter(cw).order_by("-price")[:cnt]:
cp.delete()
@@ -190,8 +190,8 @@ if settings.HAS_CELERY:
from pretix.celery import app
@app.task(bind=True, max_retries=5, default_retry_delay=2)
- def add_items_to_cart_task(self, event: str, items: List[Tuple[str, Optional[str], int]], cart_id: str):
- event = Event.objects.current.get(identity=event)
+ def add_items_to_cart_task(self, event: int, items: List[Tuple[int, Optional[int], int]], cart_id: str):
+ event = Event.objects.get(id=event)
try:
_add_items_to_cart(event, items, cart_id)
except EventLock.LockTimeoutException:
diff --git a/src/pretix/base/services/export.py b/src/pretix/base/services/export.py
index cd846c410d..bcb8e661bc 100644
--- a/src/pretix/base/services/export.py
+++ b/src/pretix/base/services/export.py
@@ -7,7 +7,7 @@ from pretix.base.signals import register_data_exporters
def export(event: str, fileid: str, provider: str, form_data: Dict[str, Any]) -> None:
- event = Event.objects.current.get(identity=event)
+ event = Event.objects.get(id=event)
file = CachedFile.objects.get(id=fileid)
responses = register_data_exporters.send(event)
for receiver, response in responses:
diff --git a/src/pretix/base/services/locking.py b/src/pretix/base/services/locking.py
index bdc8c5a0db..aa4bc02b6d 100644
--- a/src/pretix/base/services/locking.py
+++ b/src/pretix/base/services/locking.py
@@ -64,13 +64,13 @@ def lock_event_db(event):
for i in range(retries):
with transaction.atomic():
dt = now()
- l, created = EventLock.objects.get_or_create(event=event.identity)
+ l, created = EventLock.objects.get_or_create(event=event.id)
if created:
event._lock = l
return True
elif l.date < now() - timedelta(seconds=LOCK_TIMEOUT):
newtoken = uuid.uuid4()
- updated = EventLock.objects.filter(event=event.identity, token=l.token).update(date=dt, token=newtoken)
+ updated = EventLock.objects.filter(event=event.id, token=l.token).update(date=dt, token=newtoken)
if updated:
l.token = newtoken
event._lock = l
@@ -84,7 +84,7 @@ def release_event_db(event):
if not hasattr(event, '_lock') or not event._lock:
raise EventLock.LockReleaseException('Lock is not owned by this thread')
try:
- lock = EventLock.objects.get(event=event.identity, token=event._lock.token)
+ lock = EventLock.objects.get(event=event.id, token=event._lock.token)
lock.delete()
event._lock = None
except EventLock.DoesNotExist:
@@ -97,7 +97,7 @@ def redis_lock_from_event(event):
if not hasattr(event, '_lock') or not event._lock:
rc = get_redis_connection("redis")
- event._lock = Lock(redis=rc, name='pretix_event_%s' % event.identity, timeout=LOCK_TIMEOUT)
+ event._lock = Lock(redis=rc, name='pretix_event_%s' % event.id, timeout=LOCK_TIMEOUT)
return event._lock
diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py
index 45326cbe3b..12abd79cde 100644
--- a/src/pretix/base/services/orders.py
+++ b/src/pretix/base/services/orders.py
@@ -33,8 +33,8 @@ error_messages = {
def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None,
force: bool=False) -> Order:
"""
- Marks an order as paid. This clones the order object, sets the payment provider,
- info and date and returns the cloned order object.
+ Marks an order as paid. This sets the payment provider, info and date and returns
+ the order object.
:param provider: The payment provider that marked this as paid
:type provider: str
@@ -52,7 +52,6 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
can_be_paid = order._can_be_paid()
if not force and can_be_paid is not True:
raise Quota.QuotaExceededException(can_be_paid)
- order = order.clone()
order.payment_provider = provider or order.payment_provider
order.payment_info = info or order.payment_info
order.payment_date = date or now()
@@ -110,7 +109,6 @@ def _check_positions(event: Event, dt: datetime, positions: List[CartPosition]):
cp.delete()
continue
if price != cp.price:
- cp = cp.clone()
positions[i] = cp
cp.price = price
cp.save()
@@ -125,7 +123,6 @@ def _check_positions(event: Event, dt: datetime, positions: List[CartPosition]):
quota_ok = False
break
if quota_ok:
- cp = cp.clone()
positions[i] = cp
cp.expires = now() + timedelta(
minutes=event.settings.get('reservation_time', as_type=int))
@@ -163,7 +160,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], dt: d
def _perform_order(event: str, payment_provider: str, position_ids: List[str],
email: str, locale: str):
- event = Event.objects.current.get(identity=event)
+ event = Event.objects.get(id=event)
responses = register_payment_providers.send(event)
pprov = None
for receiver, response in responses:
@@ -175,8 +172,8 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
dt = now()
with event.lock():
- positions = list(CartPosition.objects.current.filter(
- identity__in=position_ids).select_related('item', 'variation'))
+ positions = list(CartPosition.objects.filter(
+ id__in=position_ids).select_related('item', 'variation'))
if len(position_ids) != len(positions):
raise OrderError(error_messages['internal'])
_check_positions(event, dt, positions)
@@ -197,7 +194,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
},
event, locale=order.locale
)
- return order.identity
+ return order.id
def perform_order(event: str, payment_provider: str, positions: List[str],
diff --git a/src/pretix/base/services/stats.py b/src/pretix/base/services/stats.py
index b91c3d6d00..b042481e8a 100644
--- a/src/pretix/base/services/stats.py
+++ b/src/pretix/base/services/stats.py
@@ -37,28 +37,28 @@ def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
num_total = {
(p['item'], p['variation']): (p['cnt'], p['price'])
- for p in (OrderPosition.objects.current
+ for p in (OrderPosition.objects
.filter(order__event=event)
.values('item', 'variation')
.annotate(cnt=Count('id'), price=Sum('price')).order_by())
}
num_cancelled = {
(p['item'], p['variation']): (p['cnt'], p['price'])
- for p in (OrderPosition.objects.current
+ for p in (OrderPosition.objects
.filter(order__event=event, order__status=Order.STATUS_CANCELLED)
.values('item', 'variation')
.annotate(cnt=Count('id'), price=Sum('price')).order_by())
}
num_refunded = {
(p['item'], p['variation']): (p['cnt'], p['price'])
- for p in (OrderPosition.objects.current
+ for p in (OrderPosition.objects
.filter(order__event=event, order__status=Order.STATUS_REFUNDED)
.values('item', 'variation')
.annotate(cnt=Count('id'), price=Sum('price')).order_by())
}
num_pending = {
(p['item'], p['variation']): (p['cnt'], p['price'])
- for p in (OrderPosition.objects.current
+ for p in (OrderPosition.objects
.filter(order__event=event,
order__status__in=(Order.STATUS_PENDING, Order.STATUS_EXPIRED))
.values('item', 'variation')
@@ -66,7 +66,7 @@ def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
}
num_paid = {
(p['item'], p['variation']): (p['cnt'], p['price'])
- for p in (OrderPosition.objects.current
+ for p in (OrderPosition.objects
.filter(order__event=event, order__status=Order.STATUS_PAID)
.values('item', 'variation')
.annotate(cnt=Count('id'), price=Sum('price')).order_by())
@@ -76,12 +76,12 @@ def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
item.all_variations = sorted(item.get_all_variations(),
key=lambda vd: vd.ordered_values())
for var in item.all_variations:
- variid = var['variation'].identity if 'variation' in var else None
- var.num_total = num_total.get((item.identity, variid), (0, 0))
- var.num_pending = num_pending.get((item.identity, variid), (0, 0))
- var.num_cancelled = num_cancelled.get((item.identity, variid), (0, 0))
- var.num_refunded = num_refunded.get((item.identity, variid), (0, 0))
- var.num_paid = num_paid.get((item.identity, variid), (0, 0))
+ variid = var['variation'].id if 'variation' in var else None
+ var.num_total = num_total.get((item.id, variid), (0, 0))
+ var.num_pending = num_pending.get((item.id, variid), (0, 0))
+ var.num_cancelled = num_cancelled.get((item.id, variid), (0, 0))
+ var.num_refunded = num_refunded.get((item.id, variid), (0, 0))
+ var.num_paid = num_paid.get((item.id, variid), (0, 0))
item.has_variations = (len(item.all_variations) != 1
or not item.all_variations[0].empty())
item.num_total = tuplesum(var.num_total for var in item.all_variations)
@@ -100,7 +100,8 @@ def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
# insert categories into a set for uniqueness
# a set is unsorted, so sort again by category
],
- key=lambda group: (group[0].position, group[0].identity) if group[0] is not None else (0, "")
+ key=lambda group: (group[0].position, group[0].id) if (
+ group[0] is not None and group[0].id is not None) else (0, 0)
)
for c in items_by_category:
@@ -116,35 +117,35 @@ def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
payment_items = []
num_total = {
o['payment_provider']: (o['cnt'], o['payment_fee'])
- for o in (Order.objects.current
+ for o in (Order.objects
.filter(event=event)
.values('payment_provider')
.annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
}
num_cancelled = {
o['payment_provider']: (o['cnt'], o['payment_fee'])
- for o in (Order.objects.current
+ for o in (Order.objects
.filter(event=event, status=Order.STATUS_CANCELLED)
.values('payment_provider')
.annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
}
num_refunded = {
o['payment_provider']: (o['cnt'], o['payment_fee'])
- for o in (Order.objects.current
+ for o in (Order.objects
.filter(event=event, status=Order.STATUS_REFUNDED)
.values('payment_provider')
.annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
}
num_pending = {
o['payment_provider']: (o['cnt'], o['payment_fee'])
- for o in (Order.objects.current
+ for o in (Order.objects
.filter(event=event, status__in=(Order.STATUS_PENDING, Order.STATUS_EXPIRED))
.values('payment_provider')
.annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
}
num_paid = {
o['payment_provider']: (o['cnt'], o['payment_fee'])
- for o in (Order.objects.current
+ for o in (Order.objects
.filter(event=event, status=Order.STATUS_PAID)
.values('payment_provider')
.annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
diff --git a/src/pretix/base/services/tickets.py b/src/pretix/base/services/tickets.py
index aefd0dbd76..469b1cbbf6 100644
--- a/src/pretix/base/services/tickets.py
+++ b/src/pretix/base/services/tickets.py
@@ -9,7 +9,7 @@ from pretix.base.signals import register_ticket_outputs
def generate(order: str, provider: str):
- order = Order.objects.current.select_related('event').get(identity=order)
+ order = Order.objects.select_related('event').get(id=order)
ct = CachedTicket.objects.get_or_create(order=order, provider=provider)[0]
if not ct.cachedfile:
cf = CachedFile()
diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py
index b5b77213ab..83f4299166 100644
--- a/src/pretix/base/settings.py
+++ b/src/pretix/base/settings.py
@@ -8,7 +8,6 @@ from django.core.files import File
from django.core.files.storage import default_storage
from django.db.models import Model
from typing import Any, Callable, Dict, Optional, TypeVar, Union
-from versions.models import Versionable
DEFAULTS = {
'max_items_per_order': {
@@ -115,7 +114,7 @@ class SettingsProxy:
def _cache(self) -> Dict[str, Any]:
if self._cached_obj is None:
self._cached_obj = {}
- for setting in self._obj.setting_objects.current.all():
+ for setting in self._obj.setting_objects.all():
self._cached_obj[setting.key] = setting
return self._cached_obj
@@ -146,8 +145,6 @@ class SettingsProxy:
return dateutil.parser.parse(value).date()
elif as_type == time:
return dateutil.parser.parse(value).time()
- elif as_type is not None and issubclass(as_type, Versionable):
- return as_type.objects.current.get(identity=value)
elif as_type is not None and issubclass(as_type, Model):
return as_type.objects.get(pk=value)
return value
@@ -162,8 +159,6 @@ class SettingsProxy:
return json.dumps(value)
elif isinstance(value, datetime) or isinstance(value, date) or isinstance(value, time):
return value.isoformat()
- elif isinstance(value, Versionable):
- return value.identity
elif isinstance(value, Model):
return value.pk
elif isinstance(value, File):
@@ -213,7 +208,6 @@ class SettingsProxy:
def set(self, key: str, value: Any) -> None:
if key in self._cache():
s = self._cache()[key]
- s = s.clone()
else:
s = self._type(object=self._obj, key=key)
s.value = self._serialize(value)
@@ -237,7 +231,7 @@ class SettingsSandbox:
prefixes for you.
"""
- def __init__(self, type: str, key: str, event: Versionable):
+ def __init__(self, type: str, key: str, event: Model):
self._event = event
self._type = type
self._key = key
diff --git a/src/pretix/control/forms/__init__.py b/src/pretix/control/forms/__init__.py
index 1966f65a23..b4e63396e2 100644
--- a/src/pretix/control/forms/__init__.py
+++ b/src/pretix/control/forms/__init__.py
@@ -14,7 +14,7 @@ from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
-from pretix.base.forms import VersionedModelForm
+from pretix.base.forms import I18nModelForm
from pretix.base.models import Item, ItemVariation
@@ -59,9 +59,9 @@ class I18nFormSet(BaseModelFormSet):
return form
-class TolerantFormsetModelForm(VersionedModelForm):
+class TolerantFormsetModelForm(I18nModelForm):
"""
- This is equivalent to a normal VersionedModelForm, but works around a problem that
+ This is equivalent to a normal I18nModelForm, but works around a problem that
arises when the form is used inside a FormSet with can_order=True and django-formset-js
enabled. In this configuration, even empty "extra" forms might have an ORDER value
sent and Django marks the form as empty and raises validation errors because the other
@@ -105,15 +105,15 @@ def selector(values, prop):
# properties they belong to EXCEPT the value for the property prop2.
# We'll see later why we need this.
return [
- v.identity for v in sorted(values, key=lambda v: v.prop.identity)
- if v.prop.identity != prop.identity
+ v.id for v in sorted(values, key=lambda v: v.prop.id)
+ if v.prop.id != prop.id
]
def sort(v, prop):
# Given a list of variations, this will sort them by their position
# on the x-axis
- return v[prop.identity].sortkey
+ return v[prop.id].sortkey
class VariationsFieldRenderer(forms.widgets.CheckboxFieldRenderer):
@@ -175,7 +175,7 @@ class VariationsFieldRenderer(forms.widgets.CheckboxFieldRenderer):
final_attrs['checked'] = 'checked'
w = self.choice_input_class(
self.name, self.value, self.attrs.copy(),
- (variation['key'], variation[properties[0].identity].value),
+ (variation['key'], variation[properties[0].id].value),
i
)
output.append(format_html('{0}', force_text(w)))
@@ -185,15 +185,15 @@ class VariationsFieldRenderer(forms.widgets.CheckboxFieldRenderer):
def render_nd(self, output, variations, properties):
# prop1 is the property on all the grid's y-axes
prop1 = properties[0]
- prop1v = list(prop1.values.current.all())
+ prop1v = list(prop1.values.all())
# prop2 is the property on all the grid's x-axes
prop2 = properties[1]
- prop2v = list(prop2.values.current.all())
+ prop2v = list(prop2.values.all())
# We now iterate over the cartesian product of all the other
# properties which are NOT on the axes of the grid because we
# create one grid for any combination of them.
- for gridrow in product(*[prop.values.current.all() for prop in properties[2:]]):
+ for gridrow in product(*[prop.values.all() for prop in properties[2:]]):
if len(gridrow) > 0:
output.append('')
output.append(", ".join([str(value.value) for value in gridrow]))
@@ -281,7 +281,7 @@ class VariationsField(forms.ModelMultipleChoiceField):
variations = self.item.get_all_variations(use_cache=True)
return (
(
- v['variation'].identity if 'variation' in v else v.key(),
+ v['variation'].id if 'variation' in v else v.key(),
v
) for v in variations
)
@@ -312,10 +312,10 @@ class VariationsField(forms.ModelMultipleChoiceField):
cleaned_value = self._clean_value(value)
- qs = self.item.variations.current.filter(identity__in=cleaned_value)
+ qs = self.item.variations.filter(id__in=cleaned_value)
# Re-check for consistency
- pks = set(force_text(getattr(o, "identity")) for o in qs)
+ pks = set(force_text(getattr(o, "id")) for o in qs)
for val in cleaned_value:
if force_text(val) not in pks:
raise ValidationError(
@@ -335,7 +335,7 @@ class VariationsField(forms.ModelMultipleChoiceField):
# which uses a very similar method
all_variations = self.item.variations.all().prefetch_related("values")
variations_cache = {
- var.to_variation_dict().identify(): var.identity for var in all_variations
+ var.to_variation_dict().identify(): var.id for var in all_variations
}
cleaned_value = []
@@ -360,7 +360,7 @@ class VariationsField(forms.ModelMultipleChoiceField):
# No ItemVariation present, create one!
var = ItemVariation()
- var.item_id = self.item.identity
+ var.item_id = self.item.id
var.save()
# Add the values to the ItemVariation object
try:
@@ -371,8 +371,8 @@ class VariationsField(forms.ModelMultipleChoiceField):
code='invalid_pk_value',
params={'pk': value},
)
- variations_cache[key] = var.identity
- cleaned_value.append(str(var.identity))
+ variations_cache[key] = var.id
+ cleaned_value.append(str(var.id))
else:
# An ItemVariation id was given
cleaned_value.append(pk)
diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py
index 7caa943637..31cb2c7816 100644
--- a/src/pretix/control/forms/event.py
+++ b/src/pretix/control/forms/event.py
@@ -4,11 +4,11 @@ from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from pytz import common_timezones
-from pretix.base.forms import SettingsForm, VersionedModelForm
+from pretix.base.forms import I18nModelForm, SettingsForm
from pretix.base.models import Event
-class EventCreateForm(VersionedModelForm):
+class EventCreateForm(I18nModelForm):
error_messages = {
'duplicate_slug': _("You already used this slug for a different event. Please choose a new one."),
}
@@ -39,7 +39,7 @@ class EventCreateForm(VersionedModelForm):
return slug
-class EventUpdateForm(VersionedModelForm):
+class EventUpdateForm(I18nModelForm):
def clean_slug(self):
return self.instance.slug
diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py
index df2c762c2f..0b40c810c4 100644
--- a/src/pretix/control/forms/item.py
+++ b/src/pretix/control/forms/item.py
@@ -1,19 +1,18 @@
import copy
from django import forms
-from django.db import models
from django.forms import BooleanField
from django.utils.translation import ugettext_lazy as _
-from pretix.base.forms import I18nModelForm, VersionedModelForm
+from pretix.base.forms import I18nModelForm
from pretix.base.models import (
Item, ItemCategory, ItemVariation, Property, PropertyValue, Question,
- Quota, Versionable,
+ Quota,
)
from pretix.control.forms import TolerantFormsetModelForm, VariationsField
-class CategoryForm(VersionedModelForm):
+class CategoryForm(I18nModelForm):
class Meta:
model = ItemCategory
localized_fields = '__all__'
@@ -22,7 +21,7 @@ class CategoryForm(VersionedModelForm):
]
-class PropertyForm(VersionedModelForm):
+class PropertyForm(I18nModelForm):
class Meta:
model = Property
localized_fields = '__all__'
@@ -40,10 +39,10 @@ class PropertyValueForm(TolerantFormsetModelForm):
]
-class QuestionForm(VersionedModelForm):
+class QuestionForm(I18nModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['items'].queryset = self.instance.event.items.current.all()
+ self.fields['items'].queryset = self.instance.event.items.all()
class Meta:
model = Question
@@ -60,10 +59,6 @@ class QuestionForm(VersionedModelForm):
class QuotaForm(I18nModelForm):
- """
- The form for quotas does not derive from VersionedModelForm as it does not
- perform a 'full clone' as part of a performance optimization
- """
def __init__(self, **kwargs):
items = kwargs['items']
@@ -72,7 +67,7 @@ class QuotaForm(I18nModelForm):
self.original_instance = copy.copy(instance) if instance else None
super().__init__(**kwargs)
- if hasattr(self, 'instance'):
+ if hasattr(self, 'instance') and self.instance.pk:
active_items = set(self.instance.items.all())
active_variations = set(self.instance.variations.all())
else:
@@ -81,36 +76,19 @@ class QuotaForm(I18nModelForm):
for item in items:
if len(item.properties.all()) > 0:
- self.fields['item_%s' % item.identity] = VariationsField(
+ self.fields['item_%s' % item.id] = VariationsField(
item, label=_("Activate for"),
required=False,
initial=active_variations
)
- self.fields['item_%s' % item.identity].set_item(item)
+ self.fields['item_%s' % item.id].set_item(item)
else:
- self.fields['item_%s' % item.identity] = BooleanField(
+ self.fields['item_%s' % item.id] = BooleanField(
label=_("Activate"),
required=False,
initial=(item in active_items)
)
- def save(self, commit=True):
- if self.instance.pk is not None and isinstance(self.instance, Versionable):
- if self.has_changed() and self.original_instance:
- new = self.instance
- old = self.original_instance
- clone = old.clone_shallow()
- for f in type(self.instance)._meta.get_fields():
- if f.name not in (
- 'id', 'identity', 'version_start_date', 'version_end_date',
- 'version_birth_date'
- ) and not isinstance(f, (
- models.ManyToOneRel, models.ManyToManyRel, models.ManyToManyField
- )):
- setattr(clone, f.name, getattr(new, f.name))
- self.instance = clone
- return super().save(commit)
-
class Meta:
model = Quota
localized_fields = '__all__'
@@ -120,10 +98,10 @@ class QuotaForm(I18nModelForm):
]
-class ItemFormGeneral(VersionedModelForm):
+class ItemFormGeneral(I18nModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['category'].queryset = self.instance.event.categories.current.all()
+ self.fields['category'].queryset = self.instance.event.categories.all()
class Meta:
model = Item
@@ -142,7 +120,7 @@ class ItemFormGeneral(VersionedModelForm):
]
-class ItemVariationForm(VersionedModelForm):
+class ItemVariationForm(I18nModelForm):
class Meta:
model = ItemVariation
localized_fields = '__all__'
diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py
index f8f2e23ae8..0706f74572 100644
--- a/src/pretix/control/forms/orders.py
+++ b/src/pretix/control/forms/orders.py
@@ -1,8 +1,8 @@
-from pretix.base.forms import VersionedModelForm
+from pretix.base.forms import I18nModelForm
from pretix.base.models import Order
-class ExtendForm(VersionedModelForm):
+class ExtendForm(I18nModelForm):
class Meta:
model = Order
fields = ['expires']
diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py
index b35742c7a2..a80ddc3e2c 100644
--- a/src/pretix/control/forms/organizer.py
+++ b/src/pretix/control/forms/organizer.py
@@ -1,11 +1,11 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
-from pretix.base.forms import VersionedModelForm
+from pretix.base.forms import I18nModelForm
from pretix.base.models import Organizer
-class OrganizerForm(VersionedModelForm):
+class OrganizerForm(I18nModelForm):
error_messages = {
'duplicate_slug': _("This slug is already in use. Please choose a different one."),
}
diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py
index 35030d2e25..593f69c040 100644
--- a/src/pretix/control/middleware.py
+++ b/src/pretix/control/middleware.py
@@ -54,16 +54,16 @@ class PermissionMiddleware:
return redirect_to_login(
path, resolved_login_url, REDIRECT_FIELD_NAME)
- request.user.events_cache = request.user.events.current.order_by(
+ request.user.events_cache = request.user.events.order_by(
"organizer", "date_from").prefetch_related("organizer")
if 'event' in url.kwargs and 'organizer' in url.kwargs:
try:
- request.event = Event.objects.current.filter(
+ request.event = Event.objects.filter(
slug=url.kwargs['event'],
permitted__id__exact=request.user.id,
organizer__slug=url.kwargs['organizer'],
).select_related('organizer')[0]
- request.eventperm = EventPermission.objects.current.get(
+ request.eventperm = EventPermission.objects.get(
event=request.event,
user=request.user
)
@@ -73,7 +73,7 @@ class PermissionMiddleware:
"have no permission to administrate it."))
elif 'organizer' in url.kwargs:
try:
- request.organizer = Organizer.objects.current.filter(
+ request.organizer = Organizer.objects.filter(
slug=url.kwargs['organizer'],
permitted__id__exact=request.user.id,
)[0]
diff --git a/src/pretix/control/permissions.py b/src/pretix/control/permissions.py
index 1b31daa72f..a38d3ffa94 100644
--- a/src/pretix/control/permissions.py
+++ b/src/pretix/control/permissions.py
@@ -15,7 +15,7 @@ def event_permission_required(permission):
# just a double check, should not ever happen
raise PermissionDenied()
try:
- perm = EventPermission.objects.current.get(
+ perm = EventPermission.objects.get(
event=request.event,
user=request.user
)
@@ -59,7 +59,7 @@ def organizer_permission_required(permission):
# just a double check, should not ever happen
raise PermissionDenied()
try:
- perm = OrganizerPermission.objects.current.get(
+ perm = OrganizerPermission.objects.get(
organizer=request.organizer,
user=request.user
)
diff --git a/src/pretix/control/templates/pretixcontrol/item/base.html b/src/pretix/control/templates/pretixcontrol/item/base.html
index 43eaadc09e..f19785ed1f 100644
--- a/src/pretix/control/templates/pretixcontrol/item/base.html
+++ b/src/pretix/control/templates/pretixcontrol/item/base.html
@@ -2,12 +2,12 @@
{% load i18n %}
{% block title %}{{ object.name }} :: {% trans "Product" %}{% endblock %}
{% block content %}
- {% if object.identity %}
+ {% if object.id %}
{% trans "Modify product:" %} {{ object.name }}
{% else %}
{% trans "Create product" %}
@@ -15,7 +15,7 @@
You will be able to adjust further settings in the next step.
{% endblocktrans %}
{% endif %}
- {% if object.identity and not object.quotas.exists %}
+ {% if object.id and not object.quotas.exists %}
{% blocktrans trimmed %}
Please note, that your product will
not be available for sale until you added your
diff --git a/src/pretix/control/templates/pretixcontrol/items/categories.html b/src/pretix/control/templates/pretixcontrol/items/categories.html
index 143107b4c6..d195c1306f 100644
--- a/src/pretix/control/templates/pretixcontrol/items/categories.html
+++ b/src/pretix/control/templates/pretixcontrol/items/categories.html
@@ -18,12 +18,12 @@
{% for c in categories %}
- | {{ c.name }} |
+ {{ c.name }} |
-
-
+
+
|
- |
+ |
{% endfor %}
diff --git a/src/pretix/control/templates/pretixcontrol/items/index.html b/src/pretix/control/templates/pretixcontrol/items/index.html
index 32605674e8..8438040b5b 100644
--- a/src/pretix/control/templates/pretixcontrol/items/index.html
+++ b/src/pretix/control/templates/pretixcontrol/items/index.html
@@ -32,15 +32,15 @@
{% if not i.active %}{% endif %}
{{ i.name }}
+ {% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}">{{ i.name }}
{% if not i.active %}{% endif %}
|
{% if i.category %}{{ i.category.name }}{% endif %} |
-
-
+
+
|
-
|
+
|
{% endfor %}
{% endfor %}
diff --git a/src/pretix/control/templates/pretixcontrol/items/questions.html b/src/pretix/control/templates/pretixcontrol/items/questions.html
index 38085446b2..34e0b6dd47 100644
--- a/src/pretix/control/templates/pretixcontrol/items/questions.html
+++ b/src/pretix/control/templates/pretixcontrol/items/questions.html
@@ -19,10 +19,10 @@
{% for q in questions %}
| {{ q.question }} |
+ {% url "control:event.items.questions.edit" organizer=request.event.organizer.slug event=request.event.slug question=q.id %}">{{ q.question }}
{{ q.get_type_display }} |
|
+ {% url "control:event.items.questions.delete" organizer=request.event.organizer.slug event=request.event.slug question=q.id %}" class="btn btn-danger btn-sm">
{% endfor %}
diff --git a/src/pretix/control/templates/pretixcontrol/items/quota.html b/src/pretix/control/templates/pretixcontrol/items/quota.html
index d66ce72d8b..6f1b08038f 100644
--- a/src/pretix/control/templates/pretixcontrol/items/quota.html
+++ b/src/pretix/control/templates/pretixcontrol/items/quota.html
@@ -25,12 +25,12 @@
-