Events
↑ Parent: MagiModel utils
← Previous: Customize views with MagiModel properties
Events are a common collection for MagiCircles websites, especially those about mobile games.
MagiCircles provides a bunch of abstract models and collections you can use to save some time and effort.
- Models:
- Collections:
- More:
${PROJECT}/models.py
:
from magi.abstract_models import BaseEvent
class Event(BaseEvent):
...
It contains:
- a name (translatable)
- a description (allowing markdown)
- a start date
- an end date
- an image
event.status
can be access to know the status of the event. For details of what status can be, see getEventStatus
in Python Utils.
The following variables can be set in your Event model to customize it:
-
STATUS_STARTS_WITHIN
: Number of days. By default,event.status
returns "starts_soon" 3 days before the start date. You can set the value to 0 to never get "starts_soon". -
STATUS_ENDS_WITHIN
: Number of days. By default,event.status
returns "ended_recently" 3 days after the end date. You can set the value to 0 to never get "ended_recently".
from collections import OrderedDict
VERSIONS = OrderedDict((
('JP', {
'translation': _('Japanese version'),
'prefix': 'jp_',
}),
('WW', {
'translation': _('Worldwide version'),
'prefix': 'ww_',
}),
))
VERSIONS
is an ordered dict with values being dicts containing:
Key | Value | Example | Default |
---|---|---|---|
translation |
Full version name | _('Japanese version') |
required |
prefix |
Prefix used for each field per version | jp_ |
required |
language |
Language in which this version is. You can also set languages (list) if there are multiple languages. |
ja |
All languages |
image |
Used in forms and filters when selecting a version | language/ja |
None |
icon |
Used in forms and filters when selecting a version | jp |
None |
timezone |
In which timezone should dates be displayed for this version? (In addition to local time) You can also set timezones (list) if you want to display multiple timezones. |
Asia/Tokyo |
Only local time gets displayed |
Here's a more complete example:
VERSIONS = OrderedDict((
('JP', {
'translation': _('Japanese version'),
'prefix': 'jp_',
'language': 'ja',
'image': 'language/ja',
'icon': 'jp',
'timezone': 'Asia/Tokyo',
}),
('WW', {
'translation': _('Worldwide version'),
'prefix': 'ww_',
'languages': [ 'en', 'fr' ],
'image': 'language/world',
'icon': 'world',
'timezone': 'UTC',
}),
))
To create an Event model using VERSIONS
, you'll need to call getBaseEventWithVersions
:
${PROJECT}/models.py
:
from magi.abstract_models import getBaseEventWithVersions
class Event(getBaseEventWithVersions(VERSIONS)):
...
Just like BaseEvent
, your Event model will contain:
- a name (translatable)
- a description (allowing markdown)
It also contains, for each version, using the prefix specified in VERSIONS
:
- a start date (Example:
ww_start_date
,jp_start_date
) - an end date (Example:
ww_end_date
,jp_end_date
)
If languages are specified for each version, it will contain, for each language for each version:
- an image (Example:
ww_en_image
,ww_th_image
,jp_ja_image
)
Otherwise, it will contain for each version:
- an image (Example:
ww_image
,jp_image
)
getBaseEventWithVersions
allows a few optional parameters:
Name | Description | Type |
---|---|---|
extra_fields |
Allows to add custom model fields per version.
|
ordered dict of field name -> lambda
|
extra_fields_per_language |
Allows to add custom model fields per language.
|
ordered dict of field name -> lambda
|
extra_utils |
Allows to specify your own utils per version, being properties, methods, or variables.
{ '{}duration': lambda _version_name, _version: property(lambda _s: _s.getDuration(_version_name)) }
|
ordered dict of field name -> lambda
|
fallbacks |
See Properties per version
|
dict of field name -> bool Ex: { '{}image': False } |
defaults |
See Utils per version and Properties per version
|
dict of field name -> default value Ex: { '{}image': 'default.png' } |
In this example, the list of cards given during an event varies depending on which version, so we want to have a cards field per version. We also have a "banner" that varies depending on which version AND language. We also want an utility property to check if the version has a start date.
${PROJECT}/models.py
:
from django.utils.translation import ugettext_lazy as _, string_concat
from magi.utils import getVerboseLanguage, uploadItem
from magi.versions_utils import getFieldNameForVersion
EVENT_EXTRA_FIELDS = OrderedDict([
('{}cards', lambda _version_name, _version: models.ManyToManyField(
Card, related_name=getFieldNameForVersion(u'{}events', _version), null=True,
verbose_name=string_concat(_version['translation'], ' - ', _('Cards')),
)),
])
EVENT_EXTRA_FIELDS_PER_LANGUAGE = OrderedDict([
('{}banner', lambda _version_name, _version, _language: models.ImageField(
string_concat(_version['translation'], ' - ', _('Banner'),' - ', getVerboseLanguage(_language)),
upload_to=uploadItem('events/banners/{}/{}'.format(_version_name, _language)), null=True,
)),
])
EVENT_EXTRA_UTILS = OrderedDict([
(u'{}has_start_date', lambda _version_name, _version: property(lambda _s: bool(_s.get_field_for_version('{}start_date', _version_name))),
class Event(getBaseEventWithVersions(
VERSIONS,
extra_fields=EVENT_EXTRA_FIELDS,
extra_fields_per_language=EVENT_EXTRA_FIELDS_PER_LANGUAGE,
extra_utils=EVENT_EXTRA_UTILS,
)):
...
Your Event model will also provide a few utility methods and properties for you:
All the default fields and custom fields will be available per version using their prefix as native model fields (extra_fields
). Ex: ww_start_date
.
The following utility properties are also available:
Name | Example | Description |
---|---|---|
{}name | ww_name |
When language or languages is specified in VERSIONS , will return the name of the event in the given version. When a version has multiple languages, it will automatically return the name in the most relevant language, based on the current user's language |
{}status | ww_status |
The status of the event in given version, see getEventStatus in Python Utils
|
All the fields with prefixes are also accessible without prefixes: when ww_start_date
and jp_start_date
exist, accessing relevant_start_date
will give you the most relevant start date based on what's more relevant for the current user.
These properties will automatically be available for all the fields, including the default ones and your custom ones (extra_fields
). These properties will automatically determine the relevant value to return within the available versions.
All the fields per language per version will also have a shortcut property. For example, if Worldwide version is available in English and Thai, you'll be able to access the images with ww_en_image
and ww_th_image
, but you'll also be able to access ww_image
: it will simply automatically determine which image to give you based on which version is more relevant to the current user.
event = models.Event.objects.get(pk=1)
print event.versions # [ "JP", "WW" ]
print event.relevant_versions # [ "WW" ]
print django.utils.translation.get_language() # "en"
event.image # will return value of ww_en_image
By default, if none of the "relevant" versions have a value, it will try to fallback to other versions that have a value.
This can be disabled by setting fallbacks
to False (as a parameter when calling getBaseEventWithVersions
) for the given field name. Finally, if no value is available in any version (or fallback is disabled), it will return what's in defaults
(as a parameter when calling getBaseEventWithVersions
) for the given field, or None
.
Name | Description |
---|---|
relevant_version |
The most relevant version for this event |
relevant_versions |
The most relevant versions for this event |
opened_versions |
Which versions would be opened by default when viewing the details of an event (item view). Opened versions checks for relevancy without taking into account which version(s) the current user plays or which language the current user prefers. |
relevant_name |
When language or languages is specified in VERSIONS , returns the most relevant name for this event by auto-detecting the most relevant language for the user |
versions_display_order |
List of versions, sorted by recommended display order (opened first, then other relevant versions, then all other versions) |
Name | Description | Example |
---|---|---|
VERSIONS |
The dict you provided with the details for each version | OrderedDict([('JP', { ...}, ]) |
FIELDS_PER_VERSION |
List of fields per version | ['{}start_date', '{}end_date'] |
ALL_FIELDS_PER_VERSION |
Actual fields names per version | ['jp_start_date', 'jp_end_date', 'ww_start_date', 'ww_end_date'] |
FIELDS_PER_VERSION_AND_LANGUAGE |
List of fields per language per version | ['{}image'] |
ALL_FIELDS_PER_VERSION_AND_LANGUAGE |
Actual fields names per language per version | ['jp_ja_image', 'ww_en_image', 'ww_th_image'] |
FIELDS_PER_VERSION_AND_LANGUAGE_BY_LANGUAGE |
Same, but as a dictionary per language | {'en': ['ww_en_image'], 'th': ['ww_th_image'], 'ja': ['jp_ja_image']} |
ALL_FIELDS_BY_VERSION |
Actual fields names of all the fields per version, including per language per version, as a dictionary per version | { 'JP': ['jp_start_date', 'jp_end_date', 'jp_ja_image'], 'WW': ['ww_start_date', 'ww_end_date', 'ww_en_image', 'ww_th_image'] } |
ALL_VERSION_FIELDS_BY_NAME |
Actual fields names by template field names of all the fields (per version or per version and language), as a dictionary | {'{}image': ['jp_ja_image', 'ww_en_image', 'ww_th_image'], '{}start_date': ['jp_start_date', 'ww_start_date']} |
get_{}_for_version
methods will automatically be available for all the default fields and custom fields (extra_fields
). These method take the version name as parameter and return the value for that version. They don't use defaults
, but you can call the method and follow it with or your_default_value
event = models.Event.objects.get(pk=1)
event.get_image_for_version('WW')
In addition, the following methods are available per version:
Name | Parameters | Description |
---|---|---|
get_name_for_version |
version_name | When language or languages is specified in VERSIONS , returns the most relevant name for this event and this version by auto-detecting the most relevant language for the user |
get_field_for_version |
field_name, version_name, get_value=None1, language=None | This is the same method called by the auto methods get_{}_for_version described above. |
get_status_for_version |
version_name | This is the same method called by the auto-properties {}_status described above. |
get_translated_values_for_version |
field_name, version_name | When language or languages is specified in VERSIONS , return all the values for a translated field in that version. For example, if WW version has languages ['en', 'th'] , then it will return the value in English and Thai. This is useful if you have other translated fields than the name that should still be displayed per version. |
get_values_per_languages_for_version |
field_name, version_name, get_value=None1 | Returns a dictionary with keys = languages, values = the value for that language and version |
get_value_of_relevant_language_for_version |
field_name, version_name, default=None | Returns the value for the most relevant language for a given version. |
get_relevant_translated_value_for_version |
field_name, version_name, fallback=False, default=None | For text fields with translations (like "name"), return the translated value for the most relevant language for a given version. This is useful if you have other translated fields than the name that should still be displayed per version. |
Name | Parameters | Description |
---|---|---|
get_relevant_name |
return_version=False | This is the same method called when accessing relevant_name , but allows an optional parameter to return the version name |
get_field_for_relevant_version |
field_name, default=None, get_value=None1</sup, return_version=False, fallback=True | Get the value of a field for the most relevant version. It's the same method called by the auto properties relevant_{} described above, but allows more flexibility using parameters. |
get_translated_value_for_relevant_version |
field_name, default=None, return_version=False | When language or languages is specified in VERSIONS , get the value of a translated field for the most relevant version by auto-detecting the most relevant language for the user |
These methods are directly available at the class level. In other words, you don't need an instance of the model to call them.
Name | Parameters | Description |
---|---|---|
get_version_name |
version_name | Returns the value of translation specified in VERSIONS for given version |
get_version_image |
version_name | Returns the value specified in VERSIONS for given version |
get_version_icon |
version_name | Returns the value specified in VERSIONS for given version |
get_field_name_for_version |
field_name, version_name | Returns the name of a field for a given version. For ex: models.Event.get_field_name_for_version('{}name', 'WW') will return "ww_name"
|
get_field_name_for_version_and_language |
field_name, version_name, language | Returns the name of a field for a given version and language. For ex: models.Event.get_field_name_for_version_and_language('{}image', 'WW', 'en') will return "ww_en_image"`. |
get_version_languages |
version_name | Returns the list of languages for a given version |
get_version_info |
version_name, field_name, default=None | Returns any field specified in VERSIONS . Fail safe. |
get_all_versions_field_names |
field_name | Returns all the actual field names for that field name: ['jp_start_date', 'ww_start_date'] (works with fields per version and language too) |
${PROJECT}/models.py
:
from magi.abstract_models import BaseEventParticipation
class EventParticipation(BaseEventParticipation):
...
The collection name is eventparticipation
.
It contains an account, and you need to add an event foreign key yourself.
class EventParticipation(BaseEventParticipation):
event = models.ForeignKey(Event, related_name='participations', verbose_name=_('Event'))
BaseEventCollection
only works with a model made from BaseEvent
(with or without versions).
${PROJECT}/magicollections.py
:
from magi.abstract_collections import BaseEventCollection as _BaseEventCollection
class EventCollection(_BaseEventCollection):
queryset = models.Event.objects.all()
ℹ️ For images, the same settings and methods are available! Just replace "icon" with "image".
- Available settings:
Key | Value | Default | Example |
---|---|---|---|
base_fields_icons | To use instead of fields_icons when setting icons. Make sure you extend the existing value instead of overriding it |
A bunch of icons already set |
base_fields_icons = _BaseEventCollection.base_fields_icons.copy() base_fields_icons.update({ 'boost_value': 'statistics' })
|
- Available settings:
Key | Value | Default | Example |
---|---|---|---|
base_fields_icons | To use instead of fields_icons when setting icons for fields that are not per version or language. Make sure you extend the existing value instead of overriding it |
A bunch of icons already set |
base_fields_icons = _BaseEventCollection.base_fields_icons.copy() base_fields_icons.update({ 'boost_value': 'statistics' })
|
fields_icons_per_version | Set icons for fields that are per version. Make sure you extend the existing value instead of overriding it | A bunch of icons already set |
fields_icons_per_version = _BaseEventCollection.fields_icons_per_version.copy() fields_icons_per_version.update({ '{}start_date': 'event' })
|
fields_icons_per_version_and_language | Same but for fields per version and language |
- Available methods (can be overridden):
Name | Description | Parameters | Return value | Default |
---|---|---|---|---|
get_fields_icons_per_version | Same as fields_icons_per_version but called dynamically | version_name, version | Dict | A bunch of icons already set |
get_fields_icons_per_version_and_language | Same but for fields per version and language | version_name, version, language |
The BaseEventCollection
comes with:
- a form class
- a filter form class (in list view)
The form class can be overridden like so:
${PROJECT}/forms.py
:
from magi.forms import to_EventForm as _to_EventForm
def to_EventForm(cls):
form_class = _to_EventForm(cls)
class _EventForm(form_class):
...
return _EventForm
${PROJECT}/magicollections.py
:
from . import forms
class EventCollection(_BaseEventCollection):
...
def to_form_class(self):
self._form_class = forms.to_EventForm(self)
To override the filter form class:
${PROJECT}/forms.py
:
from magi.forms import to_EventFilterForm as _to_EventFilterForm
def to_EventFilterForm(cls):
form_class = _to_EventFilterForm(cls)
class _EventFilterForm(form_class):
...
return _EventFilterForm
${PROJECT}/magicollections.py
:
class EventCollection(_BaseEventCollection):
class ListView(_BaseEventCollection.ListView):
def to_filter_form_class(self):
self._filter_form = forms.to_EventFilterForm(self)
- Item views contain the following settings (can be overriden):
Key | Value | Default | Example |
---|---|---|---|
fields_order_before | Because fields_order gets generated automatically based on relevant versions, you can set the order of all the other fields with this value. | ['name', 'c_versions'] | |
fields_exclude_before | To use instead of fields_exclude for fields that are not per version or per version and language. Make sure you extend it and not override it. |
[] | fields_exclude_before = _BaseEventCollection.ItemView.fields_exclude_before + ['boost_value'] |
fields_exclude_per_version | Will exclude given fields for all versions | [] | ['{}start_date'] |
fields_exclude_per_version_and_language | Will exclude given fields for all versions and languages | [] | ['{}image'] |
Assuming you have an EventParticipation model in ${PROJECT}/models.py
(see Abstract models), you can link it to your event collection like so:
${PROJECT}/magicollections.py
:
class EventCollection(_BaseEventCollection):
...
collectible = models.EventParticipation
A base event participation collection will get setup automatically.
Can be used with or without using the BaseEvent models.
from magi.utils import eventToCountDownField
Name | Description | Parameters | Return value |
---|---|---|---|
getRelevantVersion | Returns the most relevant version | request=None, exclude_versions=[], Either: (item=None) Or: (versions=None, versions_statuses=None) check_filtered_choice=True, check_status=True, check_accounts=True, check_language=True, fallback_to_first=True |
The name of the relevant version or None |
getRelevantVersions | Return the list of most relevant versions, order by relevance | Same as getRelevantVersion
|
List |
getAllVersionsOrderedByRelevance | Returns all the version names with relevant versions first | Same as getRelevantVersion
|
List |
sortByRelevantVersions | Changes the order of a queryset to sort by relevant version(s) | queryset, sorted_field_name='{}start_date' and the same parameters as getRelevantVersion
|
Queryset |
toCountDownField | Returns a countdown field that can be added to the list of fields displayed under an item in list view or item view, for example using get_extra_fields
|
date, field_name=None, verbose_name=None, sentence=None, classes=None, icon=None, image=None | dict (see MagiFields) |
eventToCountDownField | Auto-determines which date to display based on event status and returns a countdown field made using toCountDownField
|
start_date, end_date, field_name=None, verbose_name=None | dict (see MagiFields) |
Please also note that most methods available for event models also exist as standalone utility functions with a camel case equivalent.
Example:
from versions_utils import getFieldForRelevantVersion
event = models.Event.objects.get(id=1)
event.get_field_for_relevant_version('start_date')
getFieldForRelevantVersion(e, 'start_date') # will return the same thing as above
In order of relevancy:
- The current user is filtering the list of events by a certain version ("See all Worldwide events")
- The event in this version is currently running ("current")
- The event in this version starts soon or ended recently
- The current user plays that version (has an account with that version)
- The current user prefers a language in which that version exists (ex: Speaks Japanese and
jp
version is available in Japanese) - Fallback to first version specified in VERSIONS list
Please note that if you're calling functions to check which version(s) is/are relevant, some parameters are available to let you bypass some of these criterion.
1: get_value
is a lambda that transforms the value for you. It takes as parameters: item, version_name, version.
→ Next: Form utils
I. Introduction
II. Tutorials
III. References
- Files tree
- Default collections
- Default pages
- Website settings
- MagiCollection settings
- Abstract models
- Abstract collections
- MagiForm settings
- MagiFiltersForm settings
- Single pages settings
IV. Utils
-
MagiModel utils
- MagiModel images and files
- DateTime fields
- BaseAccount model
- Save choices values as integer rather than strings
- Store comma separated values
- Store dictionaries
- Store Markdown texts
- Translate fields values in multiple languages
- Store JSON
- More model field types
- Transform images before saving them
- Check choices at form level instead of model level
- Use an internal cache for foreign keys in models
- Customize views with MagiModel properties
- Events
- Form utils
- Python utils
- Templates utils
- Javascript utils
- Enable and disable existing collections and pages
- Translations
- Page titles and descriptions
- Characters
- Seasons
- Roles and permissions
- Allow your staff team to change configurations
- Custom users preferences and settings
- Background illustrations
- Activities tabs
- Corner popups
VI. More