Skip to content
This repository was archived by the owner on Oct 5, 2023. It is now read-only.

Commit 9df06f4

Browse files
authored
Use a django model for managing experiments (#24)
1 parent cb74c6b commit 9df06f4

14 files changed

+335
-110
lines changed

django_google_optimize/admin.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from django.contrib import admin
2+
3+
from .models import ExperimentVariant, GoogleExperiment
4+
5+
6+
class ExperimentVariantInline(admin.StackedInline):
7+
model = ExperimentVariant
8+
9+
10+
@admin.register(GoogleExperiment)
11+
class GoogleExperimentAdmin(admin.ModelAdmin):
12+
list_display = (
13+
"experiment_id",
14+
"experiment_alias",
15+
)
16+
inlines = [
17+
ExperimentVariantInline,
18+
]

django_google_optimize/middleware.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
from django.conf import settings
2-
31
from .utils import get_experiments_variants
42

5-
experiments = getattr(settings, "GOOGLE_OPTIMIZE_EXPERIMENTS", None)
6-
73

84
def google_optimize(get_response):
95
def middleware(request):
10-
request.google_optimize = get_experiments_variants(request, experiments)
6+
request.google_optimize = get_experiments_variants(request)
117
return get_response(request)
128

139
return middleware
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 3.0.2 on 2020-01-28 16:33
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
initial = True
10+
11+
dependencies = [
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name='GoogleExperiment',
17+
fields=[
18+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19+
('experiment_id', models.CharField(max_length=50, unique=True)),
20+
('experiment_alias', models.CharField(blank=True, max_length=30, null=True, unique=True)),
21+
('active', models.BooleanField()),
22+
],
23+
),
24+
migrations.CreateModel(
25+
name='ExperimentVariant',
26+
fields=[
27+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
28+
('index', models.IntegerField()),
29+
('alias', models.CharField(blank=True, max_length=50, null=True)),
30+
('experiment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='experiment_variant', to='django_google_optimize.GoogleExperiment')),
31+
],
32+
),
33+
migrations.AddConstraint(
34+
model_name='experimentvariant',
35+
constraint=models.UniqueConstraint(fields=('alias', 'experiment'), name='Can not have the same alias within an experiment_variant'),
36+
),
37+
migrations.AddConstraint(
38+
model_name='experimentvariant',
39+
constraint=models.UniqueConstraint(fields=('index', 'experiment'), name='Can not have the same index within an experiment_variant'),
40+
),
41+
]

django_google_optimize/migrations/__init__.py

Whitespace-only changes.

django_google_optimize/models.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from django.db import models
2+
3+
4+
class GoogleExperiment(models.Model):
5+
experiment_id = models.CharField(max_length=50, unique=True)
6+
experiment_alias = models.CharField(
7+
max_length=30, unique=True, blank=True, null=True
8+
)
9+
active = models.BooleanField()
10+
11+
12+
class ExperimentVariant(models.Model):
13+
index = models.IntegerField()
14+
alias = models.CharField(max_length=50, blank=True, null=True)
15+
experiment = models.ForeignKey(
16+
GoogleExperiment,
17+
null=True,
18+
blank=True,
19+
on_delete=models.CASCADE,
20+
related_name="experiment_variant",
21+
)
22+
23+
class Meta:
24+
constraints = [
25+
models.UniqueConstraint(
26+
fields=["alias", "experiment"],
27+
name="Can not have the same alias within an experiment_variant",
28+
),
29+
models.UniqueConstraint(
30+
fields=["index", "experiment"],
31+
name="Can not have the same index within an experiment_variant",
32+
),
33+
]

django_google_optimize/utils.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,64 @@
11
import logging
22

3+
from .models import GoogleExperiment
4+
35
logger = logging.getLogger()
46

57

6-
def get_experiments_variants(request, experiments):
8+
# pylint: disable=too-many-return-statements
9+
def get_experiments_variants(request):
10+
experiments = GoogleExperiment.objects.all()
711
if not experiments:
8-
logger.error("Setting GOOGLE_OPTIMIZE_EXPERIMENTS not defined")
12+
logger.warning("No experiment added")
913
return None
1014

1115
try:
12-
experiment_variants = _parse_experiments(request)
16+
cookie_data = _parse_experiments(request)
1317
except Exception: # pylint: disable=broad-except
14-
logger.error("Failed to parse _gaexp %s", request.COOKIES.get("_gaexp"))
18+
logger.warning("Failed to parse _gaexp %s", request.COOKIES.get("_gaexp"))
1519
return None
1620

17-
if not experiment_variants:
21+
if not cookie_data:
1822
logger.debug("Missing _ga_exp cookie")
1923
return None
2024

2125
active_experiments = {}
2226

2327
for experiment in experiments:
2428

25-
experiment_id = experiment.get("id", None)
26-
experiment_alias = experiment.get("alias", None)
27-
variant_aliases = experiment.get("variant_aliases", None)
28-
29-
if not experiment_id:
30-
logger.warning("experiment id not found in experiment settings")
31-
return None
29+
experiment_id = experiment.experiment_id
3230

33-
if experiment_id not in experiment_variants:
31+
if experiment_id not in cookie_data:
3432
logger.warning(
3533
"experiment id %s not found in experiments cookie %s",
3634
experiment_id,
3735
request.COOKIES["_gaexp"],
3836
)
3937
return None
4038

41-
variant = experiment_variants[experiment_id]
39+
variant_name = cookie_data[experiment_id]
4240

43-
if variant_aliases:
44-
if variant in variant_aliases:
45-
variant = variant_aliases[variant]
41+
experiment_variants = experiment.experiment_variant.all()
42+
43+
if experiment_variants:
44+
variant = experiment_variants.filter(index=variant_name).first()
45+
if variant:
46+
if variant.alias:
47+
variant_name = variant.alias
48+
else:
49+
logger.warning(
50+
"No experiment variant added with the index %s", variant_name
51+
)
52+
return None
53+
else:
54+
logger.warning("No variants added")
55+
return None
4656

57+
experiment_alias = experiment.experiment_alias
4758
if experiment_alias:
48-
active_experiments[experiment_alias] = variant
59+
active_experiments[experiment_alias] = variant_name
4960
else:
50-
active_experiments[experiment_id] = variant
61+
active_experiments[experiment_id] = variant_name
5162

5263
return active_experiments
5364

manage.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env python
2+
"""Django's command-line utility for administrative tasks."""
3+
import os
4+
import sys
5+
6+
7+
def main():
8+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
9+
try:
10+
from django.core.management import execute_from_command_line
11+
except ImportError as exc:
12+
raise ImportError(
13+
"Couldn't import Django. Are you sure it's installed and "
14+
"available on your PYTHONPATH environment variable? Did you "
15+
"forget to activate a virtual environment?"
16+
) from exc
17+
execute_from_command_line(sys.argv)
18+
19+
20+
if __name__ == "__main__":
21+
main()

0 commit comments

Comments
 (0)