Skip to content

Commit

Permalink
Make Recipe locale and country selection many-to-many
Browse files Browse the repository at this point in the history
Fixes bug 1248263.
  • Loading branch information
mythmon committed Feb 18, 2016
1 parent cf5c282 commit e526b52
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 9 deletions.
28 changes: 23 additions & 5 deletions normandy/recipes/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ class RecipeActionInline(SortableTabularInline):

@admin.register(models.Recipe)
class RecipeAdmin(NonSortableParentAdmin):
list_display = ['name', 'enabled', 'locale', 'country', 'start_time', 'end_time']
list_filter = ['enabled', 'locale', 'country']
search_fields = ['name', 'locale', 'country']
list_display = ['name', 'enabled', 'get_locales', 'get_countries', 'start_time', 'end_time']
search_fields = ['name', 'locales', 'countries']
inlines = [RecipeActionInline]
filter_horizontal = ['locales', 'countries']

list_filter = [
('enabled', admin.BooleanFieldListFilter),
('locales', admin.RelatedOnlyFieldListFilter),
('countries', admin.RelatedOnlyFieldListFilter),
]

fieldsets = [
[None, {
Expand All @@ -31,15 +37,27 @@ class RecipeAdmin(NonSortableParentAdmin):
['Delivery Rules', {
'fields': [
'enabled',
'locale',
'country',
'locales',
'countries',
'sample_rate',
'start_time',
'end_time',
]
}],
]

def get_locales(self, obj):
val = ', '.join(l.code for l in obj.locales.all())
if not val:
val = self.get_empty_value_display()
return val

def get_countries(self, obj):
val = ', '.join(l.name for l in obj.countries.all())
if not val:
val = self.get_empty_value_display()
return val


@admin.register(models.Action)
class ActionAdmin(admin.ModelAdmin):
Expand Down
55 changes: 55 additions & 0 deletions normandy/recipes/migrations/0016_auto_20160218_2024.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-18 20:24
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('recipes', '0015_auto_20160217_1819'),
]

operations = [
migrations.CreateModel(
name='Country',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=255, unique=True)),
('name', models.CharField(max_length=255)),
('order', models.IntegerField()),
],
options={
'ordering': ['order', 'name'],
},
),
migrations.AddField(
model_name='locale',
name='order',
field=models.IntegerField(default=100),
preserve_default=False,
),
migrations.RemoveField(
model_name='recipe',
name='country',
),
migrations.RemoveField(
model_name='recipe',
name='locale',
),
migrations.AddField(
model_name='recipe',
name='locales',
field=models.ManyToManyField(blank=True, to='recipes.Locale'),
),
migrations.AddField(
model_name='recipe',
name='countries',
field=models.ManyToManyField(blank=True, to='recipes.Country'),
),
migrations.AlterModelOptions(
name='locale',
options={'ordering': ['order', 'code']},
),
]
49 changes: 49 additions & 0 deletions normandy/recipes/migrations/0017_countries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-18 19:03
from __future__ import unicode_literals

from django.db import migrations

from django_countries import countries


def add_countries(apps, schema_editor):
Country = apps.get_model('recipes', 'Country')
for (code, name) in countries:
if code == 'US':
order = 0
else:
order = 100

Country.objects.update_or_create(code=code, defaults={
'name': name,
'order': order,
})


def remove_countries(apps, schema_editor):
Country = apps.get_model('recipes', 'Country')
Country.objects.all().delete()


def set_locale_sort_order(apps, schema_editor):
Locale = apps.get_model('recipes', 'Locale')
english = Locale.objects.get(code='en-US')
english.order = 0
english.save()


def noop(apps, schema_editor):
pass


class Migration(migrations.Migration):

dependencies = [
('recipes', '0016_auto_20160218_2024'),
]

operations = [
migrations.RunPython(add_countries, remove_countries),
migrations.RunPython(set_locale_sort_order, noop),
]
21 changes: 17 additions & 4 deletions normandy/recipes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django.db import models

from adminsortable.models import SortableMixin
from django_countries.fields import CountryField
from rest_framework.reverse import reverse

from normandy.recipes import utils
Expand All @@ -21,23 +20,37 @@ class Locale(models.Model):
code = models.CharField(max_length=255, unique=True)
english_name = models.CharField(max_length=255, blank=True)
native_name = models.CharField(max_length=255, blank=True)
order = models.IntegerField()

class Meta:
ordering = ['code']
ordering = ['order', 'code']

def __str__(self):
return '{self.code} ({self.english_name})'.format(self=self)


class Country(models.Model):
"""Database table for countries from django_countries."""
code = models.CharField(max_length=255, unique=True)
name = models.CharField(max_length=255)
order = models.IntegerField()

class Meta:
ordering = ['order', 'name']

def __str__(self):
return '{self.name} ({self.code})'.format(self=self)


class Recipe(models.Model):
"""A set of actions to be fetched and executed by users."""
name = models.CharField(max_length=255, unique=True)
actions = models.ManyToManyField('Action', through='RecipeAction')

# Fields that determine who this recipe is sent to.
enabled = models.BooleanField(default=False)
locale = models.ForeignKey(Locale, blank=True, null=True)
country = CountryField(blank=True, null=True, default=None)
locales = models.ManyToManyField(Locale, blank=True)
countries = models.ManyToManyField(Country, blank=True)
start_time = models.DateTimeField(blank=True, null=True, default=None)
end_time = models.DateTimeField(blank=True, null=True, default=None)
sample_rate = PercentField(default=100)
Expand Down
6 changes: 6 additions & 0 deletions normandy/recipes/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ def update(self, name, content, last_modified):
if name == 'languages.json':
languages = json.loads(content)
for locale_code, names in languages.items():
if locale_code == 'en-US':
order = 0
else:
order = 100

Locale.objects.update_or_create(code=locale_code, defaults={
'english_name': names['English'],
'native_name': names['native'],
'order': order,
})

# Remove obsolete locales.
Expand Down

0 comments on commit e526b52

Please sign in to comment.