[PATCH v2 2/6] models: Add 'Event' model

Daniel Axtens dja at axtens.net
Tue Feb 7 08:11:57 AEDT 2017


Hi Stephen,

I'm reviewing this series as I get time, but one general question -
should any of this be hidden behind a config option? I'm wondering if
anyone who doesn't want REST or is nervous about the performance impact
might want to turn it off (or at least might want to be able to turn it
off).

Thoughts?

(Relatedly, I guess a patchwork benchmark might not be a bad idea - make
sure we don't regress catastrophically without noticing...)

Regards,
Daniel

Stephen Finucane <stephen at that.guru> writes:

> Events record Patch-related things like initial creation, state
> transitions, delegation assigning etc.
>
> Signed-off-by: Stephen Finucane <stephen at that.guru>
> ---
> v2:
> - 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 | 39 ++++++++++++
>  patchwork/models.py                          | 92 +++++++++++++++++++++++++++-
>  2 files changed, 129 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..7ec131b
> --- /dev/null
> +++ b/patchwork/migrations/0017_add_event_model.py
> @@ -0,0 +1,39 @@
> +# -*- coding: utf-8 -*-
> +# Generated by Django 1.10.5 on 2017-01-31 02:10
> +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.SmallIntegerField(choices=[(0, b'patch-created'), (1, b'patch-dependencies-met'), (2, b'patch-state-changed'), (3, b'patch-delegate-changed'), (4, b'patch-check-created'), (5, b'cover-letter-created'), (6, b'series-created')], help_text=b'The category of the event.')),
> +                ('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.Series')),
> +                ('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 0c7f72b..70bc319 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
> @@ -792,6 +793,93 @@ 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_PATCH_CREATED = 0
> +    CATEGORY_PATCH_DEPENDENCIES_MET = 1
> +    CATEGORY_PATCH_STATE_CHANGED = 2
> +    CATEGORY_PATCH_DELEGATE_CHANGED = 3
> +    CATEGORY_PATCH_CHECK_CREATED = 4
> +    CATEGORY_COVER_CREATED = 5
> +    CATEGORY_SERIES_CREATED = 6
> +    CATEGORY_CHOICES = (
> +        (CATEGORY_PATCH_CREATED, 'patch-created'),
> +        (CATEGORY_PATCH_DEPENDENCIES_MET, 'patch-dependencies-met'),
> +        (CATEGORY_PATCH_STATE_CHANGED, 'patch-state-changed'),
> +        (CATEGORY_PATCH_DELEGATE_CHANGED, 'patch-delegate-changed'),
> +        (CATEGORY_PATCH_CHECK_CREATED, 'patch-check-created'),
> +        (CATEGORY_COVER_CREATED, 'cover-letter-created'),
> +        (CATEGORY_SERIES_CREATED, 'series-created'),
> +    )
> +
> +    # parents
> +
> +    project = models.ForeignKey(
> +        Project, related_name='+',
> +        help_text='The project that the events belongs to.')
> +
> +    # event metadata
> +
> +    category = models.SmallIntegerField(
> +        choices=CATEGORY_CHOICES,
> +        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(
> +        Series, 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