mirror of
https://github.com/pretix/pretix.git
synced 2026-05-08 15:44:02 +00:00
Manage item properties
This commit is contained in:
@@ -1,16 +1,24 @@
|
|||||||
|
# Functional requirements
|
||||||
Django>=1.7
|
Django>=1.7
|
||||||
pytz
|
pytz
|
||||||
django-bootstrap3
|
django-bootstrap3
|
||||||
|
-e git+https://github.com/tixl/django-formset-js.git@master#egg=django-formset-js
|
||||||
|
|
||||||
|
# Deployment / static file compilation requirements
|
||||||
django-compressor
|
django-compressor
|
||||||
BeautifulSoup4
|
BeautifulSoup4
|
||||||
html5lib
|
html5lib
|
||||||
slimit
|
slimit
|
||||||
lxml
|
lxml
|
||||||
|
|
||||||
|
# Debugging requirements
|
||||||
|
django-debug-toolbar
|
||||||
|
|
||||||
|
# Testing requirements
|
||||||
pyflakes
|
pyflakes
|
||||||
pep8
|
pep8
|
||||||
pep8-naming
|
pep8-naming
|
||||||
flake8
|
flake8
|
||||||
django-debug-toolbar
|
|
||||||
coveralls
|
coveralls
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ INSTALLED_APPS = (
|
|||||||
'compressor',
|
'compressor',
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'debug_toolbar.apps.DebugToolbarConfig',
|
'debug_toolbar.apps.DebugToolbarConfig',
|
||||||
|
'djangoformsetjs',
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
|
|||||||
20
src/tixlbase/migrations/0013_propertyvalue_position.py
Normal file
20
src/tixlbase/migrations/0013_propertyvalue_position.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tixlbase', '0012_auto_20140929_1935'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='propertyvalue',
|
||||||
|
name='position',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -393,10 +393,18 @@ class PropertyValue(models.Model):
|
|||||||
max_length=250,
|
max_length=250,
|
||||||
verbose_name=_("Value"),
|
verbose_name=_("Value"),
|
||||||
)
|
)
|
||||||
|
position = models.IntegerField(
|
||||||
|
default=0
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: %s" % (self.prop.name, self.value)
|
return "%s: %s" % (self.prop.name, self.value)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Property value")
|
||||||
|
verbose_name_plural = _("Property values")
|
||||||
|
ordering = ("position",)
|
||||||
|
|
||||||
|
|
||||||
class Item(models.Model):
|
class Item(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|||||||
6
src/tixlcontrol/static/tixlcontrol/js/ui/main.js
Normal file
6
src/tixlcontrol/static/tixlcontrol/js/ui/main.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
$(function() {
|
||||||
|
$("[data-formset]").formset({
|
||||||
|
animateForms: true,
|
||||||
|
reorderMode: 'animate',
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -14,3 +14,13 @@ td > .form-group > .checkbox {
|
|||||||
.has-success .form-control {
|
.has-success .form-control {
|
||||||
border-color: #cccccc;
|
border-color: #cccccc;
|
||||||
}
|
}
|
||||||
|
.form-horizontal [data-formset] .form-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
[data-formset] .form-group:not([data-formset-form-deleted]):last-of-type [data-formset-move-down-button],
|
||||||
|
[data-formset] .form-group:not([data-formset-form-deleted]):first-of-type [data-formset-move-up-button] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none; // Future-proof disabling of clicks
|
||||||
|
.opacity(.65);
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{% compress js %}
|
{% compress js %}
|
||||||
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>
|
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static "js/jquery.formset.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "bootstrap/dist/js/bootstrap.js" %}"></script>
|
<script type="text/javascript" src="{% static "bootstrap/dist/js/bootstrap.js" %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static "tixlcontrol/js/ui/main.js" %}"></script>
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -7,12 +7,14 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Item name" %}</th>
|
<th>{% trans "Item name" %}</th>
|
||||||
|
<th>{% trans "Category" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for i in items %}
|
{% for i in items %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.pk %}">{{ i.name }}</a></strong></td>
|
<td><strong><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.pk %}">{{ i.name }}</a></strong></td>
|
||||||
|
<td>{{ i.category }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
38
src/tixlcontrol/templates/tixlcontrol/items/properties.html
Normal file
38
src/tixlcontrol/templates/tixlcontrol/items/properties.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Item properties" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Item properties" %}</h1>
|
||||||
|
{% if "updated" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "Your changes have been saved." %}
|
||||||
|
</div>
|
||||||
|
{% elif "created" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "A new property has been created." %}
|
||||||
|
</div>
|
||||||
|
{% elif "deleted" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "The property has been deleted." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<p>
|
||||||
|
<a href="{% url "control:event.items.properties.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create new property" %}</a>
|
||||||
|
</p>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Item properties" %}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for p in properties %}
|
||||||
|
<tr>
|
||||||
|
<td><strong><a href="{% url "control:event.items.properties.edit" organizer=request.event.organizer.slug event=request.event.slug property=p.pk %}">{{ p.name }}</a></strong></td>
|
||||||
|
<td class="text-right"><a href="{% url "control:event.items.properties.delete" organizer=request.event.organizer.slug event=request.event.slug property=p.pk %}"" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
72
src/tixlcontrol/templates/tixlcontrol/items/property.html
Normal file
72
src/tixlcontrol/templates/tixlcontrol/items/property.html
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load formset_tags %}
|
||||||
|
{% block title %}{% trans "Item property" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Item property" %}</h1>
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% if "success" in request.GET %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
{% trans "Your changes have been saved." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans "General information" %}</legend>
|
||||||
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans "Values" %}</legend>
|
||||||
|
<div data-formset data-formset-prefix="{{ formset.prefix }}">
|
||||||
|
<div data-formset-body>
|
||||||
|
{{ formset.management_form }}
|
||||||
|
{% for f in formset %}
|
||||||
|
<div class="form-group" data-formset-form>
|
||||||
|
{{ f.id }}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
{% bootstrap_field f.value form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="sr-only">
|
||||||
|
{% bootstrap_field f.ORDER form_group_class="" layout="inline" %}
|
||||||
|
{% bootstrap_field f.DELETE form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 text-right">
|
||||||
|
<button type="button" class="btn btn-default" data-formset-move-up-button><i class="fa fa-arrow-up"></i></button>
|
||||||
|
<button type="button" class="btn btn-default" data-formset-move-down-button><i class="fa fa-arrow-down"></i></button>
|
||||||
|
<button type="button" class="btn btn-danger" data-formset-delete-button><i class="fa fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<script type="form-template" data-formset-empty-form>
|
||||||
|
{% escapescript %}
|
||||||
|
<div class="form-group" data-formset-form>
|
||||||
|
{{ formset.empty_form.id }}
|
||||||
|
<div class="col-sm-10">
|
||||||
|
{% bootstrap_field formset.empty_form.value form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="sr-only">
|
||||||
|
{% bootstrap_field formset.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||||
|
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 text-right">
|
||||||
|
<button type="button" class="btn btn-default" data-formset-move-up-button><i class="fa fa-arrow-up"></i></button>
|
||||||
|
<button type="button" class="btn btn-default" data-formset-move-down-button><i class="fa fa-arrow-down"></i></button>
|
||||||
|
<button type="button" class="btn btn-danger" data-formset-delete-button><i class="fa fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endescapescript %}
|
||||||
|
</script>
|
||||||
|
<button type="button" class="btn btn-default" data-formset-add><i class="fa fa-plus"></i> {% trans "Add a new value" %}</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{% trans "Save" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{% extends "tixlcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% block title %}{% trans "Delete item property" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Delete item property" %}</h1>
|
||||||
|
{% if not possible %}
|
||||||
|
<p>{% blocktrans %}You can not delete the property <strong>{{ property }}</strong> as long as the following items use it:{% endblocktrans %}</p>
|
||||||
|
<ul>
|
||||||
|
{% for item in dependent %}
|
||||||
|
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>{% blocktrans %}Are you sure you want to the property <strong>{{ property }}</strong>?{% endblocktrans %}</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{% trans "Confirm" %}
|
||||||
|
</button>
|
||||||
|
<a href="{% url "control:event.items.properties" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default">
|
||||||
|
{% trans "Cancel" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -29,6 +29,9 @@ urlpatterns += patterns(
|
|||||||
url(r'^category/(?P<category>\d+)/$', item.CategoryUpdate.as_view(), name='event.items.categories.edit'),
|
url(r'^category/(?P<category>\d+)/$', item.CategoryUpdate.as_view(), name='event.items.categories.edit'),
|
||||||
url(r'^category/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'),
|
url(r'^category/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'),
|
||||||
url(r'^properties$', item.PropertyList.as_view(), name='event.items.properties'),
|
url(r'^properties$', item.PropertyList.as_view(), name='event.items.properties'),
|
||||||
|
url(r'^properties/(?P<property>\d+)/$', item.PropertyUpdate.as_view(), name='event.items.properties.edit'),
|
||||||
|
url(r'^properties/(?P<property>\d+)/delete$', item.PropertyDelete.as_view(), name='event.items.properties.delete'),
|
||||||
|
url(r'^properties/add$', item.PropertyCreate.as_view(), name='event.items.properties.add'),
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|||||||
32
src/tixlcontrol/views/forms.py
Normal file
32
src/tixlcontrol/views/forms.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from django import forms
|
||||||
|
|
||||||
|
|
||||||
|
class TolerantFormsetModelForm(forms.ModelForm):
|
||||||
|
|
||||||
|
def has_changed(self):
|
||||||
|
"""
|
||||||
|
Returns True if data differs from initial. Contrary to the default
|
||||||
|
implementation, the ORDER field is being ignored.
|
||||||
|
"""
|
||||||
|
for name, field in self.fields.items():
|
||||||
|
if name == 'ORDER':
|
||||||
|
continue
|
||||||
|
prefixed_name = self.add_prefix(name)
|
||||||
|
data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
|
||||||
|
if not field.show_hidden_initial:
|
||||||
|
initial_value = self.initial.get(name, field.initial)
|
||||||
|
if callable(initial_value):
|
||||||
|
initial_value = initial_value()
|
||||||
|
else:
|
||||||
|
initial_prefixed_name = self.add_initial_prefix(name)
|
||||||
|
hidden_widget = field.hidden_widget()
|
||||||
|
try:
|
||||||
|
initial_value = field.to_python(hidden_widget.value_from_datadict(
|
||||||
|
self.data, self.files, initial_prefixed_name))
|
||||||
|
except forms.ValidationError:
|
||||||
|
# Always assume data has changed if validation fails.
|
||||||
|
self._changed_data.append(name)
|
||||||
|
continue
|
||||||
|
if field._has_changed(initial_value, data_value):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -5,13 +5,14 @@ from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
|||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.core.urlresolvers import resolve, reverse
|
from django.core.urlresolvers import resolve, reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect, HttpResponseForbidden
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Q
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.forms.models import inlineformset_factory
|
||||||
|
|
||||||
from tixlbase.models import Item, ItemCategory, Property, ItemVariation
|
from tixlbase.models import Item, ItemCategory, Property, ItemVariation, PropertyValue
|
||||||
from tixlcontrol.permissions import EventPermissionRequiredMixin, event_permission_required
|
from tixlcontrol.permissions import EventPermissionRequiredMixin, event_permission_required
|
||||||
|
from tixlcontrol.views.forms import TolerantFormsetModelForm
|
||||||
|
|
||||||
|
|
||||||
class ItemList(ListView):
|
class ItemList(ListView):
|
||||||
@@ -22,7 +23,7 @@ class ItemList(ListView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Item.objects.filter(
|
return Item.objects.filter(
|
||||||
event=self.request.event
|
event=self.request.event
|
||||||
)
|
).prefetch_related("category")
|
||||||
|
|
||||||
|
|
||||||
class CategoryForm(forms.ModelForm):
|
class CategoryForm(forms.ModelForm):
|
||||||
@@ -147,8 +148,8 @@ def category_move_down(request, organizer, event, category):
|
|||||||
|
|
||||||
class PropertyList(ListView):
|
class PropertyList(ListView):
|
||||||
model = Property
|
model = Property
|
||||||
context_object_name = 'items'
|
context_object_name = 'properties'
|
||||||
template_name = 'tixlcontrol/items/index.html'
|
template_name = 'tixlcontrol/items/properties.html'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Property.objects.filter(
|
return Property.objects.filter(
|
||||||
@@ -156,6 +157,164 @@ class PropertyList(ListView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Property
|
||||||
|
localized_fields = '__all__'
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyValueForm(TolerantFormsetModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = PropertyValue
|
||||||
|
localized_fields = '__all__'
|
||||||
|
fields = [
|
||||||
|
'value',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||||
|
model = Property
|
||||||
|
form_class = PropertyForm
|
||||||
|
template_name = 'tixlcontrol/items/property.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'property'
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
url = resolve(self.request.path_info)
|
||||||
|
return self.request.event.properties.get(
|
||||||
|
id=url.kwargs['property']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
url = resolve(self.request.path_info)
|
||||||
|
return reverse('control:event.items.properties.edit', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
'property': url.kwargs['property']
|
||||||
|
}) + '?success=true'
|
||||||
|
|
||||||
|
def get_formset(self):
|
||||||
|
formsetclass = inlineformset_factory(
|
||||||
|
Property, PropertyValue,
|
||||||
|
form=PropertyValueForm,
|
||||||
|
can_order=True,
|
||||||
|
extra=0,
|
||||||
|
)
|
||||||
|
formset = formsetclass(**self.get_form_kwargs())
|
||||||
|
return formset
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
context = super().get_context_data(*args, **kwargs)
|
||||||
|
context['formset'] = self.get_formset()
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form, formset):
|
||||||
|
for i, f in enumerate(formset.ordered_forms):
|
||||||
|
f.instance.position = i
|
||||||
|
formset.save()
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
form_class = self.get_form_class()
|
||||||
|
form = self.get_form(form_class)
|
||||||
|
formset = self.get_formset()
|
||||||
|
if form.is_valid() and formset.is_valid():
|
||||||
|
return self.form_valid(form, formset)
|
||||||
|
else:
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyCreate(EventPermissionRequiredMixin, CreateView):
|
||||||
|
model = Property
|
||||||
|
form_class = PropertyForm
|
||||||
|
template_name = 'tixlcontrol/items/property.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'property'
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('control:event.items.properties', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
}) + '?created=true'
|
||||||
|
|
||||||
|
def get_formset(self):
|
||||||
|
formsetclass = inlineformset_factory(
|
||||||
|
Property, PropertyValue,
|
||||||
|
form=PropertyValueForm,
|
||||||
|
can_order=True,
|
||||||
|
extra=3,
|
||||||
|
)
|
||||||
|
formset = formsetclass(**self.get_form_kwargs())
|
||||||
|
return formset
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
self.object = None
|
||||||
|
context = super().get_context_data(*args, **kwargs)
|
||||||
|
context['formset'] = self.get_formset()
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form, formset):
|
||||||
|
form.instance.event = self.request.event
|
||||||
|
resp = super().form_valid(form)
|
||||||
|
for i, f in enumerate(formset.ordered_forms):
|
||||||
|
f.instance.position = i
|
||||||
|
f.instance.prop = form.instance
|
||||||
|
f.instance.save()
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
form_class = self.get_form_class()
|
||||||
|
form = self.get_form(form_class)
|
||||||
|
formset = self.get_formset()
|
||||||
|
if form.is_valid() and formset.is_valid():
|
||||||
|
return self.form_valid(form, formset)
|
||||||
|
else:
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyDelete(EventPermissionRequiredMixin, DeleteView):
|
||||||
|
model = Property
|
||||||
|
form_class = PropertyForm
|
||||||
|
template_name = 'tixlcontrol/items/property_delete.html'
|
||||||
|
permission = 'can_change_items'
|
||||||
|
context_object_name = 'property'
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
context = super().get_context_data(*args, **kwargs)
|
||||||
|
context['dependent'] = self.get_object().items.all()
|
||||||
|
context['possible'] = self.is_allowed()
|
||||||
|
return context
|
||||||
|
|
||||||
|
def is_allowed(self):
|
||||||
|
return self.get_object().items.count() == 0
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
if not hasattr(self, 'object') or not self.object:
|
||||||
|
url = resolve(self.request.path_info)
|
||||||
|
self.object = self.request.event.properties.get(
|
||||||
|
id=url.kwargs['property']
|
||||||
|
)
|
||||||
|
return self.object
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
if self.is_allowed():
|
||||||
|
success_url = self.get_success_url()
|
||||||
|
self.get_object().delete()
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
else:
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('control:event.items.properties', kwargs={
|
||||||
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
'event': self.request.event.slug,
|
||||||
|
}) + '?deleted=true'
|
||||||
|
|
||||||
|
|
||||||
class ItemUpdateFormGeneral(forms.ModelForm):
|
class ItemUpdateFormGeneral(forms.ModelForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|||||||
Reference in New Issue
Block a user