mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
233 lines
8.6 KiB
ReStructuredText
233 lines
8.6 KiB
ReStructuredText
.. highlight:: python
|
|
:linenothreshold: 5
|
|
|
|
.. _`customview`:
|
|
|
|
Creating custom views
|
|
=====================
|
|
|
|
This page describes how to provide a custom view from within your plugin. Before you start
|
|
reading this page, please read and understand how :ref:`URL handling <urlconf>` works in
|
|
pretix.
|
|
|
|
Control panel views
|
|
-------------------
|
|
|
|
If you want to add a custom view to the control area of an event, just register an URL in your
|
|
``urls.py`` that lives in the ``/control/`` subpath:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.urls import re_path
|
|
|
|
from . import views
|
|
|
|
urlpatterns = [
|
|
re_path(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/mypluginname/',
|
|
views.admin_view, name='backend'),
|
|
]
|
|
|
|
It is required that your URL parameters are called ``organizer`` and ``event``. If you want to
|
|
install a view on organizer level, you can leave out the ``event``.
|
|
|
|
You can then implement the view as you would normally do. Our middleware will automatically
|
|
detect the ``/control/`` subpath and will ensure the following things if this is an URL with
|
|
both the ``event`` and ``organizer`` parameters:
|
|
|
|
* The user is logged in
|
|
* The ``request.event`` attribute contains the current event
|
|
* The ``request.organizer`` attribute contains the event's organizer
|
|
* The user has permission to access view the current event
|
|
|
|
If only the ``organizer`` parameter is present, it will be ensured that:
|
|
|
|
* The user is logged in
|
|
* The ``request.organizer`` attribute contains the event's organizer
|
|
* The user has permission to access view the current organizer
|
|
|
|
If you want to require specific permission types, we provide you with a decorator or a mixin for
|
|
your views:
|
|
|
|
.. code-block:: python
|
|
|
|
from pretix.control.permissions import (
|
|
event_permission_required, EventPermissionRequiredMixin
|
|
)
|
|
|
|
class AdminView(EventPermissionRequiredMixin, View):
|
|
permission = 'can_view_orders'
|
|
|
|
...
|
|
|
|
|
|
@event_permission_required('can_view_orders')
|
|
def admin_view(request, organizer, event):
|
|
...
|
|
|
|
Similarly, there is ``organizer_permission_required`` and ``OrganizerPermissionRequiredMixin``. In case of
|
|
event-related views, there is also a signal that allows you to add the view to the event navigation like this:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.urls import resolve, reverse
|
|
from django.dispatch import receiver
|
|
from django.utils.translation import gettext_lazy as _
|
|
from pretix.control.signals import nav_event
|
|
|
|
|
|
@receiver(nav_event, dispatch_uid='friends_tickets_nav')
|
|
def navbar_info(sender, request, **kwargs):
|
|
url = resolve(request.path_info)
|
|
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_vouchers'):
|
|
return []
|
|
return [{
|
|
'label': _('My plugin view'),
|
|
'icon': 'heart',
|
|
'url': reverse('plugins:myplugin:index', kwargs={
|
|
'event': request.event.slug,
|
|
'organizer': request.organizer.slug,
|
|
}),
|
|
'active': url.namespace == 'plugins:myplugin' and url.url_name == 'review',
|
|
}]
|
|
|
|
|
|
Event settings view
|
|
-------------------
|
|
|
|
A special case of a control panel view is a view hooked into the event settings page. For this case, there is a
|
|
special navigation signal:
|
|
|
|
.. code-block:: python
|
|
|
|
@receiver(nav_event_settings, dispatch_uid='friends_tickets_nav_settings')
|
|
def navbar_settings(sender, request, **kwargs):
|
|
url = resolve(request.path_info)
|
|
return [{
|
|
'label': _('My settings'),
|
|
'url': reverse('plugins:myplugin:settings', kwargs={
|
|
'event': request.event.slug,
|
|
'organizer': request.organizer.slug,
|
|
}),
|
|
'active': url.namespace == 'plugins:myplugin' and url.url_name == 'settings',
|
|
}]
|
|
|
|
Also, your view should inherit from ``EventSettingsViewMixin`` and your template from ``pretixcontrol/event/settings_base.html``
|
|
for good integration. If you just want to display a form, you could do it like the following:
|
|
|
|
.. code-block:: python
|
|
|
|
class MySettingsView(EventSettingsViewMixin, EventSettingsFormView):
|
|
model = Event
|
|
permission = 'can_change_settings'
|
|
form_class = MySettingsForm
|
|
template_name = 'my_plugin/settings.html'
|
|
|
|
def get_success_url(self, **kwargs):
|
|
return reverse('plugins:myplugin:settings', kwargs={
|
|
'organizer': self.request.event.organizer.slug,
|
|
'event': self.request.event.slug,
|
|
})
|
|
|
|
With this template::
|
|
|
|
{% extends "pretixcontrol/event/settings_base.html" %}
|
|
{% load i18n %}
|
|
{% load bootstrap3 %}
|
|
{% block title %} {% trans "Friends Tickets Settings" %} {% endblock %}
|
|
{% block inside %}
|
|
<form action="" method="post" class="form-horizontal">
|
|
{% csrf_token %}
|
|
<fieldset>
|
|
<legend>{% trans "Friends Tickets Settings" %}</legend>
|
|
{% bootstrap_form form layout="horizontal" %}
|
|
</fieldset>
|
|
<div class="form-group submit-group">
|
|
<button type="submit" class="btn btn-primary btn-save">
|
|
{% trans "Save" %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
{% endblock %}
|
|
|
|
Frontend views
|
|
--------------
|
|
|
|
Including a custom view into the participant-facing frontend is a little bit different as there is
|
|
no path prefix like ``control/``.
|
|
|
|
First, define your URL in your ``urls.py``, but this time in the ``event_patterns`` section and wrapped by
|
|
``event_url``:
|
|
|
|
.. code-block:: python
|
|
|
|
from pretix.multidomain import event_url
|
|
|
|
from . import views
|
|
|
|
event_patterns = [
|
|
event_url(r'^mypluginname/', views.frontend_view, name='frontend'),
|
|
]
|
|
|
|
You can then implement a view as you would normally do. It will be automatically ensured that:
|
|
|
|
* The requested event exists
|
|
* The requested event is active (you can disable this check using ``event_url(…, require_live=True)``)
|
|
* The event is accessed via the domain it should be accessed
|
|
* The ``request.event`` attribute contains the correct ``Event`` object
|
|
* The ``request.organizer`` attribute contains the correct ``Organizer`` object
|
|
* Your plugin is enabled
|
|
* The locale is set correctly
|
|
|
|
REST API viewsets
|
|
-----------------
|
|
|
|
Our REST API is built upon `Django REST Framework`_ (DRF). DRF has two important concepts that are different from
|
|
standard Django request handling: There are `ViewSets`_ to group related views in a single class and `Routers`_ to
|
|
automatically build URL configurations from them.
|
|
|
|
To integrate a custom viewset with pretix' REST API, you can just register with one of our routers within the
|
|
``urls.py`` module of your plugin:
|
|
|
|
.. code-block:: python
|
|
|
|
from pretix.api.urls import event_router, router, orga_router
|
|
|
|
router.register('global_viewset', MyViewSet)
|
|
orga_router.register('orga_level_viewset', MyViewSet)
|
|
event_router.register('event_level_viewset', MyViewSet)
|
|
|
|
Routes registered with ``router`` are inserted into the global API space at ``/api/v1/``. Routes registered with
|
|
``orga_router`` will be included at ``/api/v1/organizers/(organizer)/`` and routes registered with ``event_router``
|
|
will be included at ``/api/v1/organizers/(organizer)/events/(event)/``.
|
|
|
|
In case of ``orga_router`` and ``event_router``, permission checking is done for you similarly as with custom views
|
|
in the control panel. However, you need to make sure on your own only to return the correct subset of data! ``request
|
|
.event`` and ``request.organizer`` are available as usual.
|
|
|
|
To require a special permission like ``can_view_orders``, you do not need to inherit from a special ViewSet base
|
|
class, you can just set the ``permission`` attribute on your viewset:
|
|
|
|
.. code-block:: python
|
|
|
|
class MyViewSet(ModelViewSet):
|
|
permission = 'can_view_orders'
|
|
...
|
|
|
|
If you want to check the permission only for some methods of your viewset, you have to do it yourself. Note here that
|
|
API authentications can be done via user sessions or API tokens and you should therefore check something like the
|
|
following:
|
|
|
|
.. code-block:: python
|
|
|
|
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken) else request.user)
|
|
if perm_holder.has_event_permission(request.event.organizer, request.event, 'can_view_orders'):
|
|
...
|
|
|
|
|
|
.. warning:: It is important that you do this in the ``yourplugin.urls`` module, otherwise pretix will not find your
|
|
routes early enough during system startup.
|
|
|
|
.. _Django REST Framework: http://www.django-rest-framework.org/
|
|
.. _ViewSets: http://www.django-rest-framework.org/api-guide/viewsets/
|
|
.. _Routers: http://www.django-rest-framework.org/api-guide/routers/
|