mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Allow to adjust the order of products (closes #60)
This commit is contained in:
29
src/pretix/base/migrations/0003_auto_20150602_2232.py
Normal file
29
src/pretix/base/migrations/0003_auto_20150602_2232.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0002_auto_20150524_1148'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='item',
|
||||
options={'verbose_name_plural': 'Products', 'ordering': ('category__position', 'category', 'position'), 'verbose_name': 'Product'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='position',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organizer',
|
||||
name='slug',
|
||||
field=models.SlugField(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(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')], verbose_name='Slug'),
|
||||
),
|
||||
]
|
||||
@@ -860,10 +860,14 @@ class Item(Versionable):
|
||||
),
|
||||
default=False
|
||||
)
|
||||
position = models.IntegerField(
|
||||
default=0
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Product")
|
||||
verbose_name_plural = _("Products")
|
||||
ordering = ("category__position", "category", "position")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
{% block title %}{% trans "Products" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Products" %}</h1>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
Below, you find a list of all available products. You can click on a product name to inspect and change
|
||||
product details. You can also use the buttons on the right to change the order of products within a
|
||||
give category.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
<a href="{% url "control:event.items.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create new product" %}</a>
|
||||
@@ -12,16 +19,24 @@
|
||||
<tr>
|
||||
<th>{% trans "Product name" %}</th>
|
||||
<th>{% trans "Category" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for i in items %}
|
||||
<tr>
|
||||
<td><strong><a href="
|
||||
{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}">{{ i.name }}</a></strong></td>
|
||||
<td>{% if i.category %}{{ i.category.name }}{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% regroup items by category as cat_list %}
|
||||
{% for c in cat_list %}
|
||||
{% for i in c.list %}
|
||||
<tr>
|
||||
<td><strong><a href="
|
||||
{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}">{{ i.name }}</a></strong></td>
|
||||
<td>{% if i.category %}{{ i.category.name }}{% endif %}</td>
|
||||
<td>
|
||||
<a href="{% url "control:event.items.up" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}" class="btn btn-default btn-sm {% if forloop.counter0 == 0 %}disabled{% endif %}"><i class="fa fa-arrow-up"></i></a>
|
||||
<a href="{% url "control:event.items.down" organizer=request.event.organizer.slug event=request.event.slug item=i.identity %}" class="btn btn-default btn-sm {% if forloop.revcounter0 == 0 %}disabled{% endif %}"><i class="fa fa-arrow-down"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
|
||||
@@ -27,6 +27,8 @@ urlpatterns = [
|
||||
name='event.item.variations'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/restrictions$', item.ItemRestrictions.as_view(),
|
||||
name='event.item.restrictions'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/up$', item.item_move_up, name='event.items.up'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/down$', item.item_move_down, name='event.items.down'),
|
||||
url(r'^categories/$', item.CategoryList.as_view(), name='event.items.categories'),
|
||||
url(r'^categories/(?P<category>[0-9a-f-]+)/delete$', item.CategoryDelete.as_view(),
|
||||
name='event.items.categories.delete'),
|
||||
|
||||
@@ -27,7 +27,9 @@ from . import UpdateView, CreateView
|
||||
class ItemList(ListView):
|
||||
model = Item
|
||||
context_object_name = 'items'
|
||||
paginate_by = 30
|
||||
# paginate_by = 30
|
||||
# Pagination is disabled as it is very unlikely to be necessary
|
||||
# here and could cause problems with the "reorder-within-category" feature
|
||||
template_name = 'pretixcontrol/items/index.html'
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -36,6 +38,49 @@ class ItemList(ListView):
|
||||
).prefetch_related("category")
|
||||
|
||||
|
||||
def item_move(request, item, up=True):
|
||||
"""
|
||||
This is a helper function to avoid duplicating code in item_move_up and
|
||||
item_move_down. It takes an item and a direction and then tries to bring
|
||||
all items for this category in a new order.
|
||||
"""
|
||||
try:
|
||||
item = request.event.items.current.get(
|
||||
identity=item
|
||||
)
|
||||
except Item.DoesNotExist:
|
||||
raise Http404(_("The requested product does not exist."))
|
||||
items = list(request.event.items.current.filter(category=item.category).order_by("position"))
|
||||
|
||||
index = items.index(item)
|
||||
if index != 0 and up:
|
||||
items[index - 1], items[index] = items[index], items[index - 1]
|
||||
elif index != len(items) - 1 and not up:
|
||||
items[index + 1], items[index] = items[index], items[index + 1]
|
||||
|
||||
for i, item in enumerate(items):
|
||||
if item.position != i:
|
||||
item.position = i
|
||||
item.save() # TODO: Clone or document sloppiness?
|
||||
messages.success(request, _('The order of items as been updated.'))
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
def item_move_up(request, organizer, event, item):
|
||||
item_move(request, item, up=True)
|
||||
return redirect('control:event.items',
|
||||
organizer=request.event.organizer.slug,
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
def item_move_down(request, organizer, event, item):
|
||||
item_move(request, item, up=False)
|
||||
return redirect('control:event.items',
|
||||
organizer=request.event.organizer.slug,
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
class CategoryForm(VersionedModelForm):
|
||||
|
||||
class Meta:
|
||||
@@ -159,6 +204,7 @@ def category_move(request, category, up=True):
|
||||
if cat.position != i:
|
||||
cat.position = i
|
||||
cat.save() # TODO: Clone or document sloppiness?
|
||||
messages.success(request, _('The order of categories as been updated.'))
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
|
||||
@@ -35,7 +35,7 @@ class EventIndex(EventViewMixin, CartDisplayMixin, TemplateView):
|
||||
'quotas', 'variations__quotas', 'quotas__event' # for .availability()
|
||||
).annotate(quotac=Count('quotas')).filter(
|
||||
quotac__gt=0
|
||||
).order_by('category__position', 'category_id', 'name')
|
||||
).order_by('category__position', 'category_id', 'position', 'name')
|
||||
|
||||
for item in items:
|
||||
item.available_variations = sorted(item.get_all_available_variations(),
|
||||
|
||||
Reference in New Issue
Block a user