Quickstart and Basic Usage¶
Django Entity Event is a great way to collect events that your users care about into a unified location. The parts of your code base that create these events are probably totally separate from the parts that display them, which are also separate from the parts that manage subscriptions to notifications. Django Entity Event makes separating these concerns as simple as possible, and provides convenient abstractions at each of these levels.
This quickstart guide handles the three parts of managing events and notifications.
- Creating, and categorizing events.
- Defining mediums and subscriptions.
- Querying events and presenting them to users.
If you are not already using Django Entity, this event framework won’t be particularly useful, and you should probably start by integrating Django Entity into your application.
Creating and Categorizing Events¶
Django Entity Event is structured such that all events come from a
Source, and can be displayed to the
user from a variety of mediums. When we’re creating events, we
don’t need to worry much about what
Medium the event will be displayed
on, we do need to know what the
Source of the events are.
Source objects are used to categorize
events. Categorizing events allows different types of events to be
consumed differently. So, before we can create an event, we need to
create a Source object. It is a good
idea to use sources to do fine grained categorization of events. To
provide higher level groupings, all sources must reference a
SourceGroup object. These objects are
very simple to create. Here we will make a single source group and two
different sources
from entity_event import Source, SourceGroup
yoursite_group = SourceGroup.objects.create(
name='yoursite',
display_name='Yoursite',
description='Events on Yoursite'
)
photo_source = Source.objects.create(
group=yoursite_group,
name='photo-tag',
display_name='Photo Tag',
description='You have been tagged in a photo'
)
product_source = Source.objects.create(
group=yoursite_group,
name='new-product',
display_name='New Product',
description='There is a new product on YourSite'
)
As seen above, the information required for these sources is fairly
minimal. It is worth noting that while we only defined a single
SourceGroup object, it will often
make sense to define more logical
SourceGroup objects.
Once we have sources defined, we can begin creating events. To create
an event we use the Event.objects.create_event method. To create an
event for the “photo-tag” group, we just need to know the source of
the event, what entities are involved, and some information about what
happened
from entity_event import Event
# Assume we're within the photo tag processing code, and we'll
# have access to variables entities_tagged, photo_owner, and
# photo_location
Event.objects.create_event(
source=photo_source,
actors=entities_tagged,
context={
'photo_owner': photo_owner
'photo_location': photo_location
}
)
The code above is all that’s required to store an event. While this is a fairly simple interface for creating events, in some applications it may be easier to read, and less intrusive in application code to use django-signals in the application code, and create events in signal handlers. In either case, We’re ready to discuss subscription management.
Managing Mediums and Subscriptions to Events¶
Once the events are created, we need to define how the users of our application are going to interact with the events. There are a large number of possible ways to notify users of events. Email, newsfeeds, notification bars, are all examples. Django Entity Event doesn’t handle the display logic for notifying users, but it does handle the subscription and event routing/querying logic that determines which events go where.
To start, we must define a Medium
object for each method our users will consume events from. Storing
Medium objects in the database has
two purposes. First, it is referenced when subscriptions are
created. Second the Medium objects
provide an entry point to query for events and have all the
subscription logic and filtering taken care of for you.
Like Source objects,
Medium objects are simple to create
from entity_event import Medium
email_medium = Medium.objects.create(
name="email",
display_name="Email",
description="Email Notifications"
)
newsfeed_medium = Medium.objects.create(
name="newsfeed",
display_name="NewsFeed",
description="Your personal feed of events"
)
At first, none of the events we have been creating are accessible by
either of these mediums. In order for the mediums to have access to
the events, an appropriate
Subscription object needs to be
created. Creating a Subscription
object encodes that an entity, or group of entities, wants to receive
notifications of events from a given source, by a given medium. For
example, we can create a subscription so that all the sub-entities of
an all_users entity will receive notifications of new products in
their newsfeed
from entity import EntityKind
from entity_event import Subscription
Subscription.objects.create(
medium=newsfeed_medium,
source=product_source,
entity=all_users,
sub_entity_kind=EntityKind.objects.get(name='user'),
only_following=False
)
With this Subscription object
defined, all events from the new product source will be available to
the newsfeed medium.
If we wanted to create a subscription for users to get email
notifications when they’ve been tagged in a photo, we will also create
a Subscription object. However,
unlike the new product events, not every event from the photos source
is relevant to every user. We want to limit the events they receive
emails about to the events where they are tagged in the photo.
In code above, you may notice the only_following=False
argument. This argument controls whether all events are relevant for
the subscription, or if the events are only relevant if they are
related to the entities being subscribed. Since new products are
relevant to all users, we set this to False. To create a
subscription for users to receive emails about photos they’re tagged
in, we’ll define the subscription as follows
Subscription.objects.create(
medium=email_medium,
source=photo_source,
entity=all_users,
sub_entity_kind=EntityKind.objects.get(name='user'),
only_following=True
)
This will only notify users if an entity they’re following is tagged in a photo. By default, entities follow themselves and their super entities.
Creating subscriptions for a whole group of people with a single entry
into the database is very powerful. However, some users may wish to
opt out of certain types of notifications. To accommodate this, we can
create an Unsubscription
object. These are used to unsubscribe a single entity from receiving
notifications of a given source on a given medium. For example if a
user wants to opt out of new product notifications in their newsfeed,
we can create an Unsubscription
object for them
from entity_event import Unsubscription
# Assume we have an entity, unsubscriber who wants to unsubscribe
Unsubscription.objects.create(
entity=unsubscriber,
source=product_source,
medium=newsfeed_medium
)
Once this object is stored in the database, this user will no longer receive this type of notification.
Once we have Medium objects set up
for the methods of sending notifications, and we have our entities
subscribed to sources of events on those mediums, we can use the
Medium objects to query for events,
which we can then display to our users.
Querying Events¶
Once we’ve got events being created, and subscriptions to them for a
given medium, we’ll want to display those events to our users. When
there are a large variety of events coming into the system from many
different sources, it would be very difficult to query the
Event model directly while still
respecting all the Subscription logic
that we hope to maintain.
For this reason, Django Entity Event provides three methods to make
querying for events` to display extremely simple. Since the
Medium objects you’ve created should
correspond directly to a means by which you want to display events to
users, there are three methods of the
Medium class to perform queries.
Medium.eventsMedium.entity_eventsMedium.events_targets
Each of these methods return somewhat different views into the events
that are being stored in the system. In each case, though, you will
call these methods from an instance of
Medium, and the events returned will
only be events for which there is a corresponding
Subscription object.
The Medium.events
method can be used to return all the events for that medium. This
method is useful for mediums that want to display events without any
particular regard for who performed the events. For example, we could
have a medium that aggregated all of the events from the new products
source. If we had a medium, all_products_medium, with the
appropriate subscriptions set up, getting all the new product events
is as simple as
all_products_medium.events()
The Medium.entity_events method can be used to get
all the events for a given entity on that medium. It takes a single
entity as an argument, and returns all the events for that entity on
that medium. We could use this method to get events for an individual
entity’s newsfeed. If we have a large number of sources creating
events, with subscriptions between those sources and the newsfeed,
aggregating them into one QuerySet of events is as simple as
newsfeed_medium.entity_events(user_entity)
There are some mediums that notify users of events independent of a
pageview’s request/response cycle. For example, an email medium will
want to process batches of events, and need information about who to
send the events to. For this use case, the
Medium.events_targets method can be
used. Instead of providing a EventQueryset, it provides a list of
tuples in the form (event, targets), where targets is a list
of the entities that should receive that notification. We could use
this function to send emails about events as follows
from django.core.mail import send_mail
new_emails = email_medium.events_targets(seen=False, mark_seen=True)
for event, targets in new_emails:
send_mail(
subject = event.context["subject"]
message = event.context["message"]
recipient_list = [t.entity_meta["email"] for t in targets]
)
As seen in the last example, these methods also support a number of arguments for filtering the events based on properties of the events themselves. All three methods support the following arguments:
start_time: providing a datetime object to this parameter will filter the events to only those that occurred at or after this time.end_time: providing a datetime object to this parameter will filter the events to only those that occurred at or before this time.seen: passingFalseto this argument will filter the events to only those which have not been marked as having been seen.include_expired: defaults toFalse, passingTrueto this argument will include events that are expired. Events with expiration are discussed increate_event().actor: providing an entity to this parameter will filter the events to only those that include the given entity as an actor.
Finally, all of these methods take an argument mark_seen. Passing
True to this argument will mark the events as having been seen by
that medium so they will not show up if False is passed to the
seen filtering argument.
Using these three methods with any combination of the event filters should make virtually any event querying task simple.