[PATCH v3 4/9] models: Add 'Event' model
Daniel Axtens
dja at axtens.net
Fri Feb 24 15:54:19 AEDT 2017
Hi Stephen,
"CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph: (0017_add_event_model, 0017_improved_delegation_rule_docs in patchwork)."
The migration has will need to be renumbered before merging.
Regards,
Daniel
> Events record Patch-related things like initial creation, state
> transitions, delegation assigning etc.
>
> Signed-off-by: Stephen Finucane <stephen at that.guru>
> ---
> Changes since v2:
> - Add database indexes to speed up queries on these oft queried fields
> - Add new events
> - series-completed
> - Rename some events
> - patch-check-added -> check-added
> - patch-dependencies-met -> patch-completed
> Changes since v1:
> - Add new events
> - series-created
> - cover-created
> These require additional fields on the model
> - Rename some events to present a clear parent-child hierarchy
> ---
> patchwork/migrations/0017_add_event_model.py | 38 +++++++++++
> patchwork/models.py | 96 +++++++++++++++++++++++++++-
> 2 files changed, 132 insertions(+), 2 deletions(-)
> create mode 100644 patchwork/migrations/0017_add_event_model.py
>
> diff --git a/patchwork/migrations/0017_add_event_model.py b/patchwork/migrations/0017_add_event_model.py
> new file mode 100644
> index 0000000..db10713
> --- /dev/null
> +++ b/patchwork/migrations/0017_add_event_model.py
> @@ -0,0 +1,38 @@
> +# -*- coding: utf-8 -*-
> +from __future__ import unicode_literals
> +
> +import datetime
> +from django.conf import settings
> +from django.db import migrations, models
> +import django.db.models.deletion
> +
> +
> +class Migration(migrations.Migration):
> +
> + dependencies = [
> + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
> + ('patchwork', '0016_series_project'),
> + ]
> +
> + operations = [
> + migrations.CreateModel(
> + name='Event',
> + fields=[
> + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
> + ('category', models.CharField(choices=[(b'cover-created', b'Cover Letter Created'), (b'patch-created', b'Patch Created'), (b'patch-completed', b'Patch Completed'), (b'patch-state-changed', b'Patch State Changed'), (b'patch-delegated', b'Patch Delegate Changed'), (b'check-created', b'Check Created'), (b'series-created', b'Series Created'), (b'series-completed', b'Series Completed')], db_index=True, help_text=b'The category of the event.', max_length=20)),
> + ('date', models.DateTimeField(default=datetime.datetime.now, help_text=b'The time this event was created.')),
> + ('cover', models.ForeignKey(blank=True, help_text=b'The cover letter that this event was created for.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.CoverLetter')),
> + ('created_check', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.Check')),
> + ('current_delegate', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
> + ('current_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.State')),
> + ('patch', models.ForeignKey(blank=True, help_text=b'The patch that this event was created for.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.Patch')),
> + ('previous_delegate', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
> + ('previous_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.State')),
> + ('project', models.ForeignKey(help_text=b'The project that the events belongs to.', on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.Project')),
> + ('series', models.ForeignKey(blank=True, help_text=b'The series that this event was created for.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='patchwork.Series')),
> + ],
> + options={
> + 'ordering': ['-date'],
> + },
> + ),
> + ]
> diff --git a/patchwork/models.py b/patchwork/models.py
> index cf363f0..d9f7bec 100644
> --- a/patchwork/models.py
> +++ b/patchwork/models.py
> @@ -20,14 +20,15 @@
>
> from __future__ import absolute_import
>
> -from collections import Counter, OrderedDict
> +from collections import Counter
> +from collections import OrderedDict
> import datetime
> import random
> import re
>
> import django
> -from django.contrib.auth.models import User
> from django.conf import settings
> +from django.contrib.auth.models import User
> from django.contrib.sites.models import Site
> from django.core.urlresolvers import reverse
> from django.db import models
> @@ -793,6 +794,97 @@ class Check(models.Model):
> return '%s (%s)' % (self.context, self.get_state_display())
>
>
> +class Event(models.Model):
> + """An event raised against a patch.
> +
> + Events are created whenever certain attributes of a patch are
> + changed.
> +
> + This model makes extensive use of nullification of fields. This is more
> + performant than a solution using concrete subclasses while still providing
> + the integrity promises that foreign keys provide. Generic foreign keys
> + are another solution, but using these will result in a lot of massaging
> + should we wish to add support for an 'expand' paramter in the REST API in
> + the future. Refer to https://code.djangoproject.com/ticket/24272 for more
> + information.
> + """
> + CATEGORY_COVER_CREATED = 'cover-created'
> + CATEGORY_PATCH_CREATED = 'patch-created'
> + CATEGORY_PATCH_COMPLETED = 'patch-completed'
> + CATEGORY_PATCH_STATE_CHANGED = 'patch-state-changed'
> + CATEGORY_PATCH_DELEGATED = 'patch-delegated'
> + CATEGORY_CHECK_CREATED = 'check-created'
> + CATEGORY_SERIES_CREATED = 'series-created'
> + CATEGORY_SERIES_COMPLETED = 'series-completed'
> + CATEGORY_CHOICES = (
> + (CATEGORY_COVER_CREATED, 'Cover Letter Created'),
> + (CATEGORY_PATCH_CREATED, 'Patch Created'),
> + (CATEGORY_PATCH_COMPLETED, 'Patch Completed'),
> + (CATEGORY_PATCH_STATE_CHANGED, 'Patch State Changed'),
> + (CATEGORY_PATCH_DELEGATED, 'Patch Delegate Changed'),
> + (CATEGORY_CHECK_CREATED, 'Check Created'),
> + (CATEGORY_SERIES_CREATED, 'Series Created'),
> + (CATEGORY_SERIES_COMPLETED, 'Series Completed'),
> + )
> +
> + # parents
> +
> + project = models.ForeignKey(
> + Project, related_name='+', db_index=True,
> + help_text='The project that the events belongs to.')
> +
> + # event metadata
> +
> + category = models.CharField(
> + max_length=20,
> + choices=CATEGORY_CHOICES,
> + db_index=True,
> + help_text='The category of the event.')
> + date = models.DateTimeField(
> + default=datetime.datetime.now,
> + help_text='The time this event was created.')
> +
> + # event object
> +
> + # only one of the below should be used, depending on which category was
> + # used
> +
> + patch = models.ForeignKey(
> + Patch, related_name='+', null=True, blank=True,
> + help_text='The patch that this event was created for.')
> + series = models.ForeignKey(
> + Series, related_name='+', null=True, blank=True,
> + help_text='The series that this event was created for.')
> + cover = models.ForeignKey(
> + CoverLetter, related_name='+', null=True, blank=True,
> + help_text='The cover letter that this event was created for.')
> +
> + # fields for 'patch-state-changed' events
> +
> + previous_state = models.ForeignKey(
> + State, related_name='+', null=True, blank=True)
> + current_state = models.ForeignKey(
> + State, related_name='+', null=True, blank=True)
> +
> + # fields for 'patch-delegate-changed' events
> +
> + previous_delegate = models.ForeignKey(
> + User, related_name='+', null=True, blank=True)
> + current_delegate = models.ForeignKey(
> + User, related_name='+', null=True, blank=True)
> +
> + # fields or 'patch-check-created' events
> +
> + created_check = models.ForeignKey(
> + Check, related_name='+', null=True, blank=True)
> +
> + # TODO(stephenfin): Validate that the correct fields are being set by way
> + # of a 'clean' method
> +
> + class Meta:
> + ordering = ['-date']
> +
> +
> class EmailConfirmation(models.Model):
> validity = datetime.timedelta(days=settings.CONFIRMATION_VALIDITY_DAYS)
> type = models.CharField(max_length=20, choices=[
> --
> 2.9.3
>
> _______________________________________________
> Patchwork mailing list
> Patchwork at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/patchwork
More information about the Patchwork
mailing list