Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Recipe locale and country selection many-to-many #39

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails if en-US is missing, make it a filter instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gah. I had a try/catch here, but removed it for easier debugging

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