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 modelcluster.fields import ParentalKey
|
||||
from modelcluster.models import ClusterableModel
|
||||
from polymorphic.models import PolymorphicModel
|
||||
from wagtail.utils.decorators import cached_classmethod
|
||||
from wagtail.wagtailadmin.edit_handlers import (
|
||||
FieldPanel, MultiFieldPanel, ObjectList, PageChooserPanel, TabbedInterface)
|
||||
from wagtail.wagtailadmin.edit_handlers import (FieldPanel, FieldRowPanel,
|
||||
InlinePanel, MultiFieldPanel,
|
||||
ObjectList, PageChooserPanel,
|
||||
TabbedInterface)
|
||||
from wagtail.wagtailadmin.forms import WagtailAdminPageForm
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
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
|
||||
class AbstractBaseRule(PolymorphicModel):
|
||||
"""Base for creating rules to segment users with"""
|
||||
segment = ParentalKey('Segment', related_name="rules")
|
||||
|
||||
def test_user(self, request):
|
||||
"""Test if the user matches this rule"""
|
||||
return True
|
||||
@@ -84,12 +38,15 @@ class AbstractBaseRule(PolymorphicModel):
|
||||
@python_2_unicode_compatible
|
||||
class TimeRule(AbstractBaseRule):
|
||||
"""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"))
|
||||
end_time = models.TimeField(_("Ending time"))
|
||||
|
||||
panels = [
|
||||
FieldRowPanel([
|
||||
FieldPanel('start_time'),
|
||||
FieldPanel('end_time'),
|
||||
]),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -113,6 +70,7 @@ class TimeRule(AbstractBaseRule):
|
||||
@python_2_unicode_compatible
|
||||
class ReferralRule(AbstractBaseRule):
|
||||
"""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"))
|
||||
|
||||
panels = [
|
||||
@@ -138,6 +96,7 @@ class ReferralRule(AbstractBaseRule):
|
||||
@python_2_unicode_compatible
|
||||
class VisitCountRule(AbstractBaseRule):
|
||||
"""Visit count rule to segment users based on amount of visits"""
|
||||
segment = ParentalKey('Segment', related_name="visit_count_rules")
|
||||
OPERATOR_CHOICES = (
|
||||
('more_than', 'More than'),
|
||||
('less_than', 'Less than'),
|
||||
@@ -154,9 +113,11 @@ class VisitCountRule(AbstractBaseRule):
|
||||
)
|
||||
|
||||
panels = [
|
||||
PageChooserPanel('counted_page'),
|
||||
FieldRowPanel([
|
||||
FieldPanel('operator'),
|
||||
FieldPanel('count'),
|
||||
PageChooserPanel('counted_page'),
|
||||
]),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -194,6 +155,55 @@ class VisitCountRule(AbstractBaseRule):
|
||||
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):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AdminPersonalisablePageForm, self).__init__(*args, **kwargs)
|
||||
|
@@ -14,19 +14,6 @@
|
||||
{% block form %}
|
||||
{{ 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">
|
||||
<h2>
|
||||
<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):
|
||||
"""The base model for the Segments administration interface."""
|
||||
model = Segment
|
||||
menu_icon = 'group'
|
||||
add_to_settings_menu = False
|
||||
list_display = ('status', 'name', 'create_date', 'edit_date')
|
||||
create_view_class = SegmentCreateView
|
||||
index_view_extra_css = ['personalisation/segment/index.css']
|
||||
form_view_extra_css = ['personalisation/segment/form.css']
|
||||
inspect_view_enabled = True
|
||||
|
Reference in New Issue
Block a user