add manager for Related class; rename get_on_air as on_air + can retrieve by last logs instead of date
This commit is contained in:
		@ -648,7 +648,7 @@ class LogsPage(DatedListPage):
 | 
			
		||||
 | 
			
		||||
        logs = []
 | 
			
		||||
        for date in context['nav_dates']['dates']:
 | 
			
		||||
            items = self.station.get_on_air(date)
 | 
			
		||||
            items = self.station.on_air(date = date)
 | 
			
		||||
            items = [ self.as_item(item) for item in items ]
 | 
			
		||||
            logs.append((date, items))
 | 
			
		||||
        return logs
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,10 @@ from modelcluster.fields import ParentalKey
 | 
			
		||||
from modelcluster.tags import ClusterTaggableManager
 | 
			
		||||
from taggit.models import TaggedItemBase
 | 
			
		||||
 | 
			
		||||
# aircox
 | 
			
		||||
import aircox.programs.models as programs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def related_pages_filter(reset_cache=False):
 | 
			
		||||
    """
 | 
			
		||||
@ -398,12 +402,12 @@ class DatedListBase(models.Model):
 | 
			
		||||
        return [ first + tz.timedelta(days=i)
 | 
			
		||||
                    for i in range(0, self.nav_days) ]
 | 
			
		||||
 | 
			
		||||
    def get_date_context(self, date):
 | 
			
		||||
    def get_date_context(self, date = None):
 | 
			
		||||
        """
 | 
			
		||||
        Return a dict that can be added to the context to be used by
 | 
			
		||||
        a date_list.
 | 
			
		||||
        """
 | 
			
		||||
        today = tz.now().today()
 | 
			
		||||
        today = tz.now().date()
 | 
			
		||||
        if not date:
 | 
			
		||||
            date = today
 | 
			
		||||
 | 
			
		||||
@ -809,3 +813,41 @@ class SectionList(ListBase, SectionItem):
 | 
			
		||||
            )
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionTimetable(SectionItem,DatedListBase):
 | 
			
		||||
    panels = SectionItem.panels + DatedListBase.panels
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self, context):
 | 
			
		||||
        from aircox.cms.models import DiffusionPage
 | 
			
		||||
        diffs = []
 | 
			
		||||
        for date in context['nav_dates']['dates']:
 | 
			
		||||
            items = programs.Diffusion.objects.get_at(date).order_by('start')
 | 
			
		||||
            items = [ DiffusionPage.as_item(item) for item in items ]
 | 
			
		||||
            diffs.append((date, items))
 | 
			
		||||
        return diffs
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        context = super().get_context(request, page, *args, **kwargs)
 | 
			
		||||
        context.update(self.get_date_context())
 | 
			
		||||
        context['object_list'] = self.get_queryset(context)
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionLogs(SectionItem):
 | 
			
		||||
    count = models.SmallIntegerField(
 | 
			
		||||
        _('count'),
 | 
			
		||||
        default = 5,
 | 
			
		||||
        help_text = _('number of items to display in the list'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels + [
 | 
			
		||||
        FieldPanel('count'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,7 @@ class DiffusionsMenu(GenericMenu):
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return programs.Diffusion.objects.filter(
 | 
			
		||||
            type = programs.Diffusion.Type.normal,
 | 
			
		||||
            start__contains = tz.now().date() + tz.timedelta(days=2),
 | 
			
		||||
            start__contains = tz.now().date(),
 | 
			
		||||
        ).order_by('start')
 | 
			
		||||
 | 
			
		||||
    def get_title(self, item):
 | 
			
		||||
 | 
			
		||||
@ -150,7 +150,7 @@ class Station(programs.Nameable):
 | 
			
		||||
        * archive: if false, exclude log of diffusion's archives from
 | 
			
		||||
            the queryset;
 | 
			
		||||
        """
 | 
			
		||||
        qs = Log.get_for(model = models) \
 | 
			
		||||
        qs = Log.objects.get_for(model = models) \
 | 
			
		||||
                .filter(station = self, type = Log.Type.play)
 | 
			
		||||
        if not archives and self.dealer:
 | 
			
		||||
            qs = qs.exclude(
 | 
			
		||||
@ -161,45 +161,66 @@ class Station(programs.Nameable):
 | 
			
		||||
            )
 | 
			
		||||
        return qs.order_by('date')
 | 
			
		||||
 | 
			
		||||
    def get_on_air(self, date = None):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def __mix_logs_and_diff(diffs, logs, count = 0):
 | 
			
		||||
        """
 | 
			
		||||
        Return a list of what should have normally been on air at the
 | 
			
		||||
        given date, ordered descending on the diffusion time
 | 
			
		||||
        Mix together logs and diffusion items ordering by their date.
 | 
			
		||||
        Diffs and Logs are assumed to be ordered by -date, and so is
 | 
			
		||||
        the resulting list
 | 
			
		||||
        """
 | 
			
		||||
        # we fill a list with diff and retrieve logs that happened between
 | 
			
		||||
        # each to put them too there
 | 
			
		||||
        items = []
 | 
			
		||||
        diff_ = None
 | 
			
		||||
        for diff in diffs:
 | 
			
		||||
            logs_ = \
 | 
			
		||||
                logs.filter(date__gt = diff.end, date__lt = diff_.start) \
 | 
			
		||||
                    if diff_ else logs.filter(date__gt = diff.end)
 | 
			
		||||
            diff_ = diff
 | 
			
		||||
            items.extends(logs_)
 | 
			
		||||
            items.append(diff)
 | 
			
		||||
            if count and len(items) >= count:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if diff_ and not count or len(items) <= count:
 | 
			
		||||
            logs_ = logs.filter(date__lt = diff_.end)
 | 
			
		||||
            items.extend(logs_)
 | 
			
		||||
 | 
			
		||||
        return items[:count] if count else items
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def on_air(self, date = None, count = 0):
 | 
			
		||||
        """
 | 
			
		||||
        Return a list of what happened on air, based on logs and
 | 
			
		||||
        diffusions informations. The list is sorted by -date.
 | 
			
		||||
 | 
			
		||||
        * date: only for what happened on this date;
 | 
			
		||||
        * count: number of items to retrieve if not zero;
 | 
			
		||||
 | 
			
		||||
        Be careful with what you which for: the result is a plain list.
 | 
			
		||||
 | 
			
		||||
        The list contains:
 | 
			
		||||
        - track logs: for the streamed programs;
 | 
			
		||||
        - diffusion: for the scheduled diffusions;
 | 
			
		||||
        * track logs: for the streamed programs;
 | 
			
		||||
        * diffusion: for the scheduled diffusions;
 | 
			
		||||
        """
 | 
			
		||||
        # TODO: argument to get sound instead of tracks
 | 
			
		||||
        # FIXME: as an iterator?
 | 
			
		||||
        # TODO argument to get sound instead of tracks
 | 
			
		||||
        # TODO #Station
 | 
			
		||||
        date = date or tz.now().date()
 | 
			
		||||
        if date > datetime.date.today():
 | 
			
		||||
            return []
 | 
			
		||||
 | 
			
		||||
        logs = Log.get_for(model = programs.Track) \
 | 
			
		||||
                    .filter(date__contains = date) \
 | 
			
		||||
                    .order_by('date')
 | 
			
		||||
        diffs = programs.Diffusion.objects.get_at(date) \
 | 
			
		||||
                    .filter(type = programs.Diffusion.Type.normal) \
 | 
			
		||||
                    .order_by('start')
 | 
			
		||||
 | 
			
		||||
        # mix up
 | 
			
		||||
        items = []
 | 
			
		||||
        prev_diff = None
 | 
			
		||||
        for diff in diffs:
 | 
			
		||||
            logs_ = logs.filter(date__gt = prev_diff.end,
 | 
			
		||||
                                date__lt = diff.start) \
 | 
			
		||||
                    if prev_diff else \
 | 
			
		||||
                    logs.filter(date__lt = diff.start)
 | 
			
		||||
            prev_diff = diff
 | 
			
		||||
            items.extend(logs_)
 | 
			
		||||
            items.append(diff)
 | 
			
		||||
 | 
			
		||||
        # last logs
 | 
			
		||||
        if prev_diff:
 | 
			
		||||
            logs_ = logs.filter(date__gt = prev_diff.end)
 | 
			
		||||
            items.extend(logs_)
 | 
			
		||||
        return reversed(items)
 | 
			
		||||
 | 
			
		||||
        logs = Log.objects.get_for(model = programs.Track) \
 | 
			
		||||
                  .filter(station = self) \
 | 
			
		||||
                  .order_by('-date')
 | 
			
		||||
        diffs = programs.Diffusion.objects \
 | 
			
		||||
                    .filter(type = Diffusion.Type.normal) \
 | 
			
		||||
                    .order_by('-date')
 | 
			
		||||
        if date:
 | 
			
		||||
            logs = logs.filter(date__contains = date)
 | 
			
		||||
            diffs = diffs.get_at(date)
 | 
			
		||||
        return self.__mix_logs_and_diff(diffs, logs, count)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def save(self, make_sources = True, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ class Monitor:
 | 
			
		||||
        if not current_sound or not current_source:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        log = Log.get_for(model = programs.Sound) \
 | 
			
		||||
        log = Log.objects.get_for(model = programs.Sound) \
 | 
			
		||||
                    .filter(station = self.station).order_by('date').last()
 | 
			
		||||
 | 
			
		||||
        # only streamed
 | 
			
		||||
@ -92,11 +92,11 @@ class Monitor:
 | 
			
		||||
        Log tracks for the given sound (for streamed programs); Called by
 | 
			
		||||
        self.trace
 | 
			
		||||
        """
 | 
			
		||||
        logs = Log.get_for(model = programs.Track) \
 | 
			
		||||
        logs = Log.objects.get_for(model = programs.Track) \
 | 
			
		||||
                  .filter(pk__gt = log.pk)
 | 
			
		||||
        logs = [ log.related_id for log in logs ]
 | 
			
		||||
 | 
			
		||||
        tracks = programs.Track.get_for(object = log.related) \
 | 
			
		||||
        tracks = programs.Track.objects.get_for(object = log.related) \
 | 
			
		||||
                               .filter(in_seconds = True)
 | 
			
		||||
        if tracks and len(tracks) == len(logs):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,7 @@ class SoundInfo:
 | 
			
		||||
        if not os.path.exists(path):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        old = Track.get_for(object = sound)
 | 
			
		||||
        old = Track.objects.get_for(object = sound)
 | 
			
		||||
        if old:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,29 @@ def date_or_default(date, no_time = False):
 | 
			
		||||
    return date
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RelatedManager(models.Manager):
 | 
			
		||||
    def get_for(self, object = None, model = None):
 | 
			
		||||
        """
 | 
			
		||||
        Return a queryset that filter on the given object or model(s)
 | 
			
		||||
 | 
			
		||||
        * object: if given, use its type and pk; match on models only.
 | 
			
		||||
        * model: one model or an iterable of models
 | 
			
		||||
        """
 | 
			
		||||
        if not model and object:
 | 
			
		||||
            model = type(object)
 | 
			
		||||
 | 
			
		||||
        if hasattr(model, '__iter__'):
 | 
			
		||||
            model = [ ContentType.objects.get_for_model(m).id
 | 
			
		||||
                        for m in model ]
 | 
			
		||||
            qs = self.filter(related_type__pk__in = model)
 | 
			
		||||
        else:
 | 
			
		||||
            model = ContentType.objects.get_for_model(model)
 | 
			
		||||
            qs = self.filter(related_type__pk = model.id)
 | 
			
		||||
        if object:
 | 
			
		||||
            qs = qs.filter(related_id = object.pk)
 | 
			
		||||
        return qs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Related(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    Add a field "related" of type GenericForeignKey, plus utilities.
 | 
			
		||||
@ -60,28 +83,7 @@ class Related(models.Model):
 | 
			
		||||
        'related_type', 'related_id',
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_for(cl, object = None, model = None):
 | 
			
		||||
        """
 | 
			
		||||
        Return a queryset that filter on the given object or model(s)
 | 
			
		||||
 | 
			
		||||
        * object: if given, use its type and pk; match on models only.
 | 
			
		||||
        * model: one model or list of models
 | 
			
		||||
        """
 | 
			
		||||
        if not model and object:
 | 
			
		||||
            model = type(object)
 | 
			
		||||
 | 
			
		||||
        if type(model) in (list, tuple):
 | 
			
		||||
            model = [ ContentType.objects.get_for_model(m).id
 | 
			
		||||
                        for m in model ]
 | 
			
		||||
            qs = cl.objects.filter(related_type__pk__in = model)
 | 
			
		||||
        else:
 | 
			
		||||
            model = ContentType.objects.get_for_model(model)
 | 
			
		||||
            qs = cl.objects.filter(related_type__pk = model.id)
 | 
			
		||||
 | 
			
		||||
        if object:
 | 
			
		||||
            qs = qs.filter(related_id = object.pk)
 | 
			
		||||
        return qs
 | 
			
		||||
    objects = RelatedManager()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user