Convert event from integer field to foreign key

This commit also fix conference creation for initial Site
This commit is contained in:
Élie Bouttier 2016-08-22 17:23:01 +02:00
parent 4049841028
commit 22a0fe3ca9
11 changed files with 155 additions and 14 deletions

View File

@ -7,3 +7,4 @@ class AccountsConfig(AppConfig):
def ready(self):
import accounts.signals # noqa
post_migrate.connect(accounts.signals.create_default_options, sender=self)

View File

@ -2,7 +2,7 @@ from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.contrib.sites.shortcuts import get_current_site
from django.db.models.signals import post_migrate, post_save
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_noop
@ -10,7 +10,6 @@ from django.utils.translation import ugettext_noop
from .models import Connector, Participation, Profile, Transport
@receiver(post_migrate)
def create_default_options(sender, **kwargs):
Transport.objects.get_or_create(name=ugettext_noop('Train'))
Transport.objects.get_or_create(name=ugettext_noop('Plane'))

View File

@ -6,7 +6,7 @@ from django.core import mail
from django.conf import settings
from accounts.models import Participation
from proposals.models import Topic, Talk
from proposals.models import Topic, Talk, Event
from .models import ConversationAboutTalk, ConversationWithParticipant, Message
@ -20,7 +20,8 @@ class ConversationTests(TestCase):
conversation, _ = ConversationWithParticipant.objects.get_or_create(participation=pa)
Message.objects.create(content='allo', conversation=conversation, author=b)
Message.objects.create(content='aluil', conversation=conversation, author=a)
Talk.objects.get_or_create(site=Site.objects.first(), proposer=a, title='a talk', description='yay')
site = Site.objects.first()
Talk.objects.get_or_create(site=site, proposer=a, title='a talk', description='yay', event=Event.objects.get(site=site, name='other'))
def test_models(self):
talk, participant, message = (model.objects.first() for model in

View File

@ -33,6 +33,9 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
# the post_migrate creating the first site should be call at first
'django.contrib.sites',
# our apps
'accounts',
'ponyconf',
@ -53,7 +56,6 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
]
MIDDLEWARE_CLASSES = [

View File

@ -0,0 +1 @@
default_app_config = 'proposals.apps.ProposalsConfig'

View File

@ -1,7 +1,23 @@
from django.contrib import admin
from proposals.models import Conference, Talk, Topic
from proposals.models import Conference, Talk, Topic, Event
class TalkAdmin(admin.ModelAdmin):
# Disable add button in django admin has it is too dangerous
# (it is easy to obtain incoherent data due to site framework)
def has_add_permission(self, request):
return False
# Filter for 'on site' tocpis and event
def get_form(self, request, obj=None, **kwargs):
form = super(TalkAdmin, self).get_form(request, obj, **kwargs)
# in fact, obj should never be none as 'add' button is disabled
if obj:
form.base_fields['topics'].queryset = Topic.objects.filter(site=obj.site)
form.base_fields['event'].queryset = Event.objects.filter(site=obj.site)
return form
admin.site.register(Conference)
admin.site.register(Topic)
admin.site.register(Talk)
admin.site.register(Talk, TalkAdmin)
admin.site.register(Event)

View File

@ -1,4 +1,5 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
class ProposalsConfig(AppConfig):
@ -6,3 +7,4 @@ class ProposalsConfig(AppConfig):
def ready(self):
import proposals.signals # noqa
post_migrate.connect(proposals.signals.call_first_site_post_save, sender=self)

View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-22 10:10
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
def migrate_event(apps, schema_editor):
db_alias = schema_editor.connection.alias
# Create default Event instance, as Site post_save is not triggered
Event = apps.get_model('proposals', 'Event')
Site = apps.get_model('sites', 'Site')
for site in Site.objects.using(db_alias).all():
Event.objects.using(db_alias).bulk_create([
Event(site=site, name='conference (short)'),
Event(site=site, name='conference (long)'),
Event(site=site, name='workshop'),
Event(site=site, name='stand'),
Event(site=site, name='other'),
])
# Migrate event_old field to event field
Talk = apps.get_model('proposals', 'Talk')
mapping = {
0: 'conference (short)',
1: 'conference (long)',
2: 'workshop',
3: 'stand',
4: 'other',
}
for talk in Talk.objects.using(db_alias).all():
talk.event = Event.objects.using(db_alias).get(site=talk.site, name=mapping[talk.event_old])
talk.save()
class Migration(migrations.Migration):
dependencies = [
('sites', '0002_alter_domain_unique'),
('proposals', '0009_auto_20160822_0921'),
]
operations = [
# Creation Event model
migrations.CreateModel(
name='Event',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64)),
('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
],
),
migrations.AlterUniqueTogether(
name='event',
unique_together=set([('site', 'name')]),
),
# Move field event to event_old
migrations.RenameField(
model_name='talk',
old_name='event',
new_name='event_old',
),
# Add field event as ForeignKey to Event model (with NULL allowed for now)
migrations.AddField(
model_name='talk',
name='event',
field=models.ForeignKey(to='proposals.Event', null=True),
),
# We slightly need to modify the ordering to work with the M2M
migrations.AlterModelOptions(
name='talk',
options={'ordering': ('event__id',)},
),
# Migrate the data from event_old field to event field
migrations.RunPython(migrate_event),
# Remove the event_old field as data have been migrated
migrations.RemoveField(
model_name='talk',
name='event_old',
),
# As data are now migrated, switch to null=False for event field
migrations.AlterField(
model_name='talk',
name='event',
field=models.ForeignKey(to='proposals.Event')
),
]

View File

@ -6,6 +6,7 @@ from django.core.urlresolvers import reverse
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from autoslug import AutoSlugField
@ -44,9 +45,19 @@ class Topic(PonyConfModel):
return reverse('list-talks-by-topic', kwargs={'topic': self.slug})
class Talk(PonyConfModel):
class Event(models.Model):
EVENTS = IntEnum('Event', 'conference_short conference_long workshop stand other')
site = models.ForeignKey(Site, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
class Meta:
unique_together = ('site', 'name')
def __str__(self):
return ugettext(self.name)
class Talk(PonyConfModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE)
@ -58,7 +69,7 @@ class Talk(PonyConfModel):
description = models.TextField(blank=True, verbose_name=_('Description'))
topics = models.ManyToManyField(Topic, blank=True, verbose_name=_('Topics'))
notes = models.TextField(blank=True, verbose_name=_('Notes'))
event = models.IntegerField(choices=enum_to_choices(EVENTS), default=EVENTS.conference_short.value, verbose_name=_('Format'))
event = models.ForeignKey(Event)
accepted = models.NullBooleanField(default=None)
def __str__(self):
@ -83,7 +94,7 @@ class Talk(PonyConfModel):
return query_sum(self.vote_set, 'vote')
class Meta:
ordering = ('event',)
ordering = ('event__id',)
class Vote(PonyConfModel):

View File

@ -1,10 +1,13 @@
from django.db.models.signals import m2m_changed, post_migrate, post_save
from django.db.models.signals import m2m_changed, post_save
from django.dispatch import Signal, receiver
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_noop
from django.conf import settings
from accounts.models import Participation
from .models import Conference, Talk, Topic
from .models import Conference, Talk, Topic, Event
talk_added = Signal(providing_args=["sender", "instance", "author"])
talk_edited = Signal(providing_args=["sender", "instance", "author"])
@ -15,6 +18,24 @@ def create_conference(sender, instance, **kwargs):
Conference.objects.get_or_create(site=instance)
@receiver(post_save, sender=Site, dispatch_uid="Create default events type for Site")
def create_events(sender, instance, **kwargs):
if not Event.objects.filter(site=instance).exists():
Event.objects.bulk_create([
Event(site=instance, name=ugettext_noop('conference (short)')),
Event(site=instance, name=ugettext_noop('conference (long)')),
Event(site=instance, name=ugettext_noop('workshop')),
Event(site=instance, name=ugettext_noop('stand')),
Event(site=instance, name=ugettext_noop('other')),
])
def call_first_site_post_save(apps, **kwargs):
site = Site.objects.filter(id=getattr(settings, 'SITE_ID', 1))
if site.exists():
site.first().save()
@receiver(m2m_changed, sender=Talk.speakers.through, dispatch_uid="Create Participation for speakers")
def create_participation_for_speakers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
if action != "pre_add":

View File

@ -14,7 +14,7 @@
<h3>{% trans "Format:" %}</h3>
<p>{{ talk.get_event_display }}</p>
<p>{{ talk.event }}</p>
<h3>{% trans "Abstract:" %}</h3>