Inline rules in the model admin
This commit is contained in:
39
src/personalisation/migrations/0026_auto_20161117_1201.py
Normal file
39
src/personalisation/migrations/0026_auto_20161117_1201.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.3 on 2016-11-17 11:01
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import django.db.models.deletion
|
||||||
|
import modelcluster.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalisation', '0025_auto_20161115_1310'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='abstractbaserule',
|
||||||
|
name='segment',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='referralrule',
|
||||||
|
name='segment',
|
||||||
|
field=modelcluster.fields.ParentalKey(default='', on_delete=django.db.models.deletion.CASCADE, related_name='referral_rules', to='personalisation.Segment'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='timerule',
|
||||||
|
name='segment',
|
||||||
|
field=modelcluster.fields.ParentalKey(default='', on_delete=django.db.models.deletion.CASCADE, related_name='time_rules', to='personalisation.Segment'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='visitcountrule',
|
||||||
|
name='segment',
|
||||||
|
field=modelcluster.fields.ParentalKey(default='', on_delete=django.db.models.deletion.CASCADE, related_name='visit_count_rules', to='personalisation.Segment'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@@ -12,67 +12,21 @@ from django.utils.functional import cached_property
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from modelcluster.fields import ParentalKey
|
from modelcluster.fields import ParentalKey
|
||||||
from modelcluster.models import ClusterableModel
|
from modelcluster.models import ClusterableModel
|
||||||
|
from polymorphic.models import PolymorphicModel
|
||||||
from wagtail.utils.decorators import cached_classmethod
|
from wagtail.utils.decorators import cached_classmethod
|
||||||
from wagtail.wagtailadmin.edit_handlers import (
|
from wagtail.wagtailadmin.edit_handlers import (FieldPanel, FieldRowPanel,
|
||||||
FieldPanel, MultiFieldPanel, ObjectList, PageChooserPanel, TabbedInterface)
|
InlinePanel, MultiFieldPanel,
|
||||||
|
ObjectList, PageChooserPanel,
|
||||||
|
TabbedInterface)
|
||||||
from wagtail.wagtailadmin.forms import WagtailAdminPageForm
|
from wagtail.wagtailadmin.forms import WagtailAdminPageForm
|
||||||
from wagtail.wagtailcore.models import Page
|
from wagtail.wagtailcore.models import Page
|
||||||
|
|
||||||
from personalisation.edit_handlers import ReadOnlyWidget
|
from personalisation.edit_handlers import ReadOnlyWidget
|
||||||
from polymorphic.models import PolymorphicModel
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Segment(ClusterableModel):
|
|
||||||
"""Model for a new segment"""
|
|
||||||
name = models.CharField(max_length=255)
|
|
||||||
create_date = models.DateTimeField(auto_now_add=True)
|
|
||||||
edit_date = models.DateTimeField(auto_now=True)
|
|
||||||
enable_date = models.DateTimeField(null=True, editable=False)
|
|
||||||
disable_date = models.DateTimeField(null=True, editable=False)
|
|
||||||
visit_count = models.PositiveIntegerField(default=0, editable=False)
|
|
||||||
STATUS_CHOICES = (
|
|
||||||
('enabled', 'Enabled'),
|
|
||||||
('disabled', 'Disabled'),
|
|
||||||
)
|
|
||||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="enabled")
|
|
||||||
|
|
||||||
panels = [
|
|
||||||
FieldPanel('name'),
|
|
||||||
FieldPanel('status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def encoded_name(self):
|
|
||||||
"""Returns a string with a slug for the segment"""
|
|
||||||
return slugify(self.name.lower())
|
|
||||||
|
|
||||||
|
|
||||||
def check_status_change(sender, instance, *args, **kwargs):
|
|
||||||
"""Check if the status has changed. Alter dates accordingly."""
|
|
||||||
try:
|
|
||||||
original_status = sender.objects.get(pk=instance.id).status
|
|
||||||
except sender.DoesNotExist:
|
|
||||||
original_status = ""
|
|
||||||
|
|
||||||
if original_status != instance.status:
|
|
||||||
if instance.status == "enabled":
|
|
||||||
instance.enable_date = datetime.now()
|
|
||||||
instance.visit_count = 0
|
|
||||||
return instance
|
|
||||||
if instance.status == "disabled":
|
|
||||||
instance.disable_date = datetime.now()
|
|
||||||
|
|
||||||
pre_save.connect(check_status_change, sender=Segment)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class AbstractBaseRule(PolymorphicModel):
|
class AbstractBaseRule(PolymorphicModel):
|
||||||
"""Base for creating rules to segment users with"""
|
"""Base for creating rules to segment users with"""
|
||||||
segment = ParentalKey('Segment', related_name="rules")
|
|
||||||
|
|
||||||
def test_user(self, request):
|
def test_user(self, request):
|
||||||
"""Test if the user matches this rule"""
|
"""Test if the user matches this rule"""
|
||||||
return True
|
return True
|
||||||
@@ -84,12 +38,15 @@ class AbstractBaseRule(PolymorphicModel):
|
|||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class TimeRule(AbstractBaseRule):
|
class TimeRule(AbstractBaseRule):
|
||||||
"""Time rule to segment users based on a start and end time"""
|
"""Time rule to segment users based on a start and end time"""
|
||||||
|
segment = ParentalKey('Segment', related_name="time_rules")
|
||||||
start_time = models.TimeField(_("Starting time"))
|
start_time = models.TimeField(_("Starting time"))
|
||||||
end_time = models.TimeField(_("Ending time"))
|
end_time = models.TimeField(_("Ending time"))
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
|
FieldRowPanel([
|
||||||
FieldPanel('start_time'),
|
FieldPanel('start_time'),
|
||||||
FieldPanel('end_time'),
|
FieldPanel('end_time'),
|
||||||
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -113,6 +70,7 @@ class TimeRule(AbstractBaseRule):
|
|||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class ReferralRule(AbstractBaseRule):
|
class ReferralRule(AbstractBaseRule):
|
||||||
"""Referral rule to segment users based on a regex test"""
|
"""Referral rule to segment users based on a regex test"""
|
||||||
|
segment = ParentalKey('Segment', related_name="referral_rules")
|
||||||
regex_string = models.TextField(_("Regex string to match the referer with"))
|
regex_string = models.TextField(_("Regex string to match the referer with"))
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
@@ -138,6 +96,7 @@ class ReferralRule(AbstractBaseRule):
|
|||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class VisitCountRule(AbstractBaseRule):
|
class VisitCountRule(AbstractBaseRule):
|
||||||
"""Visit count rule to segment users based on amount of visits"""
|
"""Visit count rule to segment users based on amount of visits"""
|
||||||
|
segment = ParentalKey('Segment', related_name="visit_count_rules")
|
||||||
OPERATOR_CHOICES = (
|
OPERATOR_CHOICES = (
|
||||||
('more_than', 'More than'),
|
('more_than', 'More than'),
|
||||||
('less_than', 'Less than'),
|
('less_than', 'Less than'),
|
||||||
@@ -154,9 +113,11 @@ class VisitCountRule(AbstractBaseRule):
|
|||||||
)
|
)
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
|
PageChooserPanel('counted_page'),
|
||||||
|
FieldRowPanel([
|
||||||
FieldPanel('operator'),
|
FieldPanel('operator'),
|
||||||
FieldPanel('count'),
|
FieldPanel('count'),
|
||||||
PageChooserPanel('counted_page'),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -194,6 +155,55 @@ class VisitCountRule(AbstractBaseRule):
|
|||||||
return '{} {}'.format(operator_display, self.count)
|
return '{} {}'.format(operator_display, self.count)
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class Segment(ClusterableModel):
|
||||||
|
"""Model for a new segment"""
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
create_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
edit_date = models.DateTimeField(auto_now=True)
|
||||||
|
enable_date = models.DateTimeField(null=True, editable=False)
|
||||||
|
disable_date = models.DateTimeField(null=True, editable=False)
|
||||||
|
visit_count = models.PositiveIntegerField(default=0, editable=False)
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
('enabled', 'Enabled'),
|
||||||
|
('disabled', 'Disabled'),
|
||||||
|
)
|
||||||
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="enabled")
|
||||||
|
|
||||||
|
panels = [
|
||||||
|
FieldPanel('name'),
|
||||||
|
FieldPanel('status'),
|
||||||
|
InlinePanel('time_rules', label="Time rule", min_num=None, max_num=1),
|
||||||
|
InlinePanel('referral_rules', label="Referral rule", min_num=None, max_num=1),
|
||||||
|
InlinePanel('visit_count_rules', label="Visit count rule", min_num=None, max_num=1),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def encoded_name(self):
|
||||||
|
"""Returns a string with a slug for the segment"""
|
||||||
|
return slugify(self.name.lower())
|
||||||
|
|
||||||
|
|
||||||
|
def check_status_change(sender, instance, *args, **kwargs):
|
||||||
|
"""Check if the status has changed. Alter dates accordingly."""
|
||||||
|
try:
|
||||||
|
original_status = sender.objects.get(pk=instance.id).status
|
||||||
|
except sender.DoesNotExist:
|
||||||
|
original_status = ""
|
||||||
|
|
||||||
|
if original_status != instance.status:
|
||||||
|
if instance.status == "enabled":
|
||||||
|
instance.enable_date = datetime.now()
|
||||||
|
instance.visit_count = 0
|
||||||
|
return instance
|
||||||
|
if instance.status == "disabled":
|
||||||
|
instance.disable_date = datetime.now()
|
||||||
|
|
||||||
|
pre_save.connect(check_status_change, sender=Segment)
|
||||||
|
|
||||||
|
|
||||||
class AdminPersonalisablePageForm(WagtailAdminPageForm):
|
class AdminPersonalisablePageForm(WagtailAdminPageForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AdminPersonalisablePageForm, self).__init__(*args, **kwargs)
|
super(AdminPersonalisablePageForm, self).__init__(*args, **kwargs)
|
||||||
|
@@ -14,19 +14,6 @@
|
|||||||
{% block form %}
|
{% block form %}
|
||||||
{{ edit_handler.render_form_content }}
|
{{ edit_handler.render_form_content }}
|
||||||
|
|
||||||
{% for form in additional_forms %}
|
|
||||||
<li class="object">
|
|
||||||
<h2>
|
|
||||||
<label for="{{ form.title }}">{{ form.title }}</label>
|
|
||||||
</h2>
|
|
||||||
<fieldset class="">
|
|
||||||
<p>{{ form.description }}</p>
|
|
||||||
<legend>{{ form.title }}</legend>
|
|
||||||
{{ form }}
|
|
||||||
</fieldset>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<li class="object">
|
<li class="object">
|
||||||
<h2>
|
<h2>
|
||||||
<label for="id_rules">Rules</label>
|
<label for="id_rules">Rules</label>
|
@@ -22,22 +22,12 @@ def register_admin_urls():
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SegmentCreateView(CreateView):
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'additional_forms': (TimeRuleForm, ReferralRuleForm, VisitCountRuleForm),
|
|
||||||
}
|
|
||||||
context.update(kwargs)
|
|
||||||
return super(SegmentCreateView, self).get_context_data(**context)
|
|
||||||
|
|
||||||
|
|
||||||
class SegmentModelAdmin(ModelAdmin):
|
class SegmentModelAdmin(ModelAdmin):
|
||||||
"""The base model for the Segments administration interface."""
|
"""The base model for the Segments administration interface."""
|
||||||
model = Segment
|
model = Segment
|
||||||
menu_icon = 'group'
|
menu_icon = 'group'
|
||||||
add_to_settings_menu = False
|
add_to_settings_menu = False
|
||||||
list_display = ('status', 'name', 'create_date', 'edit_date')
|
list_display = ('status', 'name', 'create_date', 'edit_date')
|
||||||
create_view_class = SegmentCreateView
|
|
||||||
index_view_extra_css = ['personalisation/segment/index.css']
|
index_view_extra_css = ['personalisation/segment/index.css']
|
||||||
form_view_extra_css = ['personalisation/segment/form.css']
|
form_view_extra_css = ['personalisation/segment/form.css']
|
||||||
inspect_view_enabled = True
|
inspect_view_enabled = True
|
||||||
|
Reference in New Issue
Block a user