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 URL handling works in pretalx.
Organiser panel views¶
If you want to add a custom view to the organiser area of an event, register an URL in your
urls.py that lives in the /orga/ subpath:
1from django.urls import re_path
2
3from pretalx.event.models.event import SLUG_REGEX
4
5from . import views
6
7urlpatterns = [
8 re_path(
9 rf"^orga/event/(?P<event>{SLUG_REGEX})/p/myplugin/$",
10 views.admin_view,
11 name="backend",
12 ),
13 re_path(
14 rf"^(?P<event>{SLUG_REGEX})/p/myplugin/$",
15 views.frontend_view,
16 name="frontend",
17 ),
18 re_path(
19 rf"^p/myplugin/$",
20 views.global_view,
21 name="global-frontend",
22 ),
23]
If you just created your urls.py file and you already had the development server running, you’ll now have to restart it for the new file to be recognised.
If your view is event-specific, you have to name one parameter in your URL
event. By convention, all plugin URLs except for backend URLs start with
a /p/ to avoid namespace collisions with event names and reserved URLs.
You can then write a regular view. Our middleware will automatically detect the
/orga/ subpath and will ensure the following points if this is an URL with
the event parameter:
The user has logged in
The
request.eventattribute contains the current eventThe user has permission to view the current event
If you want to require specific permission types, we provide you with a decorator or a mixin for your views:
from pretalx.common.mixins.views import PermissionRequired
class AdminView(PermissionRequired, View):
permission_required = "submission.orga_list_submission"
There is also a signal that allows you to add the view to the event sidebar navigation like this:
1from django.dispatch import receiver
2from django.urls import resolve, reverse
3from django.utils.translation import ugettext_lazy as _
4
5from pretalx.orga.signals import nav_event
6
7
8@receiver(nav_event, dispatch_uid="friends_tickets_nav")
9def navbar_info(sender, request, **kwargs):
10 url = resolve(request.path_info)
11 if not request.user.has_perm("event.orga_access_event", request.event):
12 return []
13 return [{
14 "label": _("My plugin view"),
15 "icon": "heart",
16 "url": reverse("plugins:myplugin:index", kwargs={
17 "event": request.event.slug,
18 }),
19 "active": url.namespace == "plugins:myplugin" and url.url_name == "view",
20 }]
Frontend views¶
Frontend views work pretty much like organiser area views. Take care that your
URL starts with fr"^(?P<event>[{SLUG_REGEX}]+)/p/mypluginname" for event
related URLs or f"^p/mypluginname" for global views. You can then write a
regular view. It will be automatically ensured that:
The requested event exists
The requested event is visible (either by being public, or if an organiser looks at it)
The request involves the correct domain for the event
The
request.eventattribute contains the correctEventobjectThe organiser has enabled the plugin
The locale middleware has processed the request
API views¶
You can also expose Django REST Framework API endpoints from your plugin.
Register your URLs with the api/events/<event>/p/<pluginname>/ prefix using
a DRF Router:
1from rest_framework import routers
2
3from pretalx.event.models.event import SLUG_REGEX
4
5from .api import MyViewSet
6
7router = routers.SimpleRouter()
8router.register(
9 f"api/events/(?P<event>{SLUG_REGEX})/p/myplugin",
10 MyViewSet,
11 basename="myplugin",
12)
13urlpatterns += router.urls
Your view should use ApiPermission & PluginPermission as its permission
classes. Set plugin_required to your plugin’s name so that the endpoint is
only available for events that have your plugin enabled. Access control is
handled by rules_permissions on your model:
1from rest_framework import serializers, viewsets
2from rules.contrib.models import RulesModelBase, RulesModelMixin
3
4from pretalx.api.permissions import ApiPermission, PluginPermission
5
6
7class MyModel(RulesModelMixin, models.Model, metaclass=RulesModelBase):
8 class Meta:
9 rules_permissions = {
10 "list": my_list_rule,
11 "create": my_create_rule,
12 "update": my_create_rule,
13 }
14
15
16class MySerializer(serializers.ModelSerializer):
17 class Meta:
18 model = MyModel
19 fields = ["id", "name"]
20
21
22class MyViewSet(viewsets.ModelViewSet):
23 serializer_class = MySerializer
24 queryset = MyModel.objects.none()
25 permission_classes = [ApiPermission & PluginPermission]
26 plugin_required = "pretalx_myplugin"
27
28 def get_queryset(self):
29 return MyModel.objects.filter(event=self.request.event)
Token-based API authentication (Authorization: Token <key>) works
automatically — the ApiPermission class skips the fine-grained endpoint
permission check for plugin views that don’t participate in the core endpoint
system, while still enforcing event access and object-level permissions via
Django rules.