@ -13,7 +13,7 @@ class DateFieldFilter(filters.FieldListFilter):
 | 
				
			|||||||
    input_type = "date"
 | 
					    input_type = "date"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, field, request, params, model, model_admin, field_path):
 | 
					    def __init__(self, field, request, params, model, model_admin, field_path):
 | 
				
			||||||
        self.field_generic = "%s__" % field_path
 | 
					        self.field_generic = f"{field_path}__"
 | 
				
			||||||
        self.date_params = {
 | 
					        self.date_params = {
 | 
				
			||||||
            k: v for k, v in params.items() if k.startswith(self.field_generic)
 | 
					            k: v for k, v in params.items() if k.startswith(self.field_generic)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,41 +0,0 @@
 | 
				
			|||||||
class UnrelatedInlineMixin:
 | 
					 | 
				
			||||||
    """Inline class that can be included in an admin change view whose model is
 | 
					 | 
				
			||||||
    not directly related to inline's model."""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    view_model = None
 | 
					 | 
				
			||||||
    parent_model = None
 | 
					 | 
				
			||||||
    parent_fk = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, parent_model, admin_site):
 | 
					 | 
				
			||||||
        self.view_model = parent_model
 | 
					 | 
				
			||||||
        super().__init__(self.parent_model, admin_site)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_parent(self, view_obj):
 | 
					 | 
				
			||||||
        """Get formset's instance from `obj` of AdminSite's change form."""
 | 
					 | 
				
			||||||
        field = self.parent_model._meta.get_field(self.parent_fk).remote_field
 | 
					 | 
				
			||||||
        return getattr(view_obj, field.name, None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def save_parent(self, parent, view_obj):
 | 
					 | 
				
			||||||
        """Save formset's instance."""
 | 
					 | 
				
			||||||
        setattr(parent, self.parent_fk, view_obj)
 | 
					 | 
				
			||||||
        parent.save()
 | 
					 | 
				
			||||||
        return parent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_formset(self, request, obj):
 | 
					 | 
				
			||||||
        ParentFormSet = super().get_formset(request, obj)
 | 
					 | 
				
			||||||
        inline = self
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class FormSet(ParentFormSet):
 | 
					 | 
				
			||||||
            view_obj = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def __init__(self, *args, instance=None, **kwargs):
 | 
					 | 
				
			||||||
                self.view_obj = instance
 | 
					 | 
				
			||||||
                instance = inline.get_parent(instance)
 | 
					 | 
				
			||||||
                self.instance = instance
 | 
					 | 
				
			||||||
                super().__init__(*args, instance=instance, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def save(self):
 | 
					 | 
				
			||||||
                inline.save_parent(self.instance, self.view_obj)
 | 
					 | 
				
			||||||
                return super().save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return FormSet
 | 
					 | 
				
			||||||
@ -121,7 +121,7 @@ class SpoofMixin:
 | 
				
			|||||||
        if funcs is not None:
 | 
					        if funcs is not None:
 | 
				
			||||||
            self.funcs = funcs
 | 
					            self.funcs = funcs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_trace(self, name, args=False, kw=False):
 | 
					    def get_trace(self, name="__call__", args=False, kw=False):
 | 
				
			||||||
        """Get a function call parameters.
 | 
					        """Get a function call parameters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param str name: function name
 | 
					        :param str name: function name
 | 
				
			||||||
@ -137,7 +137,7 @@ class SpoofMixin:
 | 
				
			|||||||
            raise ValueError(f"{name} called multiple times.")
 | 
					            raise ValueError(f"{name} called multiple times.")
 | 
				
			||||||
        return self._get_trace(trace, args=args, kw=kw)
 | 
					        return self._get_trace(trace, args=args, kw=kw)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_traces(self, name, args=False, kw=False):
 | 
					    def get_traces(self, name="__call__", args=False, kw=False):
 | 
				
			||||||
        """Get a tuple of all call parameters.
 | 
					        """Get a tuple of all call parameters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameters are the same as `get()`.
 | 
					        Parameters are the same as `get()`.
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import itertools
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
 | 
					from django.test import RequestFactory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from model_bakery import baker
 | 
					from model_bakery import baker
 | 
				
			||||||
@ -11,6 +12,10 @@ from aircox import models
 | 
				
			|||||||
from aircox.test import Interface
 | 
					from aircox.test import Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					req_factory = RequestFactory()
 | 
				
			||||||
 | 
					"""Request Factory used among different tests."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def staff_user():
 | 
					def staff_user():
 | 
				
			||||||
    return baker.make(User, is_active=True, is_staff=True)
 | 
					    return baker.make(User, is_active=True, is_staff=True)
 | 
				
			||||||
@ -25,8 +30,13 @@ def logger():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def stations():
 | 
					def station():
 | 
				
			||||||
    return baker.make(models.Station, _quantity=2)
 | 
					    return baker.make(models.Station, audio_streams="stream 1\nstream 2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def stations(station):
 | 
				
			||||||
 | 
					    return [station, baker.make(models.Station)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
@ -35,7 +45,11 @@ def programs(stations):
 | 
				
			|||||||
        itertools.chain(
 | 
					        itertools.chain(
 | 
				
			||||||
            *(
 | 
					            *(
 | 
				
			||||||
                baker.make(
 | 
					                baker.make(
 | 
				
			||||||
                    models.Program, station=station, cover=None, _quantity=2
 | 
					                    models.Program,
 | 
				
			||||||
 | 
					                    station=station,
 | 
				
			||||||
 | 
					                    cover=None,
 | 
				
			||||||
 | 
					                    status=models.Program.STATUS_PUBLISHED,
 | 
				
			||||||
 | 
					                    _quantity=2,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                for station in stations
 | 
					                for station in stations
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,14 @@
 | 
				
			|||||||
from django.urls import path, reverse
 | 
					from django.urls import path, reverse
 | 
				
			||||||
from django.test import RequestFactory
 | 
					 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aircox import admin_site, urls as _urls
 | 
					from aircox import admin_site, urls as _urls
 | 
				
			||||||
 | 
					from .conftest import req_factory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
reqs = RequestFactory()
 | 
					# Just for code quality: urls module is required because we need some
 | 
				
			||||||
 | 
					# url resolvers to be registered in order to run tests.
 | 
				
			||||||
_urls
 | 
					_urls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +20,7 @@ def site():
 | 
				
			|||||||
class TestAdminSite:
 | 
					class TestAdminSite:
 | 
				
			||||||
    @pytest.mark.django_db
 | 
					    @pytest.mark.django_db
 | 
				
			||||||
    def test_each_context(self, site, staff_user):
 | 
					    def test_each_context(self, site, staff_user):
 | 
				
			||||||
        req = reqs.get("admin/test")
 | 
					        req = req_factory.get("admin/test")
 | 
				
			||||||
        req.user = staff_user
 | 
					        req.user = staff_user
 | 
				
			||||||
        context = site.each_context(req)
 | 
					        context = site.each_context(req)
 | 
				
			||||||
        assert "programs" in context
 | 
					        assert "programs" in context
 | 
				
			||||||
 | 
				
			|||||||
@ -48,9 +48,7 @@ class BaseView(TemplateResponseMixin, ContextMixin):
 | 
				
			|||||||
                kwargs["sidebar_list_url"] = self.get_sidebar_url()
 | 
					                kwargs["sidebar_list_url"] = self.get_sidebar_url()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if "audio_streams" not in kwargs:
 | 
					        if "audio_streams" not in kwargs:
 | 
				
			||||||
            streams = self.station.audio_streams
 | 
					            kwargs["audio_streams"] = self.station.streams
 | 
				
			||||||
            streams = streams and streams.split("\n")
 | 
					 | 
				
			||||||
            kwargs["audio_streams"] = streams
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if "model" not in kwargs:
 | 
					        if "model" not in kwargs:
 | 
				
			||||||
            model = (
 | 
					            model = (
 | 
				
			||||||
@ -63,7 +61,7 @@ class BaseView(TemplateResponseMixin, ContextMixin):
 | 
				
			|||||||
        return super().get_context_data(**kwargs)
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME: rename to sth like [Base]?StationAPIView
 | 
					# FIXME: rename to sth like [Base]?StationAPIView/Mixin
 | 
				
			||||||
class BaseAPIView:
 | 
					class BaseAPIView:
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def station(self):
 | 
					    def station(self):
 | 
				
			||||||
 | 
				
			|||||||
@ -91,6 +91,8 @@ class AttachedToMixin:
 | 
				
			|||||||
        return super().get_page()
 | 
					        return super().get_page()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: django-filter provides filter mixin, but I don't remember why this is
 | 
				
			||||||
 | 
					# used.
 | 
				
			||||||
class FiltersMixin:
 | 
					class FiltersMixin:
 | 
				
			||||||
    """Mixin integrating Django filters' filter set."""
 | 
					    """Mixin integrating Django filters' filter set."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								notes.md
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								notes.md
									
									
									
									
									
								
							@ -76,6 +76,6 @@ cms:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# For the next version:
 | 
					# For the next version:
 | 
				
			||||||
## Refactorisation
 | 
					## Refactorisation
 | 
				
			||||||
Move:
 | 
					- move into `aircox_streamer`: `Log`, `Port`
 | 
				
			||||||
- into `aircox_streamer`: `Log`, `Port`
 | 
					- move into `aircox_cms`: `Page`, `NavItem`, `Category`, `StaticPage`, etc.
 | 
				
			||||||
- into `aircox_cms`: `Page`, `NavItem`, `Category`, `StaticPage`, etc.
 | 
					- use TextChoice and IntegerChoices in models fields enums
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user