Compare commits
No commits in common. "7e6f0e377a7d2bc45eab28c3372c67da18325749" and "4aea8b281fd0dc571a92d67a45556be7691b52c4" have entirely different histories.
7e6f0e377a
...
4aea8b281f
|
@ -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 = f"{field_path}__"
|
self.field_generic = "%s__" % 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)
|
||||||
}
|
}
|
||||||
|
|
41
aircox/admin/mixins.py
Normal file
41
aircox/admin/mixins.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
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="__call__", args=False, kw=False):
|
def get_trace(self, name, 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="__call__", args=False, kw=False):
|
def get_traces(self, name, 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()`.
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
from datetime import date, timedelta
|
|
||||||
|
|
||||||
from django.contrib.admin import filters as d_filters
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from ..conftest import req_factory
|
|
||||||
from aircox import models
|
|
||||||
from aircox.admin import filters
|
|
||||||
|
|
||||||
|
|
||||||
class FakeFilter(d_filters.FieldListFilter):
|
|
||||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
|
||||||
self.field = field
|
|
||||||
self.request = request
|
|
||||||
self.params = params
|
|
||||||
self.model = model
|
|
||||||
self.model_admin = model_admin
|
|
||||||
self.field_path = field_path
|
|
||||||
|
|
||||||
|
|
||||||
class DateFieldFilter(filters.DateFieldFilter, FakeFilter):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
today = date.today()
|
|
||||||
tomorrow = date.today() + timedelta(days=1)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def req():
|
|
||||||
return req_factory.get("/test", {"pub_date__gte": today})
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def date_filter(req):
|
|
||||||
return DateFieldFilter(
|
|
||||||
models.Page._meta.get_field("pub_date"),
|
|
||||||
req,
|
|
||||||
{"pub_date__lte": tomorrow, "other_param": 13},
|
|
||||||
models.Page,
|
|
||||||
None,
|
|
||||||
"pub_date",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestDateFieldFilter:
|
|
||||||
def test___init__(self, date_filter):
|
|
||||||
assert date_filter.date_params == {"pub_date__lte": tomorrow}
|
|
||||||
|
|
||||||
date_filter.links = [
|
|
||||||
(str(link[0]), *list(link[1:])) for link in date_filter.links
|
|
||||||
]
|
|
||||||
assert date_filter.links == [
|
|
||||||
(str(_("None")), "pub_date__isnull", None, "1"),
|
|
||||||
(str(_("Exact")), "pub_date__date", date_filter.input_type),
|
|
||||||
(str(_("Since")), "pub_date__gte", date_filter.input_type),
|
|
||||||
(str(_("Until")), "pub_date__lte", date_filter.input_type),
|
|
||||||
]
|
|
||||||
assert date_filter.query_attrs == {
|
|
||||||
"pub_date__gte": today.strftime("%Y-%m-%d")
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@ 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
|
||||||
|
@ -12,10 +11,6 @@ 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)
|
||||||
|
@ -30,13 +25,8 @@ def logger():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def station():
|
def stations():
|
||||||
return baker.make(models.Station, audio_streams="stream 1\nstream 2")
|
return baker.make(models.Station, _quantity=2)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def stations(station):
|
|
||||||
return [station, baker.make(models.Station)]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -45,11 +35,7 @@ def programs(stations):
|
||||||
itertools.chain(
|
itertools.chain(
|
||||||
*(
|
*(
|
||||||
baker.make(
|
baker.make(
|
||||||
models.Program,
|
models.Program, station=station, cover=None, _quantity=2
|
||||||
station=station,
|
|
||||||
cover=None,
|
|
||||||
status=models.Program.STATUS_PUBLISHED,
|
|
||||||
_quantity=2,
|
|
||||||
)
|
)
|
||||||
for station in stations
|
for station in stations
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# Just for code quality: urls module is required because we need some
|
reqs = RequestFactory()
|
||||||
# url resolvers to be registered in order to run tests.
|
|
||||||
_urls
|
_urls
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +19,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 = req_factory.get("admin/test")
|
req = reqs.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,7 +48,9 @@ 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:
|
||||||
kwargs["audio_streams"] = self.station.streams
|
streams = self.station.audio_streams
|
||||||
|
streams = streams and streams.split("\n")
|
||||||
|
kwargs["audio_streams"] = streams
|
||||||
|
|
||||||
if "model" not in kwargs:
|
if "model" not in kwargs:
|
||||||
model = (
|
model = (
|
||||||
|
@ -61,7 +63,7 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
# FIXME: rename to sth like [Base]?StationAPIView/Mixin
|
# FIXME: rename to sth like [Base]?StationAPIView
|
||||||
class BaseAPIView:
|
class BaseAPIView:
|
||||||
@property
|
@property
|
||||||
def station(self):
|
def station(self):
|
||||||
|
|
|
@ -91,8 +91,6 @@ 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 into `aircox_streamer`: `Log`, `Port`
|
Move:
|
||||||
- move into `aircox_cms`: `Page`, `NavItem`, `Category`, `StaticPage`, etc.
|
- into `aircox_streamer`: `Log`, `Port`
|
||||||
- use TextChoice and IntegerChoices in models fields enums
|
- into `aircox_cms`: `Page`, `NavItem`, `Category`, `StaticPage`, etc.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user