Compare commits

..
71 Commits
Author SHA1 Message Date
Guido 8185c7edf6 typho 2024-07-15 22:48:29 +02:00
Guido 51862ad3ed logo e/o favicon potrebbero mancare! 2024-07-15 19:19:29 +02:00
Davide Borgonovo 0eed8c8679 Incremento di versione 2023-10-27 12:49:55 +02:00
Davide Borgonovo d74fcd4001 location messa nel windowRef, altrimenti non funzionava la modale 2023-10-27 12:49:25 +02:00
Guido 97e1a2b315 rendo invertibile questa migrazione 2023-06-21 22:38:51 +02:00
Pietro 45266906a3 pulsante logout in django 4 2023-05-22 16:14:40 +02:00
davide_borgonovo 5496f996be Fixes #1
Fixes #2
2023-03-14 16:54:05 +01:00
davide_borgonovo d85690fb9c Aggiunto default per quando un utente non ha un tema attivo assegnato o se è un non utente. In questo modo non usa un tema a caso ma quello settato come default 2023-01-30 15:08:33 +01:00
davide_borgonovo c44621dae1 Ho messo un attribute error che non era vero 2023-01-10 18:18:41 +01:00
davide_borgonovo 5f2e2982b1 Updated version 2022-12-27 10:44:46 +01:00
davide_borgonovo 1b0d20f494 Corretto il get_active_theme nel context_processor e nel modello 2022-12-27 10:43:38 +01:00
davide_borgonovo 7e85ebac9b Importo ImportMixin o non funziona 2022-11-22 10:09:05 +01:00
davide_borgonovo 95fb2df285 Import mixin non veniva usato 2022-11-22 10:05:38 +01:00
davide_borgonovo 363bc310a1 Aggiunta import dei temi con uno .zip 2022-10-27 16:12:11 +02:00
davide_borgonovo 2ee03fc2de Non so perchè non si era preso dentro queste modifiche nella migrazione 29 2022-10-26 10:25:58 +02:00
davide_borgonovo 74dacaba2c Updated version 2022-10-25 18:00:29 +02:00
davide_borgonovo 9272e6563b Tolto tema di default con Django e warning brutto 2022-10-25 17:59:57 +02:00
davide_borgonovo a96cede14f white-space: normal nello user-tools che altrimenti nella versione mobile tagliava i link in alto a dx 2022-09-14 14:34:35 +02:00
Guido 903417ab79 theme.env_name everywere 2022-09-13 19:04:50 +02:00
davide_borgonovo d76c64c2d6 Messa la migrazione che altrimenti voleva fare la prima volta che si faceva makemigrations. Mi era scapapto un verbose name 2022-08-26 11:23:12 +02:00
davide_borgonovo 4244b0b3ae Aggiornata versione 2022-04-28 18:34:52 +02:00
davide_borgonovo 7baffaf490 Ora più utenti possono avere lo stesso tema e li setto con una Inline 2022-04-28 18:34:28 +02:00
davide_borgonovo b8a160f746 Aggiornata versione 2022-03-15 17:59:01 +01:00
davide_borgonovo 5e3e3a1480 Revert "Converted dynamic inline CSS to external static CSS using CSS variables. #157 #93"
This reverts commit 8fe7178a13.
2022-03-15 17:56:03 +01:00
davide_borgonovo 7d649185cb Forkino per aggiungere modalità demo con un tema selezionato e per rendere il tema associabile ad un utente 2022-03-14 23:58:22 +01:00
Fabio Caccamo 3ff4f05e51 Update test-package.yml
Revert "Update test-package.yml"

This reverts commit d5cb8ff3fd09d43e3b2d333693b9fd97619a2b7f.

Update test-package.yml

Updated `create-matrix-action` version.

Update test-package.yml

Update test-package.yml

Update test-package.yml

Update test-package.yml
2022-03-10 15:50:09 +01:00
Fabio Caccamo d8cffd8c2c Updated CHANGELOG and version. 2022-03-09 10:14:57 +01:00
Mustafa M. A. U. AbuGhazy 8fe7178a13 Converted dynamic inline CSS to external static CSS using CSS variables. #157 #93 2022-03-09 10:14:57 +01:00
Fabio Caccamo d2b680e477 Update test-package.yml 2022-03-09 10:14:57 +01:00
Fabio Caccamo c07cad01e9 Updated CHANGELOG and version. 2022-02-24 10:24:45 +01:00
Fabio Caccamo 9c3798b155 Sorted imports. [ci skip] 2022-02-24 10:24:28 +01:00
MG Santos 06069644fd Removed public disclosures of the lib's version. #154 2022-02-22 16:22:19 +01:00
Fabio Caccamo f3e7fcef33 Delete label-sponsors.yml 2022-02-18 00:05:28 +01:00
Fabio Caccamo e64614274c Reformatted code with Black. 2022-02-08 18:58:59 +01:00
Fabio Caccamo 9b252d8577 Create label-sponsors.yml 2022-02-07 01:09:56 +01:00
Fabio Caccamo 1db3436e2a Updated CHANGELOG and version. 2022-02-04 22:06:34 +01:00
Fabio Caccamo 0f58934ae4 Updated translations. 2022-02-04 22:04:20 +01:00
Fabio Caccamo ec84ce8119 Added missing closing quote and parenthesis to polish translation. 2022-02-04 16:41:52 +01:00
Kamil 369c5582a6 Added Polish translation. #152 2022-02-04 14:35:51 +01:00
Fabio Caccamo 8c4ea1f749 Create dependabot.yml 2022-02-03 08:45:34 +01:00
leandromsd 7649fef2c2 Correcting spelling error (#151) 2022-01-28 14:17:57 +01:00
Fabio Caccamo 958996f119 Update test-package.yml 2022-01-27 23:26:30 +01:00
Fabio Caccamo 7719ac4277 Updated README. [ci skip] 2022-01-27 23:26:26 +01:00
Fabio Caccamo 8930ba1ddc Fixed login logo max-width and title color. 2022-01-21 14:17:09 +01:00
Fabio Caccamo ee63826836 Updated CHANGELOG and version. 2022-01-21 13:41:56 +01:00
Fabio Caccamo 7c0a105c92 Fixed body scroll reset to top when opening related modal. #150 2022-01-21 13:39:21 +01:00
Fabio Caccamo c8ababb8e4 Create SECURITY.md 2022-01-20 19:26:59 +01:00
leandromsdandLeandro Caixeta 384a63f76f Added portuguese brazil localization. #149
* add portuguese brazil language

* replace empty translations with the original text

Co-authored-by: Leandro Caixeta <leandro.caixeta@buser.com.br>
2022-01-20 13:39:38 +01:00
Fabio Caccamo f6c4d50bb3 Update test-package.yml 2022-01-17 22:11:05 +01:00
Fabio Caccamo 84c15d2b28 Update setup.py 2022-01-12 02:23:16 +01:00
Fabio Caccamo 6d46dfafc2 Updated version and CHANGELOG. 2022-01-05 18:48:55 +01:00
Micah Walter 3f076578bb Added link to admin home page on logo and title. #147 2022-01-05 18:31:07 +01:00
Fabio Caccamo cc4c379465 Fixed missing comma in tests settings MIDDLEWARE_CLASSES. #145 2022-01-04 18:16:53 +01:00
Fabio Caccamo c9f0795a95 Updated workflows.
- Added `create-release.yml` workflow.
- Renamed `pythonpackage.yml` to `test-package.yml`.
2021-12-22 21:56:47 +01:00
Fabio Caccamo 042e93a84b Fixed collapsed inlines rounded bottom borders. 2021-12-21 15:58:39 +01:00
Fabio Caccamo c9e800b5ab Updated README. #115 2021-12-15 11:14:29 +01:00
Fabio Caccamo 7257fbffb3 Merge branch 'master' of https://github.com/fabiocaccamo/django-admin-interface 2021-12-08 15:52:44 +01:00
Fabio Caccamo 1f690978bf Added django 4.0 to CI. 2021-12-08 15:52:41 +01:00
Fabio Caccamo 3d9cfd134d Update pythonpackage.yml 2021-12-07 21:07:33 +01:00
Fabio Caccamo 017f905330 Update pythonpackage.yml 2021-12-07 18:48:23 +01:00
Fabio Caccamo 796cea4a49 Updated CHANGELOG and version. [ci skip] 2021-12-07 11:08:57 +01:00
Fabio Caccamo 0178e0ccff Fixed check_installed_apps checks. 2021-12-07 10:59:57 +01:00
Fabio Caccamo 70ed000f08 Replaced travis with GitHub action workflow. #142 2021-12-07 10:43:46 +01:00
Éric 294f8520ab Fix django default appconfig deprecation warning (#141) 2021-12-06 22:33:33 +01:00
Fabio Caccamo 1b28c183f0 Update README.md 2021-12-06 21:19:21 +01:00
Fabio Caccamo 520dceaa97 Updated CHANGELOG and version. 2021-11-25 11:58:11 +01:00
Fabio Caccamo 2fa85eb964 Fixed migration error. 2021-11-25 11:58:00 +01:00
Fabio Caccamo 3bc6e6fe3b Revert "Removed wrong migration."
This reverts commit 8ded8e160b.
2021-11-25 11:55:57 +01:00
Fabio Caccamo 3dc31df5f1 Updated CHANGELOG and version. 2021-11-25 11:49:22 +01:00
Fabio Caccamo 8ded8e160b Removed wrong migration. 2021-11-25 11:49:13 +01:00
Fabio Caccamo f4e5662e49 Updated README.md. [ci skip] 2021-11-24 18:49:47 +01:00
90 changed files with 2911 additions and 1325 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
+29
View File
@@ -0,0 +1,29 @@
name: Create release
on:
push:
tags:
- '*.*.*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Extract release notes
id: extract-release-notes
uses: ffurrer2/extract-release-notes@v1
- name: Create release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
body: ${{ steps.extract-release-notes.outputs.release_notes }}
+93
View File
@@ -0,0 +1,93 @@
name: Test package
on:
push:
pull_request:
workflow_dispatch:
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Create matrix
uses: fabiocaccamo/create-matrix-action@v2
id: create_matrix
with:
matrix: |
python-version {2.7}, django-version {1.8,1.9,1.10,1.11}, database {sqlite,postgres}
python-version {3.6}, django-version {1.8,1.9,1.10,1.11,2.0,2.1,2.2,3.0,3.1,3.2}, database {sqlite,postgres}
python-version {3.7}, django-version {2.0,2.1,2.2,3.0,3.1,3.2}, database {sqlite,postgres}
python-version {3.8}, django-version {2.2,3.0,3.1,3.2}, database {sqlite,postgres}
python-version {3.9}, django-version {2.2,3.0,3.1,3.2}, database {sqlite,postgres}
python-version {3.10}, django-version {3.2,4.0}, database {sqlite,postgres}
outputs:
matrix: ${{ steps.create_matrix.outputs.matrix }}
test:
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{fromJson(needs.prepare.outputs.matrix)}}
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v2
- name: Install psycopg2 prerequisites
run: sudo apt-get install libpq-dev
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Upgrade pip version
run: |
pip install pip --upgrade
- name: Install django
run: |
pip install "Django ~= ${{ matrix.django-version }}"
- name: Install requirements
run: |
pip install -r requirements.txt
pip install -r requirements-test.txt
- name: Run tests
env:
DATABASE_ENGINE: ${{ matrix.database }}
run: |
coverage run --append --source=admin_interface setup.py test
coverage xml -o ./coverage.xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
fail_ci_if_error: false
files: ./coverage.xml
flags: unittests
verbose: true
+2
View File
@@ -56,3 +56,5 @@ docs/_build/
target/ target/
screenshots screenshots
TODO.txt TODO.txt
.idea/
-171
View File
@@ -1,171 +0,0 @@
os: linux
dist: xenial
language: python
cache: pip
jobs:
include:
- python: "2.7"
env: TOX_ENV=py27-dj17-sqlite
- python: "2.7"
env: TOX_ENV=py27-dj17-postgres
- python: "2.7"
env: TOX_ENV=py27-dj18-sqlite
- python: "2.7"
env: TOX_ENV=py27-dj18-postgres
- python: "2.7"
env: TOX_ENV=py27-dj19-sqlite
- python: "2.7"
env: TOX_ENV=py27-dj19-postgres
- python: "2.7"
env: TOX_ENV=py27-dj110-sqlite
- python: "2.7"
env: TOX_ENV=py27-dj110-postgres
- python: "2.7"
env: TOX_ENV=py27-dj111-sqlite
- python: "2.7"
env: TOX_ENV=py27-dj111-postgres
- python: "3.5"
env: TOX_ENV=py35-dj18-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj18-postgres
- python: "3.5"
env: TOX_ENV=py35-dj19-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj19-postgres
- python: "3.5"
env: TOX_ENV=py35-dj110-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj110-postgres
- python: "3.5"
env: TOX_ENV=py35-dj111-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj111-postgres
- python: "3.5"
env: TOX_ENV=py35-dj20-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj20-postgres
- python: "3.5"
env: TOX_ENV=py35-dj21-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj21-postgres
# - python: "3.5"
# env: TOX_ENV=py35-dj22-sqlite
- python: "3.5"
env: TOX_ENV=py35-dj22-postgres
- python: "3.6"
env: TOX_ENV=py36-dj111-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj111-postgres
- python: "3.6"
env: TOX_ENV=py36-dj20-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj20-postgres
- python: "3.6"
env: TOX_ENV=py36-dj21-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj21-postgres
- python: "3.6"
env: TOX_ENV=py36-dj22-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj22-postgres
- python: "3.6"
env: TOX_ENV=py36-dj30-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj30-postgres
- python: "3.6"
env: TOX_ENV=py36-dj31-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj31-postgres
- python: "3.6"
env: TOX_ENV=py36-dj32-sqlite
- python: "3.6"
env: TOX_ENV=py36-dj32-postgres
- python: "3.6"
env: TOX_ENV=py36-djmaster-sqlite
- python: "3.6"
env: TOX_ENV=py36-djmaster-postgres
- python: "3.7"
env: TOX_ENV=py37-dj20-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj20-postgres
- python: "3.7"
env: TOX_ENV=py37-dj21-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj21-postgres
- python: "3.7"
env: TOX_ENV=py37-dj22-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj22-postgres
- python: "3.7"
env: TOX_ENV=py37-dj30-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj30-postgres
- python: "3.7"
env: TOX_ENV=py37-dj31-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj31-postgres
- python: "3.7"
env: TOX_ENV=py37-dj32-sqlite
- python: "3.7"
env: TOX_ENV=py37-dj32-postgres
- python: "3.7"
env: TOX_ENV=py37-djmaster-sqlite
- python: "3.7"
env: TOX_ENV=py37-djmaster-postgres
- python: "3.8"
env: TOX_ENV=py38-dj22-sqlite
- python: "3.8"
env: TOX_ENV=py38-dj22-postgres
- python: "3.8"
env: TOX_ENV=py38-dj30-sqlite
- python: "3.8"
env: TOX_ENV=py38-dj30-postgres
- python: "3.8"
env: TOX_ENV=py38-dj31-sqlite
- python: "3.8"
env: TOX_ENV=py38-dj31-postgres
- python: "3.8"
env: TOX_ENV=py38-dj32-sqlite
- python: "3.8"
env: TOX_ENV=py38-dj32-postgres
- python: "3.8"
env: TOX_ENV=py38-djmaster-sqlite
- python: "3.8"
env: TOX_ENV=py38-djmaster-postgres
- python: "3.9"
env: TOX_ENV=py39-dj22-sqlite
- python: "3.9"
env: TOX_ENV=py39-dj22-postgres
- python: "3.9"
env: TOX_ENV=py39-dj30-sqlite
- python: "3.9"
env: TOX_ENV=py39-dj30-postgres
- python: "3.9"
env: TOX_ENV=py39-dj31-sqlite
- python: "3.9"
env: TOX_ENV=py39-dj31-postgres
- python: "3.9"
env: TOX_ENV=py39-dj32-sqlite
- python: "3.9"
env: TOX_ENV=py39-dj32-postgres
- python: "3.9"
env: TOX_ENV=py39-djmaster-sqlite
- python: "3.9"
env: TOX_ENV=py39-djmaster-postgres
allow_failures:
- env: TOX_ENV=py36-djmaster-sqlite
- env: TOX_ENV=py36-djmaster-postgres
- env: TOX_ENV=py37-djmaster-sqlite
- env: TOX_ENV=py37-djmaster-postgres
- env: TOX_ENV=py38-djmaster-sqlite
- env: TOX_ENV=py38-djmaster-postgres
- env: TOX_ENV=py39-djmaster-sqlite
- env: TOX_ENV=py39-djmaster-postgres
install:
- pip install tox
services:
- postgresql
before_script:
- psql -c 'create database admin_interface;' -U postgres
script:
- tox -e $TOX_ENV
+33
View File
@@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.19.0](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.19.0) - 2022-03-08
- Converted dynamic inline CSS to external static CSS using CSS variables. #157 #93 (thanks to [@Mustafa-Abu-Ghazy](https://github.com/Mustafa-Abu-Ghazy))
## [0.18.7](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.7) - 2022-02-24
- Removed public disclosures of the lib's version. #154 (thanks to [@mintyPT](https://github.com/mintyPT))
- Reformatted code with **Black**.
## [0.18.6](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.6) - 2022-02-04
- Added polish (`pl`) localization by [paduszyk](https://github.com/paduszyk). #152
- Fixed login logo `max-width` and title `color`.
## [0.18.5](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.5) - 2022-01-21
- Added portuguese brazil (`pt_BR`) localization by [leandromsd](https://github.com/leandromsd). #149
- Fixed body scroll reset to top when opening related modal. #150
## [0.18.4](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.4) - 2022-01-05
- Added official django 4.0 support.
- Added link to admin home page on logo and title. #147
- Fixed collapsed inlines rounded bottom borders.
- Fixed missing comma in tests settings `MIDDLEWARE_CLASSES`. #145
## [0.18.3](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.3) - 2021-12-07
- Added official python 3.10 support.
- Replaced travis with GitHub action workflow. #142
- Fixed `check_installed_apps` checks.
- Fixed django default appconfig deprecation warning. #141
## [0.18.2](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.2) - 2021-10-25
- Fixed migration error.
## [0.18.1](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.1) - 2021-10-25
- Removed wrong migration.
## [0.18.0](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.0) - 2021-10-24 ## [0.18.0](https://github.com/fabiocaccamo/django-admin-interface/releases/tag/0.18.0) - 2021-10-24
- Added foldable apps support. #117 - Added foldable apps support. #117
- Removed `css` field from `Theme` model. - Removed `css` field from `Theme` model.
+73 -34
View File
@@ -2,22 +2,24 @@
[![](https://img.shields.io/pypi/djversions/django-admin-interface?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/) [![](https://img.shields.io/pypi/djversions/django-admin-interface?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
[![](https://img.shields.io/pypi/v/django-admin-interface.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-admin-interface/) [![](https://img.shields.io/pypi/v/django-admin-interface.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-admin-interface/)
[![](https://pepy.tech/badge/django-admin-interface)](https://pepy.tech/project/django-admin-interface) [![](https://pepy.tech/badge/django-admin-interface/month)](https://pepy.tech/project/django-admin-interface)
[![](https://img.shields.io/github/stars/fabiocaccamo/django-admin-interface?logo=github)](https://github.com/fabiocaccamo/django-admin-interface/) [![](https://img.shields.io/github/stars/fabiocaccamo/django-admin-interface?logo=github)](https://github.com/fabiocaccamo/django-admin-interface/)
[![](https://badges.pufler.dev/visits/fabiocaccamo/django-admin-interface?label=visitors&color=blue)](https://badges.pufler.dev) [![](https://badges.pufler.dev/visits/fabiocaccamo/django-admin-interface?label=visitors&color=blue)](https://badges.pufler.dev)
[![](https://img.shields.io/pypi/l/django-admin-interface.svg?color=blue)](https://github.com/fabiocaccamo/django-admin-interface/blob/master/LICENSE.txt) [![](https://img.shields.io/pypi/l/django-admin-interface.svg?color=blue)](https://github.com/fabiocaccamo/django-admin-interface/blob/master/LICENSE.txt)
[![](https://img.shields.io/travis/fabiocaccamo/django-admin-interface?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-admin-interface) [![](https://img.shields.io/github/workflow/status/fabiocaccamo/django-admin-interface/Test%20package?label=build&logo=github)](https://github.com/fabiocaccamo/django-admin-interface)
[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-admin-interface?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-admin-interface) [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-admin-interface?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-admin-interface)
[![](https://img.shields.io/codacy/grade/21cb657283c04e70b56fb935277a1ad1?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-admin-interface) [![](https://img.shields.io/codacy/grade/21cb657283c04e70b56fb935277a1ad1?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-admin-interface)
[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-admin-interface?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-admin-interface/) [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-admin-interface?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-admin-interface/)
[![](https://requires.io/github/fabiocaccamo/django-admin-interface/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-admin-interface/requirements/?branch=master) [![](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
# django-admin-interface # django-admin-interface
django-admin-interface is a modern **responsive flat admin interface customizable by the admin itself**. django-admin-interface is a modern **responsive flat admin interface customizable by the admin itself**.
![django-admin-interface-preview](https://user-images.githubusercontent.com/1035294/35631521-64b0cab8-06a4-11e8-8f57-c04fdfbb7e8b.gif) ![django-admin-interface-preview](https://user-images.githubusercontent.com/1035294/35631521-64b0cab8-06a4-11e8-8f57-c04fdfbb7e8b.gif)
---
## Features ## Features
- Beautiful default **django-theme** - Beautiful default **django-theme**
- Themes management and customization *(you can **customize admin title, logo and colors**)* - Themes management and customization *(you can **customize admin title, logo and colors**)*
@@ -26,6 +28,7 @@ django-admin-interface is a modern **responsive flat admin interface customizabl
- Environment name/marker - Environment name/marker
- Language chooser - Language chooser
- List filter dropdown - List filter dropdown
- `NEW` **Foldable apps** *(accordions in the navigation bar)*
- `NEW` **List filter sticky** - `NEW` **List filter sticky**
- `NEW` **Form controls sticky** *(pagination and save/delete buttons)* - `NEW` **Form controls sticky** *(pagination and save/delete buttons)*
- Compatibility / Style optimizations for: - Compatibility / Style optimizations for:
@@ -36,59 +39,63 @@ django-admin-interface is a modern **responsive flat admin interface customizabl
- `django-tabbed-admin` - `django-tabbed-admin`
- `sorl-thumbnail` - `sorl-thumbnail`
---
## Installation ## Installation
- Run `pip install django-admin-interface` - Run `pip install django-admin-interface`
- Add `admin_interface`, `flat_responsive`, `flat` and `colorfield` to `settings.INSTALLED_APPS` **before** `django.contrib.admin` - Add `admin_interface`, `flat_responsive`, `flat` and `colorfield` to `settings.INSTALLED_APPS` **before** `django.contrib.admin`
```python ```python
INSTALLED_APPS = ( INSTALLED_APPS = (
#... #...
'admin_interface', "admin_interface",
'flat_responsive', # only if django version < 2.0 "flat_responsive", # only if django version < 2.0
'flat', # only if django version < 1.9 "flat", # only if django version < 1.9
'colorfield', "colorfield",
#... #...
'django.contrib.admin', "django.contrib.admin",
#... #...
) )
# only if django version >= 3.0 # only if django version >= 3.0
X_FRAME_OPTIONS = 'SAMEORIGIN' X_FRAME_OPTIONS = "SAMEORIGIN"
SILENCED_SYSTEM_CHECKS = ['security.W019'] SILENCED_SYSTEM_CHECKS = ["security.W019"]
``` ```
- Run ``python manage.py migrate`` - Run `python manage.py migrate`
- Run ``python manage.py collectstatic`` - Run `python manage.py collectstatic`
- Restart your application server - Restart your application server
#### Upgrade #### Upgrade
- Run `pip install django-admin-interface --upgrade` - Run `pip install django-admin-interface --upgrade`
- Run ``python manage.py migrate`` *(add* ``--fake-initial`` *if you are upgrading from 0.1.0 version)* - Run `python manage.py migrate` *(add* `--fake-initial` *if you are upgrading from 0.1.0 version)*
- Run ``python manage.py collectstatic --clear`` - Run `python manage.py collectstatic --clear`
- Restart your application server - Restart your application server
---
## Optional themes ## Optional themes
This package ships with optional themes as fixtures, they can be installed using the [loaddata admin command](https://docs.djangoproject.com/en/1.11/ref/django-admin/#django-admin-loaddata). Optional themes are activated on installation. This package ships with optional themes as fixtures, they can be installed using the [loaddata admin command](https://docs.djangoproject.com/en/1.11/ref/django-admin/#django-admin-loaddata). Optional themes are activated on installation.
##### [Django](https://www.djangoproject.com/) theme (default): ##### [Django](https://www.djangoproject.com/) theme (default):
Run ``python manage.py loaddata admin_interface_theme_django.json`` Run `python manage.py loaddata admin_interface_theme_django.json`
##### [Bootstrap](http://getbootstrap.com/) theme: ##### [Bootstrap](http://getbootstrap.com/) theme:
Run ``python manage.py loaddata admin_interface_theme_bootstrap.json`` Run `python manage.py loaddata admin_interface_theme_bootstrap.json`
##### [Foundation](http://foundation.zurb.com/) theme: ##### [Foundation](http://foundation.zurb.com/) theme:
Run ``python manage.py loaddata admin_interface_theme_foundation.json`` Run `python manage.py loaddata admin_interface_theme_foundation.json`
##### [U.S. Web Design Standards](https://standards.usa.gov/) theme: ##### [U.S. Web Design Standards](https://standards.usa.gov/) theme:
Run ``python manage.py loaddata admin_interface_theme_uswds.json`` Run `python manage.py loaddata admin_interface_theme_uswds.json`
### Add more themes ### Add more themes
You can add a theme you've created through the admin to this repository by [sending us a PR](http://makeapullrequest.com/). Here are the steps to follow to add: You can add a theme you've created through the admin to this repository by [sending us a PR](http://makeapullrequest.com/). Here are the steps to follow to add:
1. Export your exact theme as fixture using the `dumpdata` admin command: 1. Export your exact theme as fixture using the `dumpdata` admin command:
``python manage.py dumpdata admin_interface.Theme --indent 4 -o admin_interface_theme_{{name}}.json --pks=N`` `python manage.py dumpdata admin_interface.Theme --indent 4 -o admin_interface_theme_{{name}}.json --pks=N`
2. Copy the generated json file into the fixtures folder *(making sure its name starts with* `admin_interface_theme_` *to avoid clashes with fixtures that might be provided by other third party apps)*. 2. Copy the generated json file into the fixtures folder *(making sure its name starts with* `admin_interface_theme_` *to avoid clashes with fixtures that might be provided by other third party apps)*.
3. Remove the `"pk"` from the fixture and make sure the `active` field is set to `true` *(in this way a theme is automatically activated when installed)*. 3. Remove the `pk` from the fixture and make sure the `active` field is set to `true` *(in this way a theme is automatically activated when installed)*.
4. Edit the section above to document your theme. 4. Edit the section above to document your theme.
@@ -119,6 +126,7 @@ You can add **theme support to existing third-party libraries** using the follow
- `--admin-interface-related-modal-background-color` - `--admin-interface-related-modal-background-color`
- `--admin-interface-related-modal-background-opacity` - `--admin-interface-related-modal-background-opacity`
---
## Screenshots ## Screenshots
###### Admin login ###### Admin login
@@ -133,11 +141,50 @@ You can add **theme support to existing third-party libraries** using the follow
###### Admin theme customization ###### Admin theme customization
![django-admin-interface_theme_customization](https://cloud.githubusercontent.com/assets/1035294/11240250/7350d942-8df1-11e5-9b28-f2f54c333cdc.gif) ![django-admin-interface_theme_customization](https://cloud.githubusercontent.com/assets/1035294/11240250/7350d942-8df1-11e5-9b28-f2f54c333cdc.gif)
---
## FAQ ## FAQ
- #### I already have a custom `base_site.html`, how can I make it work?
### Custom `base-site.html`
> I already have a custom `base_site.html`, how can I make it work?
You can use [django-apptemplates](https://github.com/bittner/django-apptemplates), then add `{% extends "admin_interface:admin/base_site.html" %}` to your `base_site.html` You can use [django-apptemplates](https://github.com/bittner/django-apptemplates), then add `{% extends "admin_interface:admin/base_site.html" %}` to your `base_site.html`
### Language Chooser not showing
> I have enabled the **Language Chooser**, but it is not visible in the admin, what should I do?
You must configure multilanguage `settings` and `urls` correctly:
```python
LANGUAGES = (
("en", _("English")),
("it", _("Italiano")),
("fr", _("Française")),
# more than one language is expected here
)
LANGUAGE_CODE = "en"
USE_I18N = True
MIDDLEWARE = [
# ...
"django.middleware.locale.LocaleMiddleware",
# ...
]
```
```python
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.urls import include, path
# ...
urlpatterns = [
path("i18n/", include("django.conf.urls.i18n")),
]
urlpatterns += i18n_patterns(path("admin/", admin.site.urls))
```
---
## Testing ## Testing
```bash ```bash
# create python virtual environment # create python virtual environment
@@ -151,6 +198,7 @@ git clone https://github.com/fabiocaccamo/django-admin-interface.git src && cd s
# install dependencies # install dependencies
pip install -r requirements.txt pip install -r requirements.txt
pip install -r requirements-test.txt
# run tests # run tests
tox tox
@@ -160,24 +208,13 @@ python setup.py test
python -m django test --settings "tests.settings" python -m django test --settings "tests.settings"
``` ```
---
## License ## License
Released under [MIT License](LICENSE.txt). Released under [MIT License](LICENSE.txt).
--- ---
## Supporting
I would like to spend more time on this project, especially to improve it and adding new features.
As everyone knows open-source projects takes up a lot of time that is unpaid. :money_with_wings:
If you are using this package in commercial project(s), please consider the idea to become a sponsor or donating once:
- [GitHub Sponsor](https://github.com/sponsors/fabiocaccamo)
- [PayPal](https://www.paypal.me/fabiocaccamo)
- BTC: bc1q2t0pv8z3udpyuvfnx5kskhqdad4dcvtfuzmvjw
- ETH: 0x8B55Fb7798b5A9F797A4455C00821B6e53daca74
## See also ## See also
- [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨 - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨
@@ -194,4 +231,6 @@ If you are using this package in commercial project(s), please consider the idea
- [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳 - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳
- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. 🧢
- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️ - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️
+14
View File
@@ -0,0 +1,14 @@
# Security Policy
## Supported Versions
Keep this library updated to the latest version.
| Version | Supported |
| ------- | ------------------ |
| latest | :white_check_mark: |
| oldest | :x: |
## Reporting a Vulnerability
Open an issue.
+3 -2
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- import django
default_app_config = 'admin_interface.apps.AdminInterfaceConfig' if django.VERSION < (3, 2):
default_app_config = "admin_interface.apps.AdminInterfaceConfig"
+178 -126
View File
@@ -1,139 +1,191 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from admin_interface.compat import gettext_lazy as _
from admin_interface.models import Theme
from django.contrib import admin from django.contrib import admin
from django.contrib.auth import models as auth_models
from admin_interface.compat import gettext_lazy as _
from admin_interface.models import Theme, UserTheme
from .import_tema.admin import ImportMixin
class ThemeAdmin(admin.ModelAdmin): class UserInline(admin.TabularInline):
model = UserTheme
extra = 0
autocomplete_fields = ('user', )
list_display = ('name', 'active', )
list_editable = ('active', ) class ThemeAdmin(ImportMixin, admin.ModelAdmin):
inlines = [UserInline, ]
list_display = (
"name",
"active",
"demo",
"default",
)
list_editable = ("active",)
list_per_page = 100 list_per_page = 100
show_full_result_count = False show_full_result_count = False
fieldsets = ( fieldsets = (
(None, { (
'classes': ('wide', ), None,
'fields': ('name', 'active', ) {
}), "classes": ("wide",),
(_('Environment'), { "fields": (
'classes': ('wide', ), "name",
'fields': ( "active",
'env_name', "demo",
'env_color', "default",
'env_visible_in_header', ),
'env_visible_in_favicon', },
) ),
}), (
(_('Language chooser'), { _("Environment"),
'classes': ('wide', ), {
'fields': ( "classes": ("wide",),
'language_chooser_active', "fields": (
'language_chooser_display', "env_name",
) "env_color",
}), "env_visible_in_header",
(_('Logo'), { "env_visible_in_favicon",
'classes': ('wide', ), ),
'fields': ( },
'logo', ),
'logo_max_width', (
'logo_max_height', _("Language chooser"),
'logo_color', {
'logo_visible', "classes": ("wide",),
) "fields": (
}), "language_chooser_active",
(_('Favicon'), { "language_chooser_display",
'classes': ('wide', ), ),
'fields': ('favicon', ) },
}), ),
(_('Title'), { (
'classes': ('wide', ), _("Logo"),
'fields': ( {
'title', "classes": ("wide",),
'title_color', "fields": (
'title_visible', "logo",
) "logo_max_width",
}), "logo_max_height",
(_('Header'), { "logo_color",
'classes': ('wide', ), "logo_visible",
'fields': ( ),
'css_header_background_color', },
'css_header_text_color', ),
'css_header_link_color', (_("Favicon"), {"classes": ("wide",), "fields": ("favicon",)}),
'css_header_link_hover_color', (
) _("Title"),
}), {
(_('Breadcrumbs / Module headers'), { "classes": ("wide",),
'classes': ('wide', ), "fields": (
'fields': ( "title",
'css_module_background_color', "title_color",
'css_module_background_selected_color', "title_visible",
'css_module_text_color', ),
'css_module_link_color', },
'css_module_link_selected_color', ),
'css_module_link_hover_color', (
'css_module_rounded_corners', _("Header"),
) {
}), "classes": ("wide",),
(_('Generic Links'), { "fields": (
'classes': ('wide', ), "css_header_background_color",
'fields': ( "css_header_text_color",
'css_generic_link_color', "css_header_link_color",
'css_generic_link_hover_color', "css_header_link_hover_color",
) ),
}), },
(_('Save Buttons'), { ),
'classes': ('wide', ), (
'fields': ( _("Breadcrumbs / Module headers"),
'css_save_button_background_color', {
'css_save_button_background_hover_color', "classes": ("wide",),
'css_save_button_text_color', "fields": (
) "css_module_background_color",
}), "css_module_background_selected_color",
(_('Delete Buttons'), { "css_module_text_color",
'classes': ('wide', ), "css_module_link_color",
'fields': ( "css_module_link_selected_color",
'css_delete_button_background_color', "css_module_link_hover_color",
'css_delete_button_background_hover_color', "css_module_rounded_corners",
'css_delete_button_text_color', ),
) },
}), ),
(_('Navigation Bar'), { (
'classes': ('wide', ), _("Generic Links"),
'fields': ( {
'foldable_apps', "classes": ("wide",),
) "fields": (
}), "css_generic_link_color",
(_('Related Modal'), { "css_generic_link_hover_color",
'classes': ('wide', ), ),
'fields': ( },
'related_modal_active', ),
'related_modal_background_color', (
'related_modal_background_opacity', _("Save Buttons"),
'related_modal_rounded_corners', {
'related_modal_close_button_visible', "classes": ("wide",),
) "fields": (
}), "css_save_button_background_color",
(_('Form Controls'), { "css_save_button_background_hover_color",
'classes': ('wide', ), "css_save_button_text_color",
'fields': ( ),
'form_submit_sticky', },
'form_pagination_sticky', ),
) (
}), _("Delete Buttons"),
(_('List Filter'), { {
'classes': ('wide', ), "classes": ("wide",),
'fields': ( "fields": (
'list_filter_dropdown', "css_delete_button_background_color",
'list_filter_sticky', "css_delete_button_background_hover_color",
) "css_delete_button_text_color",
}), ),
(_('Recent Actions'), { },
'classes': ('wide', ), ),
'fields': ('recent_actions_visible', ) (_("Navigation Bar"), {"classes": (
}), "wide",), "fields": ("foldable_apps",)}),
(
_("Related Modal"),
{
"classes": ("wide",),
"fields": (
"related_modal_active",
"related_modal_background_color",
"related_modal_background_opacity",
"related_modal_rounded_corners",
"related_modal_close_button_visible",
),
},
),
(
_("Form Controls"),
{
"classes": ("wide",),
"fields": (
"form_submit_sticky",
"form_pagination_sticky",
),
},
),
(
_("List Filter"),
{
"classes": ("wide",),
"fields": (
"list_filter_dropdown",
"list_filter_sticky",
),
},
),
(
_("Recent Actions"),
{"classes": ("wide",), "fields": ("recent_actions_visible",)},
),
) )
save_on_top = True save_on_top = True
+4 -5
View File
@@ -8,9 +8,9 @@ from django.db.models.signals import post_migrate
class AdminInterfaceConfig(AppConfig): class AdminInterfaceConfig(AppConfig):
name = 'admin_interface' name = "admin_interface"
verbose_name = _('Admin Interface') verbose_name = _("Admin Interface")
default_auto_field = 'django.db.models.AutoField' default_auto_field = "django.db.models.AutoField"
def ready(self): def ready(self):
@@ -18,5 +18,4 @@ class AdminInterfaceConfig(AppConfig):
from admin_interface.models import Theme from admin_interface.models import Theme
settings.check_installed_apps() settings.check_installed_apps()
post_migrate.connect( post_migrate.connect(Theme.post_migrate_handler, sender=self)
Theme.post_migrate_handler, sender=self)
+4 -4
View File
@@ -5,16 +5,16 @@ from django.core.cache import cache, caches
def app_cache(): def app_cache():
return caches['admin_interface'] if 'admin_interface' in settings.CACHES else cache return caches["admin_interface"] if "admin_interface" in settings.CACHES else cache
def del_cached_active_theme(): def del_cached_active_theme():
app_cache().delete('admin_interface_theme') app_cache().delete("admin_interface_theme")
def get_cached_active_theme(): def get_cached_active_theme():
return app_cache().get('admin_interface_theme', None) return app_cache().get("admin_interface_theme", None)
def set_cached_active_theme(theme): def set_cached_active_theme(theme):
app_cache().set('admin_interface_theme', theme) app_cache().set("admin_interface_theme", theme)
+16 -8
View File
@@ -2,17 +2,25 @@
import django import django
if django.VERSION >= (1, 11):
from django.core.validators import FileExtensionValidator
else:
def FileExtensionValidator(*args, **kwargs):
def noop(*args, **kwargs):
pass
return noop
if django.VERSION < (1, 10):
from django.core.urlresolvers import NoReverseMatch, reverse
else:
from django.urls import NoReverseMatch, reverse
if django.VERSION < (2, 0): if django.VERSION < (2, 0):
from django.utils.encoding import force_text as force_str from django.utils.encoding import force_text as force_str
from django.utils.translation import ugettext_lazy as gettext_lazy from django.utils.translation import ugettext_lazy as gettext_lazy
else: else:
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
if django.VERSION >= (1, 11):
from django.core.validators import FileExtensionValidator
else:
def FileExtensionValidator(*args, **kwargs):
def noop(*args, **kwargs):
pass
return noop
+43
View File
@@ -0,0 +1,43 @@
from .models import Theme, UserTheme
def get_active_theme(request):
objs_manager = Theme.objects
user_theme_manager = UserTheme.objects
objs_active_qs = objs_manager.filter(active=True)
objs_active_ls = list(objs_active_qs)
objs_active_count = len(objs_active_ls)
if objs_active_count == 0:
obj = objs_manager.first()
if obj:
obj.set_active()
# else:
# obj = objs_manager.create()
elif objs_active_count == 1:
obj = objs_active_ls[0]
elif objs_active_count > 1:
# for frame_record in inspect.stack():
# if frame_record[3]=='get_response':
# request = frame_record[0].f_locals['request']
# user = request.user
# break
# else:
# request = None
user = request.user
try:
obj = user_theme_manager.filter(user=user, theme__active=True).first().theme
except:
objs_default_qs = objs_active_qs.filter(default=True)
if len(objs_default_qs) == 0:
obj = objs_active_qs.first()
if obj:
obj.set_default()
else:
obj = objs_default_qs.first()
return {
'theme': obj,
}
@@ -27,7 +27,6 @@
"css_delete_button_background_color": "#D9534F", "css_delete_button_background_color": "#D9534F",
"css_delete_button_background_hover_color": "#C9302C", "css_delete_button_background_hover_color": "#C9302C",
"css_delete_button_text_color": "#FFFFFF", "css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true, "related_modal_active": true,
"related_modal_background_color": "#503873", "related_modal_background_color": "#503873",
"related_modal_background_opacity": 0.2, "related_modal_background_opacity": 0.2,
@@ -27,7 +27,6 @@
"css_delete_button_background_color": "#BA2121", "css_delete_button_background_color": "#BA2121",
"css_delete_button_background_hover_color": "#A41515", "css_delete_button_background_hover_color": "#A41515",
"css_delete_button_text_color": "#FFFFFF", "css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true, "related_modal_active": true,
"related_modal_background_color": "#000000", "related_modal_background_color": "#000000",
"related_modal_background_opacity": 0.2, "related_modal_background_opacity": 0.2,
@@ -27,7 +27,6 @@
"css_delete_button_background_color": "#CC4B37", "css_delete_button_background_color": "#CC4B37",
"css_delete_button_background_hover_color": "#BF4634", "css_delete_button_background_hover_color": "#BF4634",
"css_delete_button_text_color": "#FFFFFF", "css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true, "related_modal_active": true,
"related_modal_background_color": "#000000", "related_modal_background_color": "#000000",
"related_modal_background_opacity": 0.2, "related_modal_background_opacity": 0.2,
@@ -27,7 +27,6 @@
"css_delete_button_background_color": "#CD2026", "css_delete_button_background_color": "#CD2026",
"css_delete_button_background_hover_color": "#981B1E", "css_delete_button_background_hover_color": "#981B1E",
"css_delete_button_text_color": "#FFFFFF", "css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true, "related_modal_active": true,
"related_modal_background_color": "#000000", "related_modal_background_color": "#000000",
"related_modal_background_opacity": 0.8, "related_modal_background_opacity": 0.8,
@@ -27,7 +27,6 @@
"css_delete_button_background_color": "#BA2121", "css_delete_button_background_color": "#BA2121",
"css_delete_button_background_hover_color": "#A41515", "css_delete_button_background_hover_color": "#A41515",
"css_delete_button_text_color": "#FFFFFF", "css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true, "related_modal_active": true,
"related_modal_background_color": "#000000", "related_modal_background_color": "#000000",
"related_modal_background_opacity": 0.2, "related_modal_background_opacity": 0.2,
Whitespace-only changes.
+160
View File
@@ -0,0 +1,160 @@
import json
import os
import tempfile
import zipfile
import django
from django import forms
from django.conf import settings
from django.contrib import admin, messages
from django.contrib.auth import get_permission_codename
from django.core.exceptions import PermissionDenied
from django.core.files.storage import default_storage
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.urls import path, reverse
from django.utils.translation import gettext_lazy as _
from .. import models
from .forms import ImportForm
class ImportMixin(admin.ModelAdmin):
"""
Import mixin.
This is intended to be mixed with django.contrib.admin.ModelAdmin
https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#modeladmin-objects
"""
#: template for change_list view
change_list_template = 'admin/import_export/change_list_import.html'
#: template for import view
import_template_name = 'admin/import_export/import.html'
def get_model_info(self):
app_label = self.model._meta.app_label
return (self.model._meta.app_label, self.model._meta.model_name)
def has_import_permission(self, request):
"""
Returns whether a request has import permission.
"""
IMPORT_PERMISSION_CODE = getattr(settings, 'IMPORT_EXPORT_IMPORT_PERMISSION_CODE', None)
if IMPORT_PERMISSION_CODE is None:
return True
opts = self.opts
codename = get_permission_codename(IMPORT_PERMISSION_CODE, opts)
return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def get_urls(self):
urls = super().get_urls()
info = self.get_model_info()
my_urls = [
path('import/',
self.admin_site.admin_view(self.import_action),
name='%s_%s_import' % info),
]
return my_urls + urls
def get_import_context_data(self, **kwargs):
return self.get_context_data(**kwargs)
def get_context_data(self, **kwargs):
return {}
def get_form_kwargs(self, form, *args, **kwargs):
"""
Prepare/returns kwargs for the import form.
To distinguish between import and confirm import forms,
the following approach may be used:
if isinstance(form, ImportForm):
# your code here for the import form kwargs
# e.g. update.kwargs({...})
elif isinstance(form, ConfirmImportForm):
# your code here for the confirm import form kwargs
# e.g. update.kwargs({...})
...
"""
return kwargs
def import_action(self, request, *args, **kwargs):
"""
Perform a dry_run of the import to make sure the import will not
result in errors. If there where no error, save the user
uploaded file to a local temp file that will be used by
'process_import' for the actual import.
"""
if not self.has_import_permission(request):
raise PermissionDenied
context = self.get_import_context_data()
form_type = ImportForm
form_kwargs = self.get_form_kwargs(form_type, *args, **kwargs)
form = form_type(request.POST or None,
request.FILES or None,
**form_kwargs)
if request.POST and form.is_valid():
import_file_tema = form.cleaned_data['tema']
if zipfile.is_zipfile(import_file_tema):
with zipfile.ZipFile(import_file_tema, 'r') as zip_ref:
with tempfile.TemporaryDirectory() as tempdir:
zip_ref.extractall(tempdir)
lst = os.listdir(tempdir)
allowed_extensions=[".gif", ".jpg", ".jpeg", ".png", ".svg"]
try:
tema_json = [s for s in os.listdir(f'{tempdir}/{lst[0]}') if '.json' in s][0]
logo = [s for s in os.listdir(f'{tempdir}/{lst[0]}/logo') if any(ele in s for ele in allowed_extensions)]
logo = logo[0] if logo else None
favicon = [s for s in os.listdir(f'{tempdir}/{lst[0]}/favicon') if any(ele in s for ele in allowed_extensions)]
favicon = favicon[0] if favicon else None
with open(f'{tempdir}/{lst[0]}/{tema_json}', 'r') as temporary_file:
result = json.loads(temporary_file.read())
if logo:
with open(f'{tempdir}/{lst[0]}/logo/{logo}', 'rb') as temporary_file:
default_storage.save(f"admin-interface/logo/{temporary_file.name.split('/')[-1]}", temporary_file)
if favicon:
with open(f'{tempdir}/{lst[0]}/favicon/{favicon}', 'rb') as temporary_file:
default_storage.save(f"admin-interface/favicon/{temporary_file.name.split('/')[-1]}", temporary_file)
skip_result = False
except FileNotFoundError as e:
messages.error(request, 'Struttura del file .zip errata.')
skip_result = True
if not skip_result:
try:
new_theme = models.Theme(
**result[0]['fields']
)
new_theme.save()
messages.success(request, _('Import finished'))
except:
messages.error(request, 'Struttura del file .json errata.')
else:
messages.error(request, 'È richiesto un file .zip')
url = reverse('admin:%s_%s_changelist' % self.get_model_info(),
current_app=self.admin_site.name)
return HttpResponseRedirect(url)
else:
context.update(self.admin_site.each_context(request))
context['title'] = _("Import")
context['form'] = form
context['opts'] = self.model._meta
request.current_app = self.admin_site.name
return TemplateResponse(request, [self.import_template_name],
context)
def changelist_view(self, request, extra_context=None):
if extra_context is None:
extra_context = {}
extra_context['has_import_permission'] = self.has_import_permission(request)
return super().changelist_view(request, extra_context)
+11
View File
@@ -0,0 +1,11 @@
import os.path
from django import forms
from django.contrib.admin.helpers import ActionForm
from django.utils.translation import gettext_lazy as _
class ImportForm(forms.Form):
tema = forms.FileField(
label='Zip'
)
@@ -0,0 +1,139 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Christian Galeffi <chri@gallochri.com>, 2015.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-06-04 09:27+0200\n"
"PO-Revision-Date: 2015-08-30 20:32+0100\n"
"Last-Translator: Christian Galeffi <chri@gallochri.com>\n"
"Language-Team: Italian <kde-i18n-it@kde.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.5.4\n"
#: admin.py:194
#, python-format
msgid "%s through import_export"
msgstr ""
#: admin.py:200
msgid "Import finished, with {} new and {} updated {}."
msgstr ""
#: admin.py:298
#, python-format
msgid "<h1>Imported file has a wrong encoding: %s</h1>"
msgstr ""
#: admin.py:300
#, python-format
msgid "<h1>%s encountered while trying to read file: %s</h1>"
msgstr ""
#: admin.py:331 templates/admin/import_export/change_list_import_item.html:5
#: templates/admin/import_export/import.html:10
msgid "Import"
msgstr "Importare"
#: admin.py:496 templates/admin/import_export/change_list_export_item.html:5
#: templates/admin/import_export/export.html:7
msgid "Export"
msgstr "Esportare"
#: admin.py:554
msgid "You must select an export format."
msgstr "Devi selezionare un formato di esportazione."
#: admin.py:567
#, python-format
msgid "Export selected %(verbose_name_plural)s"
msgstr "Esporta selezionati %(verbose_name_plural)s"
#: forms.py:10
msgid "File to import"
msgstr "File da importare"
#: forms.py:13 forms.py:41 forms.py:66
msgid "Format"
msgstr "Formato"
#: templates/admin/import_export/base.html:11
msgid "Home"
msgstr "Home"
#: templates/admin/import_export/export.html:31
#: templates/admin/import_export/import.html:52
msgid "Submit"
msgstr "Inviare"
#: templates/admin/import_export/import.html:20
msgid ""
"Below is a preview of data to be imported. If you are satisfied with the "
"results, click 'Confirm import'"
msgstr ""
"Questa è un'anteprima dei dati che saranno importati. Se il risultato è "
"soddisfacente, premi 'Conferma importazione'"
#: templates/admin/import_export/import.html:23
msgid "Confirm import"
msgstr "Conferma importazione"
#: templates/admin/import_export/import.html:31
msgid "This importer will import the following fields: "
msgstr "Verranno importati i seguenti campi:"
#: templates/admin/import_export/import.html:61
#: templates/admin/import_export/import.html:90
msgid "Errors"
msgstr "Errori"
#: templates/admin/import_export/import.html:72
msgid "Line number"
msgstr "Numero linea"
#: templates/admin/import_export/import.html:82
msgid "Some rows failed to validate"
msgstr ""
#: templates/admin/import_export/import.html:84
msgid ""
"Please correct these errors in your data where possible, then reupload it "
"using the form above."
msgstr ""
#: templates/admin/import_export/import.html:89
msgid "Row"
msgstr ""
#: templates/admin/import_export/import.html:116
msgid "Non field specific"
msgstr ""
#: templates/admin/import_export/import.html:137
msgid "Preview"
msgstr "Anteprima"
#: templates/admin/import_export/import.html:152
msgid "New"
msgstr "Nuovo"
#: templates/admin/import_export/import.html:154
msgid "Skipped"
msgstr "Salta"
#: templates/admin/import_export/import.html:156
msgid "Delete"
msgstr "Cancella"
#: templates/admin/import_export/import.html:158
msgid "Update"
msgstr "Aggiorna"
#~ msgid "Import finished"
#~ msgstr "Importazione terminata"
@@ -0,0 +1,81 @@
.import-preview .errors {
position: relative;
}
.validation-error-count {
display: inline-block;
background-color: #e40000;
border-radius: 6px;
color: white;
font-size: 0.9em;
position: relative;
font-weight: bold;
margin-top: -2px;
padding: 0.2em 0.4em;
}
.validation-error-container {
position: absolute;
opacity: 0;
pointer-events: none;
background-color: #ffc1c1;
padding: 14px 15px 10px;
top: 25px;
margin: 0 0 20px 0;
width: 200px;
z-index: 2;
}
table.import-preview tr.skip {
background-color: #d2d2d2;
}
table.import-preview tr.new {
background-color: #bdd8b2;
}
table.import-preview tr.delete {
background-color: #f9bebf;
}
table.import-preview tr.update {
background-color: #fdfdcf;
}
.import-preview td:hover .validation-error-count {
z-index: 3;
}
.import-preview td:hover .validation-error-container {
opacity: 1;
pointer-events: auto;
}
.validation-error-list {
margin: 0;
padding: 0;
}
.validation-error-list li {
list-style: none;
margin: 0;
}
.validation-error-list > li > ul {
margin: 8px 0;
padding: 0;
}
.validation-error-list > li > ul > li {
padding: 0;
margin: 0 0 10px;
line-height: 1.28em;
}
.validation-error-field-label {
display: block;
border-bottom: 1px solid #e40000;
color: #e40000;
text-transform: uppercase;
font-weight: bold;
font-size: 0.85em;
}
@@ -0,0 +1,17 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_modify %}
{% load admin_urls %}
{% load static %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
{% block bodyclass %}{{ block.super }} {{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; {% block breadcrumbs_last %}{% endblock %}
</div>
{% endblock %}
{% endif %}
@@ -0,0 +1,13 @@
{% extends "admin/change_list.html" %}
{# Original template renders object-tools only when has_add_permission is True. #}
{# This hack allows sub templates to add to object-tools #}
{% block object-tools %}
<ul class="object-tools">
{% block object-tools-items %}
{% if has_add_permission %}
{{ block.super }}
{% endif %}
{% endblock %}
</ul>
{% endblock %}
@@ -0,0 +1,6 @@
{% extends "admin/import_export/change_list.html" %}
{% block object-tools-items %}
{% include "admin/import_export/change_list_import_item.html" %}
{{ block.super }}
{% endblock %}
@@ -0,0 +1,171 @@
{% extends "admin/import_export/base.html" %}
{% load i18n %}
{% load admin_urls %}
{% load import_export_tags %}
{% load static %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "import_export/import.css" %}" />{% endblock %}
{% block breadcrumbs_last %}
{% trans "Import" %}
{% endblock %}
{% block content %}
{% if confirm_form %}
<form action="{% url opts|admin_urlname:"process_import" %}" method="POST">
{% csrf_token %}
{{ confirm_form.as_p }}
<p>
{% trans "Below is a preview of data to be imported. If you are satisfied with the results, click 'Confirm import'" %}
</p>
<div class="submit-row">
<input type="submit" class="default" name="confirm" value="{% trans "Confirm import" %}">
</div>
</form>
{% else %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>
{% trans "This importer will import the following fields: " %}
<code>{{ fields|join:", " }}</code>
</p>
<fieldset class="module aligned">
{% for field in form %}
<div class="form-row">
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
{% if field.field.help_text %}
<p class="help">{{ field.field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="submit" class="default" value="{% trans "Submit" %}">
</div>
</form>
{% endif %}
{% if result %}
{% if result.has_errors %}
<h2>{% trans "Errors" %}</h2>
<ul>
{% for error in result.base_errors %}
<li>
{{ error.error }}
<div class="traceback">{{ error.traceback|linebreaks }}</div>
</li>
{% endfor %}
{% for line, errors in result.row_errors %}
{% for error in errors %}
<li>
{% trans "Line number" %}: {{ line }} - {{ error.error }}
<div><code>{{ error.row.values|join:", " }}</code></div>
<div class="traceback">{{ error.traceback|linebreaks }}</div>
</li>
{% endfor %}
{% endfor %}
</ul>
{% elif result.has_validation_errors %}
<h2>{% trans "Some rows failed to validate" %}</h2>
<p>{% trans "Please correct these errors in your data where possible, then reupload it using the form above." %}</p>
<table class="import-preview">
<thead>
<tr>
<th>{% trans "Row" %}</th>
<th>{% trans "Errors" %}</th>
{% for field in result.diff_headers %}
<th>{{ field }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in result.invalid_rows %}
<tr>
<td>{{ row.number }} </td>
<td class="errors">
<span class="validation-error-count">{{ row.error_count }}</span>
<div class="validation-error-container">
<ul class="validation-error-list">
{% for field_name, error_list in row.field_specific_errors.items %}
<li>
<span class="validation-error-field-label">{{ field_name }}</span>
<ul>
{% for error in error_list %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
{% if row.non_field_specific_errors %}
<li>
<span class="validation-error-field-label">{% trans "Non field specific" %}</span>
<ul>
{% for error in row.non_field_specific_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
</ul>
</div>
</td>
{% for field in row.values %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<h2>{% trans "Preview" %}</h2>
<table class="import-preview">
<thead>
<tr>
<th></th>
{% for field in result.diff_headers %}
<th>{{ field }}</th>
{% endfor %}
</tr>
</thead>
{% for row in result.valid_rows %}
<tr class="{{ row.import_type }}">
<td class="import-type">
{% if row.import_type == 'new' %}
{% trans "New" %}
{% elif row.import_type == 'skip' %}
{% trans "Skipped" %}
{% elif row.import_type == 'delete' %}
{% trans "Delete" %}
{% elif row.import_type == 'update' %}
{% trans "Update" %}
{% endif %}
</td>
{% for field in row.diff %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
{% endblock %}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,206 @@
# This file is distributed under the same license as the
# django-admin-interface package.
#
# Translators:
# Kamil Paduszyński <kpaduszy@gmail.com>, 2022
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-admin-interface\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-04 09:19+0000\n"
"PO-Revision-Date: 2022-02-04 19:13-0500\n"
"Last-Translator: Kamil Paduszyński <kpaduszy@gmail.com>\n"
"Language-Team: Polish <LL@li.org>\n"
"Language: Polish \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin_interface/admin.py:21
msgid "Environment"
msgstr "Środowisko"
#: admin_interface/admin.py:30
msgid "Language chooser"
msgstr "Wybór wersji językowej"
#: admin_interface/admin.py:37
msgid "Logo"
msgstr "Logo"
#: admin_interface/admin.py:45
msgid "Favicon"
msgstr "Ikonka"
#: admin_interface/admin.py:49
msgid "Title"
msgstr "Tytuł"
#: admin_interface/admin.py:57
msgid "Header"
msgstr "Nagłówek"
#: admin_interface/admin.py:66
msgid "Breadcrumbs / Module headers"
msgstr "Pasek nawigacyjny / nagłówki modułów"
#: admin_interface/admin.py:76
msgid "Generic Links"
msgstr "Zwykłe linki"
#: admin_interface/admin.py:83
msgid "Save Buttons"
msgstr "Przyciski zapisywania"
#: admin_interface/admin.py:91
msgid "Delete Buttons"
msgstr "Przyciski usuwania"
#: admin_interface/admin.py:99
msgid "Related Modal"
msgstr "Okno dialogowe"
#: admin_interface/admin.py:109
msgid "List Filter"
msgstr "Filtry"
#: admin_interface/admin.py:113
msgid "Recent Actions"
msgstr "Ostatnie działania"
#: admin_interface/apps.py:11
msgid "Admin Interface"
msgstr "Wygląd panelu administracyjnego"
#: admin_interface/models.py:72 admin_interface/models.py:116
#: admin_interface/models.py:135
msgid "name"
msgstr "nazwa"
#: admin_interface/models.py:75 admin_interface/models.py:132
#: admin_interface/models.py:253
msgid "active"
msgstr "aktywny"
#: admin_interface/models.py:79
#: admin_interface/templates/admin/base_site.html:6
#: admin_interface/templates/admin/base_site.html:60
msgid "Django administration"
msgstr "Administracja Django"
#: admin_interface/models.py:81
msgid "title"
msgstr "tytuł"
#: admin_interface/models.py:87 admin_interface/models.py:102
#: admin_interface/models.py:122
msgid "color"
msgstr "kolor"
#: admin_interface/models.py:90 admin_interface/models.py:105
#: admin_interface/models.py:289
msgid "visible"
msgstr "widoczny"
#: admin_interface/models.py:95
msgid "Leave blank to use the default Django logo"
msgstr "Puste ustawia domyślne logo Django"
#: admin_interface/models.py:96
msgid "logo"
msgstr "logo"
#: admin_interface/models.py:110
msgid "(.ico|.png|.gif - 16x16|32x32 px)"
msgstr "(Format pliku: .ico, .png, .gif; wymiary: 16 x 16 lub 32 x 32 px)."
#: admin_interface/models.py:111
msgid "favicon"
msgstr "ikonka"
#: admin_interface/models.py:120
msgid ""
"(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: "
"#3498DB)"
msgstr ""
"(czerwony: #E74C3C, pomarańczowy: #E67E22, żółty: #F1C40F, zielony: #2ECC71, niebieski: "
"#3498DB)"
#: admin_interface/models.py:125
msgid "visible in header (marker and name)"
msgstr "widoczne w nagłówku (znacznik i nazwa)"
#: admin_interface/models.py:128
msgid "visible in favicon (marker)"
msgstr "widoczne przy ikonce (znacznik)"
#: admin_interface/models.py:134
msgid "code"
msgstr "kod"
#: admin_interface/models.py:141
msgid "display"
msgstr "wyświetlaj"
#: admin_interface/models.py:148 admin_interface/models.py:173
#: admin_interface/models.py:214 admin_interface/models.py:233
#: admin_interface/models.py:259
msgid "background color"
msgstr "kolor tła"
#: admin_interface/models.py:154 admin_interface/models.py:179
#: admin_interface/models.py:226 admin_interface/models.py:245
#: admin_interface/models.py:249
msgid "text color"
msgstr "kolor tekstu"
#: admin_interface/models.py:160 admin_interface/models.py:185
#: admin_interface/models.py:201
msgid "link color"
msgstr "kolor linku"
#: admin_interface/models.py:166 admin_interface/models.py:191
#: admin_interface/models.py:207
msgid "link hover color"
msgstr "kolor wskazywanego linku"
#: admin_interface/models.py:194 admin_interface/models.py:279
msgid "rounded corners"
msgstr "zaokrąglenie narożników"
#: admin_interface/models.py:220 admin_interface/models.py:239
msgid "background hover color"
msgstr "kolor tła wskazywanego przycisku"
#: admin_interface/models.py:276
msgid "background opacity"
msgstr "przeźroczystość tła"
#: admin_interface/models.py:282
msgid "close button visible"
msgstr "pokaż przycisk zamykania"
#: admin_interface/models.py:286
msgid "use dropdown"
msgstr "zastosuj listy rozwijane"
#: admin_interface/models.py:298
msgid "Theme"
msgstr "Schemat"
#: admin_interface/models.py:299
msgid "Themes"
msgstr "Schematy"
#: admin_interface/templates/admin/filter.html:13
#: admin_interface/templates/admin_interface/dropdown_filter.html:4
#, python-format
msgid " By %(filter_title)s "
msgstr " po %(filter_title)s "
#: admin_interface/templates/admin/popup_response.html:3
msgid "Popup closing..."
msgstr "Zamykanie..."
Binary file not shown.
@@ -0,0 +1,234 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-28 10:01-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:21
msgid "Environment"
msgstr "Ambiente"
#: admin.py:30
msgid "Language chooser"
msgstr "Seletor de idioma"
#: admin.py:37
msgid "Logo"
msgstr "Logo"
#: admin.py:47
msgid "Favicon"
msgstr "Favicon"
#: admin.py:51
msgid "Title"
msgstr "Título"
#: admin.py:59
msgid "Header"
msgstr "Cabeçalho"
#: admin.py:68
msgid "Breadcrumbs / Module headers"
msgstr "Cabeçalhos de módulo"
#: admin.py:80
msgid "Generic Links"
msgstr "Links Genéricos"
#: admin.py:87
msgid "Save Buttons"
msgstr "Botões Salvar"
#: admin.py:95
msgid "Delete Buttons"
msgstr "Botões Deletar"
#: admin.py:103
msgid "Navigation Bar"
msgstr "Barra de Navegação"
#: admin.py:109
msgid "Related Modal"
msgstr "Modal Relacionado"
#: admin.py:119
msgid "Form Controls"
msgstr "Controles de Formulário"
#: admin.py:126
msgid "List Filter"
msgstr "Filtro de lista"
#: admin.py:133
msgid "Recent Actions"
msgstr "Ações recentes"
#: apps.py:12
msgid "Admin Interface"
msgstr "Interface do administrador"
#: models.py:73 models.py:129 models.py:148
msgid "name"
msgstr "nome"
#: models.py:76 models.py:145 models.py:274
msgid "active"
msgstr "ativo"
#: models.py:80 templates/admin/base_site.html:6
#: templates/admin/base_site.html:78
msgid "Django administration"
msgstr "Administração do Django"
#: models.py:82
msgid "title"
msgstr "título"
#: models.py:88 models.py:105 models.py:135
msgid "color"
msgstr "cor"
#: models.py:91 models.py:116 models.py:318
msgid "visible"
msgstr "visível"
#: models.py:98
msgid "Leave blank to use the default Django logo"
msgstr "Deixe em branco para usar o logotipo padrão do Django"
#: models.py:99
msgid "logo"
msgstr "logo"
#: models.py:109
msgid "max width"
msgstr "largura máxima"
#: models.py:113
msgid "max height"
msgstr "altura máxima"
#: models.py:123
msgid "(.ico|.png|.gif - 16x16|32x32 px)"
msgstr "(.ico|.png|.gif - 16x16|32x32 px)"
#: models.py:124
msgid "favicon"
msgstr "favicon"
#: models.py:133
msgid ""
"(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: "
"#3498DB)"
msgstr ""
"(vermelho: #E74C3C, laranja: #E67E22, amarelo: #F1C40F, verde: #2ECC71, "
"azul: #3498DB)"
#: models.py:138
msgid "visible in header (marker and name)"
msgstr "visível no cabeçalho (marcador e nome)"
#: models.py:141
msgid "visible in favicon (marker)"
msgstr "visível no favicon (marcador)"
#: models.py:147
msgid "code"
msgstr "código"
#: models.py:154
msgid "display"
msgstr "exibição"
#: models.py:161 models.py:186 models.py:239 models.py:258 models.py:280
msgid "background color"
msgstr "cor de fundo"
#: models.py:167 models.py:198 models.py:251 models.py:270
msgid "text color"
msgstr "cor do texto"
#: models.py:173 models.py:204 models.py:226
msgid "link color"
msgstr "cor do link"
#: models.py:179 models.py:216 models.py:232
msgid "link hover color"
msgstr "cor de foco do link"
#: models.py:192
msgid "background selected color"
msgstr "cor de fundo selecionada"
#: models.py:210
msgid "link selected color"
msgstr "link cor selecionada"
#: models.py:219 models.py:300
msgid "rounded corners"
msgstr "cantos arredondados"
#: models.py:245 models.py:264
msgid "background hover color"
msgstr "cor de fundo do foco"
#: models.py:297
msgid "background opacity"
msgstr "opacidade de fundo"
#: models.py:303
msgid "close button visible"
msgstr "botão fechar visível"
#: models.py:307
msgid "use dropdown"
msgstr "usar menu suspenso"
#: models.py:310
msgid "sticky position"
msgstr "posição sticky"
#: models.py:314
msgid "foldable apps"
msgstr "aplicativos dobráveis"
#: models.py:322
msgid "sticky submit"
msgstr "envio fixo"
#: models.py:325
msgid "sticky pagination"
msgstr "paginação fixa"
#: models.py:334
msgid "Theme"
msgstr "Tema"
#: models.py:335
msgid "Themes"
msgstr "Temas"
#: templates/admin/filter.html:13
#: templates/admin_interface/dropdown_filter.html:4
#, python-format
msgid " By %(filter_title)s "
msgstr " por %(filter_title)s "
#: templates/admin/popup_response.html:3
msgid "Popup closing..."
msgstr "Pop-up fechando..."
+171 -126
View File
@@ -9,176 +9,221 @@ import colorfield.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Theme', name="Theme",
fields=[ fields=[
('id', (
"id",
models.AutoField( models.AutoField(
verbose_name='ID', verbose_name="ID",
serialize=False, serialize=False,
auto_created=True, auto_created=True,
primary_key=True)), primary_key=True,
('name', ),
),
("name", models.CharField(default=b"Django", max_length=50)),
("active", models.BooleanField(default=True)),
(
"title",
models.CharField( models.CharField(
default=b'Django', default=b"Django administration", max_length=50, blank=True
max_length=50)), ),
('active', ),
models.BooleanField( (
default=True)), "title_visible",
('title', models.BooleanField(default=True, verbose_name=b"visible"),
models.CharField( ),
default=b'Django administration', (
max_length=50, "logo",
blank=True)), models.FileField(upload_to=b"admin-interface/logo/", blank=True),
('title_visible', ),
models.BooleanField( (
default=True, "logo_visible",
verbose_name=b'visible')), models.BooleanField(default=True, verbose_name=b"visible"),
('logo', ),
models.FileField( (
upload_to=b'admin-interface/logo/', "css_header_background_color",
blank=True)),
('logo_visible',
models.BooleanField(
default=True,
verbose_name=b'visible')),
('css_header_background_color',
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#0C4B33', default=b"#0C4B33",
help_text=b'#0C4B33', help_text=b"#0C4B33",
max_length=10, max_length=10,
verbose_name=b'background color', verbose_name=b"background color",
blank=True)), blank=True,
('css_header_title_color', ),
),
(
"css_header_title_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#F5DD5D', default=b"#F5DD5D",
help_text=b'#F5DD5D', help_text=b"#F5DD5D",
max_length=10, max_length=10,
verbose_name=b'title color', verbose_name=b"title color",
blank=True)), blank=True,
('css_header_text_color', ),
),
(
"css_header_text_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#44B78B', default=b"#44B78B",
help_text=b'#44B78B', help_text=b"#44B78B",
max_length=10, max_length=10,
verbose_name=b'text color', verbose_name=b"text color",
blank=True)), blank=True,
('css_header_link_color', ),
),
(
"css_header_link_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#FFFFFF', default=b"#FFFFFF",
help_text=b'#FFFFFF', help_text=b"#FFFFFF",
max_length=10, max_length=10,
verbose_name=b'link color', verbose_name=b"link color",
blank=True)), blank=True,
('css_header_link_hover_color', ),
),
(
"css_header_link_hover_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#C9F0DD', default=b"#C9F0DD",
help_text=b'#C9F0DD', help_text=b"#C9F0DD",
max_length=10, max_length=10,
verbose_name=b'link hover color', verbose_name=b"link hover color",
blank=True)), blank=True,
('css_module_background_color', ),
),
(
"css_module_background_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#44B78B', default=b"#44B78B",
help_text=b'#44B78B', help_text=b"#44B78B",
max_length=10, max_length=10,
verbose_name=b'background color', verbose_name=b"background color",
blank=True)), blank=True,
('css_module_text_color', ),
),
(
"css_module_text_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#FFFFFF', default=b"#FFFFFF",
help_text=b'#FFFFFF', help_text=b"#FFFFFF",
max_length=10, max_length=10,
verbose_name=b'text color', verbose_name=b"text color",
blank=True)), blank=True,
('css_module_link_color', ),
),
(
"css_module_link_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#FFFFFF', default=b"#FFFFFF",
help_text=b'#FFFFFF', help_text=b"#FFFFFF",
max_length=10, max_length=10,
verbose_name=b'link color', verbose_name=b"link color",
blank=True)), blank=True,
('css_module_link_hover_color', ),
),
(
"css_module_link_hover_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#C9F0DD', default=b"#C9F0DD",
help_text=b'#C9F0DD', help_text=b"#C9F0DD",
max_length=10, max_length=10,
verbose_name=b'link hover color', verbose_name=b"link hover color",
blank=True)), blank=True,
('css_module_rounded_corners', ),
models.BooleanField( ),
default=True, (
verbose_name=b'rounded corners')), "css_module_rounded_corners",
('css_generic_link_color', models.BooleanField(default=True, verbose_name=b"rounded corners"),
),
(
"css_generic_link_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#0C3C26', default=b"#0C3C26",
help_text=b'#0C3C26', help_text=b"#0C3C26",
max_length=10, max_length=10,
verbose_name=b'link color', verbose_name=b"link color",
blank=True)), blank=True,
('css_generic_link_hover_color', ),
),
(
"css_generic_link_hover_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#156641', default=b"#156641",
help_text=b'#156641', help_text=b"#156641",
max_length=10, max_length=10,
verbose_name=b'link hover color', verbose_name=b"link hover color",
blank=True)), blank=True,
('css_save_button_background_color', ),
),
(
"css_save_button_background_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#0C4B33', default=b"#0C4B33",
help_text=b'#0C4B33', help_text=b"#0C4B33",
max_length=10, max_length=10,
verbose_name=b'background color', verbose_name=b"background color",
blank=True)), blank=True,
('css_save_button_background_hover_color', ),
),
(
"css_save_button_background_hover_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#0C3C26', default=b"#0C3C26",
help_text=b'#0C3C26', help_text=b"#0C3C26",
max_length=10, max_length=10,
verbose_name=b'background hover color', verbose_name=b"background hover color",
blank=True)), blank=True,
('css_save_button_text_color', ),
),
(
"css_save_button_text_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#FFFFFF', default=b"#FFFFFF",
help_text=b'#FFFFFF', help_text=b"#FFFFFF",
max_length=10, max_length=10,
verbose_name=b'text color', verbose_name=b"text color",
blank=True)), blank=True,
('css_delete_button_background_color', ),
),
(
"css_delete_button_background_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#BA2121', default=b"#BA2121",
help_text=b'#BA2121', help_text=b"#BA2121",
max_length=10, max_length=10,
verbose_name=b'background color', verbose_name=b"background color",
blank=True)), blank=True,
('css_delete_button_background_hover_color', ),
),
(
"css_delete_button_background_hover_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#A41515', default=b"#A41515",
help_text=b'#A41515', help_text=b"#A41515",
max_length=10, max_length=10,
verbose_name=b'background hover color', verbose_name=b"background hover color",
blank=True)), blank=True,
('css_delete_button_text_color', ),
),
(
"css_delete_button_text_color",
colorfield.fields.ColorField( colorfield.fields.ColorField(
default=b'#FFFFFF', default=b"#FFFFFF",
help_text=b'#FFFFFF', help_text=b"#FFFFFF",
max_length=10, max_length=10,
verbose_name=b'text color', verbose_name=b"text color",
blank=True)), blank=True,
('css', ),
models.TextField( ),
blank=True)), ("css", models.TextField(blank=True)),
('list_filter_dropdown', ("list_filter_dropdown", models.BooleanField(default=False)),
models.BooleanField(
default=False)),
], ],
options={ options={
'verbose_name': 'Theme', "verbose_name": "Theme",
'verbose_name_plural': 'Themes', "verbose_name_plural": "Themes",
}, },
), ),
] ]
@@ -10,51 +10,54 @@ import colorfield.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0001_initial'), ("admin_interface", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='list_filter_dropdown', name="list_filter_dropdown",
field=models.BooleanField( field=models.BooleanField(default=False, verbose_name=b"use dropdown"),
default=False,
verbose_name=b'use dropdown'),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_active', name="related_modal_active",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name=b"active"),
default=True,
verbose_name=b'active'),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_background_color', name="related_modal_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default=b'#000000', default=b"#000000",
help_text=b'#000000', help_text=b"#000000",
max_length=10, max_length=10,
verbose_name=b'background color'), verbose_name=b"background color",
),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_background_opacity', name="related_modal_background_opacity",
field=models.FloatField( field=models.FloatField(
choices=[ choices=[
(0.1, b'10%'), (0.2, b'20%'), (0.3, b'30%'), (0.1, b"10%"),
(0.4, b'40%'), (0.5, b'50%'), (0.6, b'60%'), (0.2, b"20%"),
(0.7, b'70%'), (0.8, b'80%'), (0.9, b'90%')], (0.3, b"30%"),
(0.4, b"40%"),
(0.5, b"50%"),
(0.6, b"60%"),
(0.7, b"70%"),
(0.8, b"80%"),
(0.9, b"90%"),
],
default=0.2, default=0.2,
help_text=b'20%', help_text=b"20%",
verbose_name=b'background opacity'), verbose_name=b"background opacity",
),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_rounded_corners', name="related_modal_rounded_corners",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name=b"rounded corners"),
default=True,
verbose_name=b'rounded corners'),
), ),
] ]
@@ -10,26 +10,28 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0002_add_related_modal'), ("admin_interface", "0002_add_related_modal"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='logo_color', name="logo_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='logo color'), verbose_name="logo color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='logo', name="logo",
field=models.FileField( field=models.FileField(
blank=True, blank=True,
help_text='(leave blank to use the default Django logo)', help_text="(leave blank to use the default Django logo)",
upload_to='admin-interface/logo/'), upload_to="admin-interface/logo/",
),
), ),
] ]
@@ -8,13 +8,13 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0003_add_logo_color'), ("admin_interface", "0003_add_logo_color"),
] ]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='theme', model_name="theme",
old_name='css_header_title_color', old_name="css_header_title_color",
new_name='title_color', new_name="title_color",
), ),
] ]
@@ -8,15 +8,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0004_rename_title_color'), ("admin_interface", "0004_rename_title_color"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='recent_actions_visible', name="recent_actions_visible",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="visible"),
default=True,
verbose_name='visible'),
), ),
] ]
+149 -138
View File
@@ -10,257 +10,268 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0005_add_recent_actions_visible'), ("admin_interface", "0005_add_recent_actions_visible"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_delete_button_background_color', name="css_delete_button_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#BA2121', default="#BA2121",
help_text='#BA2121', help_text="#BA2121",
max_length=10, max_length=10,
verbose_name='background color'), verbose_name="background color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_delete_button_background_hover_color', name="css_delete_button_background_hover_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#A41515', default="#A41515",
help_text='#A41515', help_text="#A41515",
max_length=10, max_length=10,
verbose_name='background hover color'), verbose_name="background hover color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_delete_button_text_color', name="css_delete_button_text_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='text color'), verbose_name="text color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_generic_link_color', name="css_generic_link_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#0C3C26', default="#0C3C26",
help_text='#0C3C26', help_text="#0C3C26",
max_length=10, max_length=10,
verbose_name='link color'), verbose_name="link color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_generic_link_hover_color', name="css_generic_link_hover_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#156641', default="#156641",
help_text='#156641', help_text="#156641",
max_length=10, max_length=10,
verbose_name='link hover color'), verbose_name="link hover color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_header_background_color', name="css_header_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#0C4B33', default="#0C4B33",
help_text='#0C4B33', help_text="#0C4B33",
max_length=10, max_length=10,
verbose_name='background color'), verbose_name="background color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_header_link_color', name="css_header_link_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='link color'), verbose_name="link color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_header_link_hover_color', name="css_header_link_hover_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#C9F0DD', default="#C9F0DD",
help_text='#C9F0DD', help_text="#C9F0DD",
max_length=10, max_length=10,
verbose_name='link hover color'), verbose_name="link hover color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_header_text_color', name="css_header_text_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#44B78B', default="#44B78B",
help_text='#44B78B', help_text="#44B78B",
max_length=10, max_length=10,
verbose_name='text color'), verbose_name="text color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_module_background_color', name="css_module_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#44B78B', default="#44B78B",
help_text='#44B78B', help_text="#44B78B",
max_length=10, max_length=10,
verbose_name='background color'), verbose_name="background color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_module_link_color', name="css_module_link_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='link color'), verbose_name="link color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_module_link_hover_color', name="css_module_link_hover_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#C9F0DD', default="#C9F0DD",
help_text='#C9F0DD', help_text="#C9F0DD",
max_length=10, max_length=10,
verbose_name='link hover color'), verbose_name="link hover color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_module_rounded_corners', name="css_module_rounded_corners",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="rounded corners"),
default=True,
verbose_name='rounded corners'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_module_text_color', name="css_module_text_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='text color'), verbose_name="text color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_save_button_background_color', name="css_save_button_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#0C4B33', default="#0C4B33",
help_text='#0C4B33', help_text="#0C4B33",
max_length=10, max_length=10,
verbose_name='background color'), verbose_name="background color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_save_button_background_hover_color', name="css_save_button_background_hover_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#0C3C26', default="#0C3C26",
help_text='#0C3C26', help_text="#0C3C26",
max_length=10, max_length=10,
verbose_name='background hover color'), verbose_name="background hover color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css_save_button_text_color', name="css_save_button_text_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='text color'), verbose_name="text color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='list_filter_dropdown', name="list_filter_dropdown",
field=models.BooleanField( field=models.BooleanField(default=False, verbose_name="use dropdown"),
default=False,
verbose_name='use dropdown'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='logo_visible', name="logo_visible",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="visible"),
default=True,
verbose_name='visible'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='name', name="name",
field=models.CharField( field=models.CharField(default="Django", max_length=50),
default='Django',
max_length=50),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='related_modal_active', name="related_modal_active",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="active"),
default=True,
verbose_name='active'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='related_modal_background_color', name="related_modal_background_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#000000', default="#000000",
help_text='#000000', help_text="#000000",
max_length=10, max_length=10,
verbose_name='background color'), verbose_name="background color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='related_modal_background_opacity', name="related_modal_background_opacity",
field=models.FloatField( field=models.FloatField(
choices=[ choices=[
(0.1, '10%'), (0.2, '20%'), (0.3, '30%'), (0.1, "10%"),
(0.4, '40%'), (0.5, '50%'), (0.6, '60%'), (0.2, "20%"),
(0.7, '70%'), (0.8, '80%'), (0.9, '90%')], (0.3, "30%"),
(0.4, "40%"),
(0.5, "50%"),
(0.6, "60%"),
(0.7, "70%"),
(0.8, "80%"),
(0.9, "90%"),
],
default=0.2, default=0.2,
help_text='20%', help_text="20%",
verbose_name='background opacity'), verbose_name="background opacity",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='related_modal_rounded_corners', name="related_modal_rounded_corners",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="rounded corners"),
default=True,
verbose_name='rounded corners'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='title', name="title",
field=models.CharField( field=models.CharField(
blank=True, blank=True, default="Django administration", max_length=50
default='Django administration', ),
max_length=50),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='title_color', name="title_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#F5DD5D', default="#F5DD5D",
help_text='#F5DD5D', help_text="#F5DD5D",
max_length=10, max_length=10,
verbose_name='title color'), verbose_name="title color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='title_visible', name="title_visible",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="visible"),
default=True,
verbose_name='visible'),
), ),
] ]
@@ -8,17 +8,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0006_bytes_to_str'), ("admin_interface", "0006_bytes_to_str"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='favicon', name="favicon",
field=models.FileField( field=models.FileField(
blank=True, blank=True,
help_text='(.ico|.png|.gif - 16x16|32x32 px)', help_text="(.ico|.png|.gif - 16x16|32x32 px)",
upload_to='admin-interface/favicon/', upload_to="admin-interface/favicon/",
verbose_name='favicon'), verbose_name="favicon",
),
), ),
] ]
@@ -8,25 +8,32 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0007_add_favicon'), ("admin_interface", "0007_add_favicon"),
] ]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(
model_name='theme', model_name="theme", name="related_modal_background_opacity"
name='related_modal_background_opacity'
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_background_opacity', name="related_modal_background_opacity",
field=models.CharField( field=models.CharField(
choices=[ choices=[
('0.1', '10%'), ('0.2', '20%'), ('0.3', '30%'), ("0.1", "10%"),
('0.4', '40%'), ('0.5', '50%'), ('0.6', '60%'), ("0.2", "20%"),
('0.7', '70%'), ('0.8', '80%'), ('0.9', '90%')], ("0.3", "30%"),
default='0.3', ("0.4", "40%"),
help_text='20%', ("0.5", "50%"),
("0.6", "60%"),
("0.7", "70%"),
("0.8", "80%"),
("0.9", "90%"),
],
default="0.3",
help_text="20%",
max_length=5, max_length=5,
verbose_name='background opacity'), verbose_name="background opacity",
),
), ),
] ]
@@ -8,28 +8,28 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0008_change_related_modal_background_opacity_type'), ("admin_interface", "0008_change_related_modal_background_opacity_type"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='env', name="env",
field=models.CharField( field=models.CharField(
choices=[ choices=[
('development', 'Development'), ("development", "Development"),
('testing', 'Testing'), ("testing", "Testing"),
('staging', 'Staging'), ("staging", "Staging"),
('production', 'Production')], ("production", "Production"),
default='development', ],
default="development",
max_length=50, max_length=50,
verbose_name='enviroment'), verbose_name="enviroment",
),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='env_visible', name="env_visible",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="visible"),
default=True,
verbose_name='visible'),
), ),
] ]
@@ -8,62 +8,60 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0009_add_enviroment'), ("admin_interface", "0009_add_enviroment"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='active', name="active",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="active"),
default=True,
verbose_name='active'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='css', name="css",
field=models.TextField( field=models.TextField(blank=True, verbose_name="text color"),
blank=True,
verbose_name='text color'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='env', name="env",
field=models.CharField( field=models.CharField(
choices=[ choices=[
('development', 'Development'), ("development", "Development"),
('testing', 'Testing'), ("testing", "Testing"),
('staging', 'Staging'), ("staging", "Staging"),
('production', 'Production') ("production", "Production"),
], ],
default='development', default="development",
max_length=50, max_length=50,
verbose_name='environment'), verbose_name="environment",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='logo', name="logo",
field=models.FileField( field=models.FileField(
blank=True, blank=True,
help_text='Leave blank to use the default Django logo', help_text="Leave blank to use the default Django logo",
upload_to='admin-interface/logo/', upload_to="admin-interface/logo/",
verbose_name='logo'), verbose_name="logo",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='name', name="name",
field=models.CharField( field=models.CharField(
default='Django', default="Django", max_length=50, verbose_name="name"
max_length=50, ),
verbose_name='name'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='title', name="title",
field=models.CharField( field=models.CharField(
blank=True, blank=True,
default='Django administration', default="Django administration",
max_length=50, max_length=50,
verbose_name='title'), verbose_name="title",
),
), ),
] ]
@@ -10,50 +10,48 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0010_add_localization'), ("admin_interface", "0010_add_localization"),
] ]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='theme', model_name="theme",
old_name='env', old_name="env",
new_name='env_name', new_name="env_name",
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='env_name', name="env_name",
field=models.CharField( field=models.CharField(blank=True, max_length=50, verbose_name="name"),
blank=True,
max_length=50,
verbose_name='name'),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='env_color', name="env_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#E74C3C', default="#E74C3C",
help_text='(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: #3498DB)', help_text="(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: #3498DB)",
max_length=10, max_length=10,
verbose_name='color'), verbose_name="color",
),
), ),
migrations.RenameField( migrations.RenameField(
model_name='theme', model_name="theme",
old_name='env_visible', old_name="env_visible",
new_name='env_visible_in_header', new_name="env_visible_in_header",
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='env_visible_in_header', name="env_visible_in_header",
field=models.BooleanField( field=models.BooleanField(
default=True, default=True, verbose_name="visible in header (marker and name)"
verbose_name='visible in header (marker and name)'), ),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='env_visible_in_favicon', name="env_visible_in_favicon",
field=models.BooleanField( field=models.BooleanField(
default=True, default=True, verbose_name="visible in favicon (marker)"
verbose_name='visible in favicon (marker)'), ),
), ),
] ]
@@ -10,28 +10,30 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0011_add_environment_options'), ("admin_interface", "0011_add_environment_options"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='logo_color', name="logo_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='color'), verbose_name="color",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='title_color', name="title_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#F5DD5D', default="#F5DD5D",
help_text='#F5DD5D', help_text="#F5DD5D",
max_length=10, max_length=10,
verbose_name='color'), verbose_name="color",
),
), ),
] ]
@@ -8,15 +8,15 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0012_update_verbose_names'), ("admin_interface", "0012_update_verbose_names"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='related_modal_close_button_visible', name="related_modal_close_button_visible",
field=models.BooleanField( field=models.BooleanField(
default=True, default=True, verbose_name="close button visible"
verbose_name='close button visible'), ),
), ),
] ]
@@ -8,17 +8,15 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0013_add_related_modal_close_button'), ("admin_interface", "0013_add_related_modal_close_button"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='name', name="name",
field=models.CharField( field=models.CharField(
default='Django', default="Django", max_length=50, unique=True, verbose_name="name"
max_length=50, ),
unique=True,
verbose_name='name'),
), ),
] ]
@@ -8,15 +8,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0014_name_unique'), ("admin_interface", "0014_name_unique"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='language_chooser_active', name="language_chooser_active",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="active"),
default=True,
verbose_name='active'),
), ),
] ]
@@ -8,20 +8,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0015_add_language_chooser_active'), ("admin_interface", "0015_add_language_chooser_active"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='language_chooser_display', name="language_chooser_display",
field=models.CharField( field=models.CharField(
choices=[ choices=[("code", "code"), ("name", "name")],
('code', 'code'), default="code",
('name', 'name')
],
default='code',
max_length=10, max_length=10,
verbose_name='display'), verbose_name="display",
),
), ),
] ]
@@ -8,15 +8,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0016_add_language_chooser_display'), ("admin_interface", "0016_add_language_chooser_display"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='list_filter_dropdown', name="list_filter_dropdown",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="use dropdown"),
default=True,
verbose_name='use dropdown'),
), ),
] ]
@@ -8,15 +8,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0017_change_list_filter_dropdown'), ("admin_interface", "0017_change_list_filter_dropdown"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='list_filter_sticky', name="list_filter_sticky",
field=models.BooleanField( field=models.BooleanField(default=True, verbose_name="sticky position"),
default=True,
verbose_name='sticky position'),
), ),
] ]
@@ -8,22 +8,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0018_theme_list_filter_sticky'), ("admin_interface", "0018_theme_list_filter_sticky"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='form_pagination_sticky', name="form_pagination_sticky",
field=models.BooleanField( field=models.BooleanField(default=False, verbose_name="sticky pagination"),
default=False,
verbose_name='sticky pagination'),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='form_submit_sticky', name="form_submit_sticky",
field=models.BooleanField( field=models.BooleanField(default=False, verbose_name="sticky submit"),
default=False,
verbose_name='sticky submit'),
), ),
] ]
@@ -12,35 +12,38 @@ def default_link_selected(apps, schema_editor):
Theme = apps.get_model("admin_interface", "Theme") Theme = apps.get_model("admin_interface", "Theme")
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
Theme.objects.using(db_alias).update( Theme.objects.using(db_alias).update(
css_module_link_selected_color=F('css_module_link_color')) css_module_link_selected_color=F("css_module_link_color")
)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0019_add_form_sticky'), ("admin_interface", "0019_add_form_sticky"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='css_module_background_selected_color', name="css_module_background_selected_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFCC', default="#FFFFCC",
help_text='#FFFFCC', help_text="#FFFFCC",
max_length=10, max_length=10,
verbose_name='background selected color'), verbose_name="background selected color",
),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='css_module_link_selected_color', name="css_module_link_selected_color",
field=colorfield.fields.ColorField( field=colorfield.fields.ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name='link selected color'), verbose_name="link selected color",
), ),
migrations.RunPython(default_link_selected), ),
migrations.RunPython(default_link_selected,migrations.RunPython.noop),
] ]
@@ -10,36 +10,38 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0020_module_selected_colors'), ("admin_interface", "0020_module_selected_colors"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='favicon', name="favicon",
field=models.FileField( field=models.FileField(
blank=True, blank=True,
help_text='(.ico|.png|.gif - 16x16|32x32 px)', help_text="(.ico|.png|.gif - 16x16|32x32 px)",
upload_to='admin-interface/favicon/', upload_to="admin-interface/favicon/",
validators=[ validators=[
FileExtensionValidator(allowed_extensions=[ FileExtensionValidator(
'gif', 'ico', 'jpg', 'jpeg', 'png', 'svg' allowed_extensions=["gif", "ico", "jpg", "jpeg", "png", "svg"]
]) )
], ],
verbose_name='favicon'), verbose_name="favicon",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='theme', model_name="theme",
name='logo', name="logo",
field=models.FileField( field=models.FileField(
blank=True, blank=True,
help_text='Leave blank to use the default Django logo', help_text="Leave blank to use the default Django logo",
upload_to='admin-interface/logo/', upload_to="admin-interface/logo/",
validators=[ validators=[
FileExtensionValidator(allowed_extensions=[ FileExtensionValidator(
'gif', 'jpg', 'jpeg', 'png', 'svg' allowed_extensions=["gif", "jpg", "jpeg", "png", "svg"]
]) )
], ],
verbose_name='logo'), verbose_name="logo",
),
), ),
] ]
@@ -8,18 +8,22 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0021_file_extension_validator'), ("admin_interface", "0021_file_extension_validator"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='logo_max_height', name="logo_max_height",
field=models.PositiveSmallIntegerField(blank=True, default=100, verbose_name='max height'), field=models.PositiveSmallIntegerField(
blank=True, default=100, verbose_name="max height"
),
), ),
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='logo_max_width', name="logo_max_width",
field=models.PositiveSmallIntegerField(blank=True, default=400, verbose_name='max width'), field=models.PositiveSmallIntegerField(
blank=True, default=400, verbose_name="max width"
),
), ),
] ]
@@ -8,13 +8,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0022_add_logo_max_width_and_height'), ("admin_interface", "0022_add_logo_max_width_and_height"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='theme', model_name="theme",
name='foldable_apps', name="foldable_apps",
field=models.BooleanField(default=True, verbose_name='foldable apps'), field=models.BooleanField(default=True, verbose_name="foldable apps"),
), ),
] ]
@@ -8,12 +8,12 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('admin_interface', '0023_theme_foldable_apps'), ("admin_interface", "0023_theme_foldable_apps"),
] ]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(
model_name='theme', model_name="theme",
name='css', name="css",
), ),
] ]
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("admin_interface", "0024_remove_theme_css"),
]
operations = [
migrations.AddField(
model_name="theme",
name="demo",
field=models.BooleanField(default=False, verbose_name="demo"),
),
]
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("admin_interface", "0025_add_demo_option"),
]
operations = [
migrations.AddField(
model_name="theme",
name="user",
field=models.ForeignKey('auth.User', on_delete=models.CASCADE, null=True, blank=True, verbose_name="active for user"),
),
]
@@ -0,0 +1,37 @@
# Generated by Django 3.2.13 on 2022-04-28 16:03
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),
('admin_interface', '0026_add_user_option'),
]
operations = [
migrations.RemoveField(
model_name='theme',
name='user',
),
migrations.CreateModel(
name='UserTheme',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('theme', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='admin_interface.theme')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, unique=True)),
],
options={
'verbose_name': 'Users theme',
'verbose_name_plural': 'Users themes',
},
),
migrations.AddField(
model_name='theme',
name='users',
field=models.ManyToManyField(through='admin_interface.UserTheme', to=settings.AUTH_USER_MODEL),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2022-08-25 14:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('admin_interface', '0027_usertheme_m2m'),
]
operations = [
migrations.AlterField(
model_name='theme',
name='demo',
field=models.BooleanField(default=False, verbose_name='is demo'),
),
]
@@ -0,0 +1,32 @@
# Generated by Django 4.0.3 on 2022-10-25 13:59
from django.conf import settings
import django.db.models.deletion
from django.db import connection, migrations, models, transaction
def forward(apps, schema_editor):
Theme = apps.get_model("admin_interface", "Theme")
if len(Theme.objects.all()) == 1 and Theme.objects.first().name == 'Django':
with transaction.atomic():
cursor = connection.cursor()
cursor.execute("""truncate table "admin_interface_theme" restart identity;""")
def reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('admin_interface', '0028_alter_theme_demo'),
]
operations = [
migrations.RunPython(forward, reverse),
migrations.AlterField(
model_name='usertheme',
name='user',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.0.3 on 2023-01-30 14:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('admin_interface', '0029_auto_20221025_1559'),
]
operations = [
migrations.AddField(
model_name='theme',
name='default',
field=models.BooleanField(default=False, verbose_name='default'),
),
]
+269 -175
View File
@@ -2,20 +2,31 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from admin_interface.cache import del_cached_active_theme import inspect
from admin_interface.compat import FileExtensionValidator, force_str, gettext_lazy as _
from colorfield.fields import ColorField from colorfield.fields import ColorField
from django.db import models from django.db import models
from django.db.models.signals import post_delete, post_save, pre_save from django.db.models.signals import post_delete, post_save, pre_save
from six import python_2_unicode_compatible from six import python_2_unicode_compatible
from admin_interface.cache import del_cached_active_theme
from admin_interface.compat import FileExtensionValidator, force_str
from admin_interface.compat import gettext_lazy as _
@python_2_unicode_compatible
class UserTheme(models.Model):
class Meta:
verbose_name = 'Users theme'
verbose_name_plural = 'Users themes'
user = models.OneToOneField(
'auth.User', on_delete=models.CASCADE, null=True)
theme = models.ForeignKey('Theme', on_delete=models.CASCADE)
@python_2_unicode_compatible @python_2_unicode_compatible
class Theme(models.Model): class Theme(models.Model):
@staticmethod @staticmethod
def post_migrate_handler(**kwargs): def post_migrate_handler(**kwargs):
del_cached_active_theme() del_cached_active_theme()
@@ -26,26 +37,27 @@ class Theme(models.Model):
del_cached_active_theme() del_cached_active_theme()
Theme.get_active_theme() Theme.get_active_theme()
@staticmethod # @staticmethod
def post_save_handler(instance, **kwargs): # def post_save_handler(instance, **kwargs):
del_cached_active_theme() # del_cached_active_theme()
if instance.active: # if instance.active:
Theme.objects.exclude(pk=instance.pk).update(active=False) # Theme.objects.exclude(pk=instance.pk).update(active=False)
Theme.get_active_theme() # Theme.get_active_theme()
@staticmethod # @staticmethod
def pre_save_handler(instance, **kwargs): # def pre_save_handler(instance, **kwargs):
if instance.pk is None: # if instance.pk is None:
try: # try:
obj = Theme.objects.get(name=instance.name) # obj = Theme.objects.get(name=instance.name)
if obj: # if obj:
instance.pk = obj.pk # instance.pk = obj.pk
except Theme.DoesNotExist: # except Theme.DoesNotExist:
pass # pass
@staticmethod @staticmethod
def get_active_theme(): def get_active_theme():
objs_manager = Theme.objects objs_manager = Theme.objects
user_theme_manager = UserTheme.objects
objs_active_qs = objs_manager.filter(active=True) objs_active_qs = objs_manager.filter(active=True)
objs_active_ls = list(objs_active_qs) objs_active_ls = list(objs_active_qs)
objs_active_count = len(objs_active_ls) objs_active_count = len(objs_active_ls)
@@ -54,294 +66,376 @@ class Theme(models.Model):
obj = objs_manager.all().first() obj = objs_manager.all().first()
if obj: if obj:
obj.set_active() obj.set_active()
else: # else:
obj = objs_manager.create() # obj = objs_manager.create()
elif objs_active_count == 1: elif objs_active_count == 1:
obj = objs_active_ls[0] obj = objs_active_ls[0]
elif objs_active_count > 1: elif objs_active_count > 1:
obj = objs_active_ls[-1] for frame_record in inspect.stack():
obj.set_active() if frame_record[3] == 'get_response':
request = frame_record[0].f_locals['request']
user = request.user
break
else:
request = None
try:
return user_theme_manager.filter(user=user, theme__active=True).first().theme
except:
objs_default_qs = objs_active_qs.filter(default=True)
if len(objs_default_qs) == 0:
obj = objs_active_qs.first()
if obj:
obj.set_default()
else:
obj = objs_default_qs.first()
return obj return obj
name = models.CharField( name = models.CharField(
unique=True, unique=True, max_length=50, default="Django", verbose_name=_("name")
max_length=50, )
default='Django', active = models.BooleanField(default=True, verbose_name=_("active"))
verbose_name=_('name'))
active = models.BooleanField( demo = models.BooleanField(default=False, verbose_name=_("is demo"))
default=True,
verbose_name=_('active')) default = models.BooleanField(default=False, verbose_name="default")
users = models.ManyToManyField('auth.User', through=UserTheme)
title = models.CharField( title = models.CharField(
max_length=50, max_length=50,
default=_('Django administration'), default=_("Django administration"),
blank=True, blank=True,
verbose_name=_('title')) verbose_name=_("title"),
)
title_color = ColorField( title_color = ColorField(
blank=True, blank=True,
default='#F5DD5D', default="#F5DD5D",
help_text='#F5DD5D', help_text="#F5DD5D",
max_length=10, max_length=10,
verbose_name=_('color')) verbose_name=_("color"),
)
title_visible = models.BooleanField( title_visible = models.BooleanField(
default=True, default=True, verbose_name=_("visible"))
verbose_name=_('visible'))
logo = models.FileField( logo = models.FileField(
upload_to='admin-interface/logo/', upload_to="admin-interface/logo/",
blank=True, blank=True,
validators=[FileExtensionValidator( validators=[
allowed_extensions=['gif', 'jpg', 'jpeg', 'png', 'svg'])], FileExtensionValidator(
help_text=_('Leave blank to use the default Django logo'), allowed_extensions=["gif", "jpg", "jpeg", "png", "svg"]
verbose_name=_('logo')) )
],
help_text=_("Leave blank to use the default Django logo"),
verbose_name=_("logo"),
)
logo_color = ColorField( logo_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('color')) verbose_name=_("color"),
)
logo_max_width = models.PositiveSmallIntegerField( logo_max_width = models.PositiveSmallIntegerField(
blank=True, blank=True, default=400, verbose_name=_("max width")
default=400, )
verbose_name=_('max width'))
logo_max_height = models.PositiveSmallIntegerField( logo_max_height = models.PositiveSmallIntegerField(
blank=True, blank=True, default=100, verbose_name=_("max height")
default=100, )
verbose_name=_('max height')) logo_visible = models.BooleanField(default=True, verbose_name=_("visible"))
logo_visible = models.BooleanField(
default=True,
verbose_name=_('visible'))
favicon = models.FileField( favicon = models.FileField(
upload_to='admin-interface/favicon/', upload_to="admin-interface/favicon/",
blank=True, blank=True,
validators=[FileExtensionValidator( validators=[
allowed_extensions=['gif', 'ico', 'jpg', 'jpeg', 'png', 'svg'])], FileExtensionValidator(
help_text=_('(.ico|.png|.gif - 16x16|32x32 px)'), allowed_extensions=["gif", "ico", "jpg", "jpeg", "png", "svg"]
verbose_name=_('favicon')) )
],
help_text=_("(.ico|.png|.gif - 16x16|32x32 px)"),
verbose_name=_("favicon"),
)
env_name = models.CharField( env_name = models.CharField(
blank=True, blank=True, max_length=50, verbose_name=_("name"))
max_length=50,
verbose_name=_('name'))
env_color = ColorField( env_color = ColorField(
blank=True, blank=True,
default='#E74C3C', default="#E74C3C",
help_text=_('(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: #3498DB)'), help_text=_(
"(red: #E74C3C, orange: #E67E22, yellow: #F1C40F, green: #2ECC71, blue: #3498DB)"
),
max_length=10, max_length=10,
verbose_name=_('color')) verbose_name=_("color"),
)
env_visible_in_header = models.BooleanField( env_visible_in_header = models.BooleanField(
default=True, default=True, verbose_name=_("visible in header (marker and name)")
verbose_name=_('visible in header (marker and name)')) )
env_visible_in_favicon = models.BooleanField( env_visible_in_favicon = models.BooleanField(
default=True, default=True, verbose_name=_("visible in favicon (marker)")
verbose_name=_('visible in favicon (marker)')) )
language_chooser_active = models.BooleanField( language_chooser_active = models.BooleanField(
default=True, default=True, verbose_name=_("active")
verbose_name=_('active')) )
language_chooser_display_choices = ( language_chooser_display_choices = (
('code', _('code'), ), (
('name', _('name'), ), "code",
_("code"),
),
(
"name",
_("name"),
),
) )
language_chooser_display = models.CharField( language_chooser_display = models.CharField(
max_length=10, max_length=10,
choices=language_chooser_display_choices, choices=language_chooser_display_choices,
default='code', default="code",
verbose_name=_('display')) verbose_name=_("display"),
)
css_header_background_color = ColorField( css_header_background_color = ColorField(
blank=True, blank=True,
default='#0C4B33', default="#0C4B33",
help_text='#0C4B33', help_text="#0C4B33",
max_length=10, max_length=10,
verbose_name=_('background color')) verbose_name=_("background color"),
)
css_header_text_color = ColorField( css_header_text_color = ColorField(
blank=True, blank=True,
default='#44B78B', default="#44B78B",
help_text='#44B78B', help_text="#44B78B",
max_length=10, max_length=10,
verbose_name=_('text color')) verbose_name=_("text color"),
)
css_header_link_color = ColorField( css_header_link_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('link color')) verbose_name=_("link color"),
)
css_header_link_hover_color = ColorField( css_header_link_hover_color = ColorField(
blank=True, blank=True,
default='#C9F0DD', default="#C9F0DD",
help_text='#C9F0DD', help_text="#C9F0DD",
max_length=10, max_length=10,
verbose_name=_('link hover color')) verbose_name=_("link hover color"),
)
css_module_background_color = ColorField( css_module_background_color = ColorField(
blank=True, blank=True,
default='#44B78B', default="#44B78B",
help_text='#44B78B', help_text="#44B78B",
max_length=10, max_length=10,
verbose_name=_('background color')) verbose_name=_("background color"),
)
css_module_background_selected_color = ColorField( css_module_background_selected_color = ColorField(
blank=True, blank=True,
default='#FFFFCC', default="#FFFFCC",
help_text='#FFFFCC', help_text="#FFFFCC",
max_length=10, max_length=10,
verbose_name=_('background selected color')) verbose_name=_("background selected color"),
)
css_module_text_color = ColorField( css_module_text_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('text color')) verbose_name=_("text color"),
)
css_module_link_color = ColorField( css_module_link_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('link color')) verbose_name=_("link color"),
)
css_module_link_selected_color = ColorField( css_module_link_selected_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('link selected color')) verbose_name=_("link selected color"),
)
css_module_link_hover_color = ColorField( css_module_link_hover_color = ColorField(
blank=True, blank=True,
default='#C9F0DD', default="#C9F0DD",
help_text='#C9F0DD', help_text="#C9F0DD",
max_length=10, max_length=10,
verbose_name=_('link hover color')) verbose_name=_("link hover color"),
)
css_module_rounded_corners = models.BooleanField( css_module_rounded_corners = models.BooleanField(
default=True, default=True, verbose_name=_("rounded corners")
verbose_name=_('rounded corners')) )
css_generic_link_color = ColorField( css_generic_link_color = ColorField(
blank=True, blank=True,
default='#0C3C26', default="#0C3C26",
help_text='#0C3C26', help_text="#0C3C26",
max_length=10, max_length=10,
verbose_name=_('link color')) verbose_name=_("link color"),
)
css_generic_link_hover_color = ColorField( css_generic_link_hover_color = ColorField(
blank=True, blank=True,
default='#156641', default="#156641",
help_text='#156641', help_text="#156641",
max_length=10, max_length=10,
verbose_name=_('link hover color')) verbose_name=_("link hover color"),
)
css_save_button_background_color = ColorField( css_save_button_background_color = ColorField(
blank=True, blank=True,
default='#0C4B33', default="#0C4B33",
help_text='#0C4B33', help_text="#0C4B33",
max_length=10, max_length=10,
verbose_name=_('background color')) verbose_name=_("background color"),
)
css_save_button_background_hover_color = ColorField( css_save_button_background_hover_color = ColorField(
blank=True, blank=True,
default='#0C3C26', default="#0C3C26",
help_text='#0C3C26', help_text="#0C3C26",
max_length=10, max_length=10,
verbose_name=_('background hover color')) verbose_name=_("background hover color"),
)
css_save_button_text_color = ColorField( css_save_button_text_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('text color')) verbose_name=_("text color"),
)
css_delete_button_background_color = ColorField( css_delete_button_background_color = ColorField(
blank=True, blank=True,
default='#BA2121', default="#BA2121",
help_text='#BA2121', help_text="#BA2121",
max_length=10, max_length=10,
verbose_name=_('background color')) verbose_name=_("background color"),
)
css_delete_button_background_hover_color = ColorField( css_delete_button_background_hover_color = ColorField(
blank=True, blank=True,
default='#A41515', default="#A41515",
help_text='#A41515', help_text="#A41515",
max_length=10, max_length=10,
verbose_name=_('background hover color')) verbose_name=_("background hover color"),
)
css_delete_button_text_color = ColorField( css_delete_button_text_color = ColorField(
blank=True, blank=True,
default='#FFFFFF', default="#FFFFFF",
help_text='#FFFFFF', help_text="#FFFFFF",
max_length=10, max_length=10,
verbose_name=_('text color')) verbose_name=_("text color"),
)
css = models.TextField(
blank=True,
verbose_name=_('text color'))
related_modal_active = models.BooleanField( related_modal_active = models.BooleanField(
default=True, default=True, verbose_name=_("active"))
verbose_name=_('active'))
related_modal_background_color = ColorField( related_modal_background_color = ColorField(
blank=True, blank=True,
default='#000000', default="#000000",
help_text='#000000', help_text="#000000",
max_length=10, max_length=10,
verbose_name=_('background color')) verbose_name=_("background color"),
)
related_modal_background_opacity_choices = ( related_modal_background_opacity_choices = (
('0.1', '10%', ), (
('0.2', '20%', ), "0.1",
('0.3', '30%', ), "10%",
('0.4', '40%', ), ),
('0.5', '50%', ), (
('0.6', '60%', ), "0.2",
('0.7', '70%', ), "20%",
('0.8', '80%', ), ),
('0.9', '90%', ), (
"0.3",
"30%",
),
(
"0.4",
"40%",
),
(
"0.5",
"50%",
),
(
"0.6",
"60%",
),
(
"0.7",
"70%",
),
(
"0.8",
"80%",
),
(
"0.9",
"90%",
),
) )
related_modal_background_opacity = models.CharField( related_modal_background_opacity = models.CharField(
max_length=5, max_length=5,
choices=related_modal_background_opacity_choices, choices=related_modal_background_opacity_choices,
default='0.3', default="0.3",
help_text='20%', help_text="20%",
verbose_name=_('background opacity')) verbose_name=_("background opacity"),
)
related_modal_rounded_corners = models.BooleanField( related_modal_rounded_corners = models.BooleanField(
default=True, default=True, verbose_name=_("rounded corners")
verbose_name=_('rounded corners')) )
related_modal_close_button_visible = models.BooleanField( related_modal_close_button_visible = models.BooleanField(
default=True, default=True, verbose_name=_("close button visible")
verbose_name=_('close button visible')) )
list_filter_dropdown = models.BooleanField( list_filter_dropdown = models.BooleanField(
default=True, default=True, verbose_name=_("use dropdown")
verbose_name=_('use dropdown')) )
list_filter_sticky = models.BooleanField( list_filter_sticky = models.BooleanField(
default=True, default=True, verbose_name=_("sticky position")
verbose_name=_('sticky position')) )
foldable_apps = models.BooleanField( foldable_apps = models.BooleanField(
default=True, default=True, verbose_name=_("foldable apps"))
verbose_name=_('foldable apps'))
recent_actions_visible = models.BooleanField( recent_actions_visible = models.BooleanField(
default=True, default=True, verbose_name=_("visible")
verbose_name=_('visible')) )
form_submit_sticky = models.BooleanField( form_submit_sticky = models.BooleanField(
default=False, default=False, verbose_name=_("sticky submit")
verbose_name=_('sticky submit')) )
form_pagination_sticky = models.BooleanField( form_pagination_sticky = models.BooleanField(
default=False, default=False, verbose_name=_("sticky pagination")
verbose_name=_('sticky pagination')) )
def set_active(self): def set_active(self):
self.active = True self.active = True
self.save() self.save()
class Meta: def set_default(self):
app_label = 'admin_interface' self.default = True
self.save()
verbose_name = _('Theme') def save(self):
verbose_name_plural = _('Themes') if self.default:
Theme.objects.update(default=False)
super().save()
class Meta:
app_label = "admin_interface"
verbose_name = _("Theme")
verbose_name_plural = _("Themes")
def __str__(self): def __str__(self):
return force_str(self.name) return force_str(self.name)
post_delete.connect(Theme.post_delete_handler, sender=Theme) post_delete.connect(Theme.post_delete_handler, sender=Theme)
post_save.connect(Theme.post_save_handler, sender=Theme) # post_save.connect(Theme.post_save_handler, sender=Theme)
pre_save.connect(Theme.pre_save_handler, sender=Theme) # pre_save.connect(Theme.pre_save_handler, sender=Theme)
+16 -10
View File
@@ -5,23 +5,29 @@ from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
def check_installed_app(app, app_dj_version_limit): def check_installed_app(app, max_dj_version=None):
dj_version = django.VERSION dj_version = django.VERSION
installed_apps = settings.INSTALLED_APPS installed_apps = settings.INSTALLED_APPS
if dj_version < app_dj_version_limit: if max_dj_version is None:
if app not in installed_apps: if app not in installed_apps:
raise ImproperlyConfigured( raise ImproperlyConfigured(
'\'{}\' needed before django {}.{}, ' "'{}' is required, " "add it to settings.INSTALLED_APPS.".format(app)
'add it to settings.INSTALLED_APPS.'.format( )
app, *app_dj_version_limit)) elif dj_version < max_dj_version:
if app not in installed_apps:
raise ImproperlyConfigured(
"'{}' is required before django {}.{}, "
"add it to settings.INSTALLED_APPS.".format(app, *max_dj_version)
)
else: else:
if app in installed_apps: if app in installed_apps:
raise ImproperlyConfigured( raise ImproperlyConfigured(
'\'{}\' not needed since django {}.{}, ' "'{}' is no more required since django {}.{}, "
'remove it from settings.INSTALLED_APPS.'.format( "remove it from settings.INSTALLED_APPS.".format(app, *max_dj_version)
app, *app_dj_version_limit)) )
def check_installed_apps(): def check_installed_apps():
check_installed_app('flat', (1, 9)) check_installed_app("colorfield")
check_installed_app('flat_responsive', (2, 0)) check_installed_app("flat", max_dj_version=(1, 9))
check_installed_app("flat_responsive", max_dj_version=(2, 0))
@@ -16,6 +16,7 @@
} }
windowRef = { windowRef = {
name: widgetName, name: widgetName,
location: windowRef.location,
close: function() { close: function() {
openerRef.dismissRelatedObjectModal(); openerRef.dismissRelatedObjectModal();
} }
@@ -108,6 +108,7 @@ if (typeof(django) !== 'undefined' && typeof(django.jQuery) !== 'undefined')
// open the popup using magnific popup // open the popup using magnific popup
$.magnificPopup.open({ $.magnificPopup.open({
mainClass: iframeInternalModalClass, mainClass: iframeInternalModalClass,
fixedContentPos: false,
showCloseBtn: true, showCloseBtn: true,
closeBtnInside: true, closeBtnInside: true,
items: { items: {
+5 -15
View File
@@ -2,19 +2,12 @@
{% load i18n static admin_interface_tags %} {% load i18n static admin_interface_tags %}
{% block title %} {% block title %}
{% get_admin_interface_theme as theme %}
{% if title %}{{ title }} | {% endif %}{% if theme.title %}{% trans theme.title %}{% else %}{{ site_title|default:_('Django administration') }}{% endif %} {% if title %}{{ title }} | {% endif %}{% if theme.title %}{% trans theme.title %}{% else %}{{ site_title|default:_('Django administration') }}{% endif %}
{% endblock %} {% endblock %}
{% block extrastyle %} {% block extrastyle %}
{% get_admin_interface_theme as theme %}
{% get_admin_interface_version as version %}
{% get_current_language as current_lang %} {% get_current_language as current_lang %}
<style type="text/css"> <style type="text/css">
/*
django-admin-interface {{ version }}
https://github.com/fabiocaccamo/django-admin-interface
*/
{% include "admin_interface/css/admin-interface.css" %} {% include "admin_interface/css/admin-interface.css" %}
{% include "admin_interface/css/admin-interface-fix.css" %} {% include "admin_interface/css/admin-interface-fix.css" %}
{% include "admin_interface/css/form-controls.css" %} {% include "admin_interface/css/form-controls.css" %}
@@ -39,12 +32,10 @@ https://github.com/fabiocaccamo/django-admin-interface
{% block blockbots %} {% block blockbots %}
{{ block.super }} {{ block.super }}
{% get_admin_interface_theme as theme %}
{% get_admin_interface_version as version %}
{# https://github.com/elky/django-flat-responsive#important-note #} {# https://github.com/elky/django-flat-responsive#important-note #}
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive.css' %}?v={{ version }}"> <link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive_rtl.css' %}?v={{ version }}" /> <link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive_rtl.css' %}">
{% include "admin_interface/favicon.html" %} {% include "admin_interface/favicon.html" %}
{% include "admin_interface/foldable-apps.html" %} {% include "admin_interface/foldable-apps.html" %}
{% include "admin_interface/related-modal.html" %} {% include "admin_interface/related-modal.html" %}
@@ -55,7 +46,6 @@ https://github.com/fabiocaccamo/django-admin-interface
{% endblock %} {% endblock %}
{% block bodyclass %} {% block bodyclass %}
{% get_admin_interface_theme as theme %}
flat-theme admin-interface flat-theme admin-interface
{% if theme.name %} {{ theme.name|slugify }}-theme {% endif %} {% if theme.name %} {{ theme.name|slugify }}-theme {% endif %}
{% if theme.foldable_apps %} foldable-apps {% endif %} {% if theme.foldable_apps %} foldable-apps {% endif %}
@@ -64,8 +54,8 @@ flat-theme admin-interface
{% endblock %} {% endblock %}
{% block branding %} {% block branding %}
{% get_admin_interface_theme as theme %}
<h1 id="site-name"> <h1 id="site-name">
<a href="{% url 'admin:index' %}">
{% if theme.logo_visible %} {% if theme.logo_visible %}
{% if theme.logo %} {% if theme.logo %}
<img class="logo" style="display:none;" src="{{ theme.logo.url }}" {% if theme.logo.width %}width="{{ theme.logo.width }}"{% endif %} {% if theme.logo.height %}height="{{ theme.logo.height }}"{% endif %}> <img class="logo" style="display:none;" src="{{ theme.logo.url }}" {% if theme.logo.width %}width="{{ theme.logo.width }}"{% endif %} {% if theme.logo.height %}height="{{ theme.logo.height }}"{% endif %}>
@@ -76,14 +66,14 @@ flat-theme admin-interface
{% if theme.title_visible %} {% if theme.title_visible %}
<span>{% if theme.title %}{% trans theme.title %}{% else %}{{ site_header|default:_('Django administration') }}{% endif %}</span> <span>{% if theme.title %}{% trans theme.title %}{% else %}{{ site_header|default:_('Django administration') }}{% endif %}</span>
{% endif %} {% endif %}
</a>
</h1> </h1>
{% endblock %} {% endblock %}
{% block welcome-msg %} {% block welcome-msg %}
{% get_admin_interface_theme as theme %}
{% if theme.language_chooser_active %} {% if theme.language_chooser_active %}
{% get_admin_interface_languages as languages %} {% get_admin_interface_languages as languages %}
{% include "admin_interface/language_chooser.html" %} {% include "admin_interface/language_chooser.html" %}
{% endif %} {% endif %}
{% if theme.env_visible_in_header %}<span class="environment-label {{ theme.env_name }}"></span><br>{% endif %}{{ block.super }}<br> {% if theme.env_visible_in_header %}<span class="environment-label"></span><br>{% endif %}{{ block.super }}<br>
{% endblock %} {% endblock %}
@@ -26,7 +26,7 @@
min-height: auto; min-height: auto;
padding: 10px 30px; padding: 10px 30px;
line-height: 30px; line-height: 30px;
align-items: flex-start; align-items: center;
justify-content: flex-start; justify-content: flex-start;
} }
@@ -35,7 +35,6 @@
} }
.admin-interface.login #header #branding h1 img.logo { .admin-interface.login #header #branding h1 img.logo {
max-width: 100%;
margin-right: 0; margin-right: 0;
} }
@@ -82,7 +81,7 @@
@media (max-width:1024px) { @media (max-width:1024px) {
.admin-interface #header { .admin-interface #header {
align-items: center; align-items: start;
} }
} }
@@ -93,12 +92,6 @@
display:inline-block !important; /* override inline display:none; */ display:inline-block !important; /* override inline display:none; */
} }
@media (max-width:400px) {
.admin-interface #branding h1 img.logo {
max-width: 100%;
}
}
.admin-interface #branding h1 span { .admin-interface #branding h1 span {
display: inline-block; display: inline-block;
} }
@@ -110,7 +103,7 @@
.admin-interface #user-tools { .admin-interface #user-tools {
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
white-space: nowrap; white-space: normal;
align-self: flex-start; align-self: flex-start;
} }
@@ -133,10 +133,16 @@
display: inline-block; display: inline-block;
} }
.admin-interface #branding h1 { .admin-interface #branding h1,
.admin-interface.login #header h1,
.admin-interface.login #header h1 a {
color: {{ theme.title_color }}; color: {{ theme.title_color }};
} }
.admin-interface #branding h1 a {
color: inherit;
}
.admin-interface #branding h1 .logo.default { .admin-interface #branding h1 .logo.default {
background-color: transparent; background-color: transparent;
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -145,21 +151,28 @@
background-image: url("data:image/svg+xml;utf8,<?xml version='1.0' encoding='utf-8'?><svg width='104px' height='36px' viewBox='0 0 104 36' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:sketch='http://www.bohemiancoding.com/sketch/ns'><g id='Page-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' sketch:type='MSPage'><g id='logo-django' sketch:type='MSArtboardGroup' transform='translate(-8.000000, -5.000000)' fill='{{ theme.logo_color|urlencode }}'><path d='M20.2602817,5 L25.9509859,5 L25.9509859,31.0824248 C23.0360563,31.6338042 20.8901408,31.8507285 18.5684507,31.8507285 C11.6180282,31.8434735 8,28.7383366 8,22.7747325 C8,17.0287781 11.8377465,13.2997118 17.7847887,13.2997118 C18.7076056,13.2997118 19.4107042,13.3722617 20.2602817,13.5899115 L20.2602817,5 L20.2602817,5 Z M20.2602817,18.1242821 C19.5938028,17.9066323 19.044507,17.8340823 18.3414085,17.8340823 C15.4630986,17.8340823 13.8005634,19.5897906 13.8005634,22.6666331 C13.8005634,25.6622196 15.3898592,27.316358 18.3047887,27.316358 C18.9346479,27.316358 19.4473239,27.2808085 20.2602817,27.1719836 L20.2602817,18.1242821 L20.2602817,18.1242821 Z M34.9960563,13.6987364 L34.9960563,26.7577235 C34.9960563,31.2550936 34.6591549,33.417807 33.6704225,35.2823401 C32.7476056,37.0750489 31.531831,38.2053768 29.0197183,39.453961 L23.7391549,36.9654985 C26.2512676,35.7981701 27.4670423,34.7665101 28.2433803,33.1921767 C29.056338,31.5822938 29.3126761,29.7177606 29.3126761,24.8133855 L29.3126761,13.6987364 L34.9960563,13.6987364 Z M29.3126761,5.02901997 L35.0033803,5.02901997 L35.0033803,10.8112493 L29.3126761,10.8112493 L29.3126761,5.02901997 Z M38.4302535,14.9828702 C40.9430986,13.8148163 43.3453521,13.2997118 45.9673239,13.2997118 C48.8895775,13.2997118 50.8077183,14.0687411 51.6580282,15.5705246 C52.1340845,16.4121037 52.2878873,17.5076077 52.2878873,19.8509704 L52.2878873,31.2993491 C49.7398873,31.6620987 46.5239437,31.922553 44.1649014,31.922553 C39.3970141,31.922553 37.2584225,30.2756696 37.2584225,26.6198787 C37.2584225,22.6659076 40.1008451,20.8376494 47.079831,20.2565245 L47.079831,19.0159207 C47.079831,17.9929667 46.559831,17.6229621 45.124338,17.6229621 C43.0223662,17.6229621 40.6567324,18.2106165 38.4375775,19.3423954 L38.4302535,14.9828702 Z M47.336169,23.9420608 C43.571662,24.3048105 42.3485634,24.8931904 42.3485634,26.3579734 C42.3485634,27.4549284 43.051662,27.9693073 44.604338,27.9693073 C45.4539155,27.9693073 46.2302535,27.8967574 47.3354366,27.7153826 L47.3354366,23.9420608 L47.336169,23.9420608 Z M55.056338,14.5765906 C58.4180282,13.6987364 61.1857465,13.2997118 63.9908169,13.2997118 C66.9057465,13.2997118 69.0157746,13.9599162 70.2674366,15.2367949 C71.4458592,16.4411237 71.8208451,17.7615324 71.8208451,20.5764696 L71.8208451,31.6258237 L66.1294085,31.6258237 L66.1294085,20.8013744 C66.1294085,18.6393866 65.3896901,17.8340823 63.3616901,17.8340823 C62.5846197,17.8340823 61.8822535,17.9066323 60.7397183,18.2403619 L60.7397183,31.6265492 L55.056338,31.6265492 L55.056338,14.5765906 Z M74.0326761,34.7012152 C76.0240563,35.7241692 78.0169014,36.1964692 80.1261972,36.1964692 C83.8540845,36.1964692 85.4433803,34.6946857 85.4433803,31.1107193 L85.4433803,31.0018944 C84.3374648,31.5460188 83.223493,31.7716491 81.7513803,31.7716491 C76.764507,31.7716491 73.5932394,28.5141573 73.5932394,23.3558574 C73.5932394,16.9496987 78.2878873,13.3294573 86.5932394,13.3294573 C89.0321127,13.3294573 91.2878873,13.583382 94.0189859,14.1347615 L92.0708169,18.1975575 C90.5562254,17.9073578 91.9463099,18.1540275 90.804507,18.0452026 L90.804507,18.6328571 L90.8777465,21.0124947 L90.9136338,24.0886117 C90.9509859,24.8583664 90.9509859,25.6259447 90.988338,26.3956994 L90.988338,27.9330324 C90.988338,32.7648576 90.5774648,35.0291409 89.3616901,36.900929 C87.5892958,39.6425908 84.5212958,41 80.1620845,41 C77.943662,41 76.0240563,40.6727998 74.0326761,39.9030451 L74.0326761,34.7012152 L74.0326761,34.7012152 Z M85.3335211,17.8703573 L85.1504225,17.8703573 L84.7395493,17.8703573 C83.6336338,17.8340823 82.3380282,18.1242821 81.4510986,18.6756615 C80.0895775,19.4446908 79.3872113,20.8376494 79.3872113,22.8110074 C79.3872113,25.6252192 80.7934085,27.2365531 83.3055211,27.2365531 C84.0811268,27.2365531 84.7117183,27.0921787 85.4441127,26.8738034 L85.4441127,26.4667983 L85.4441127,24.9294653 C85.4441127,24.269261 85.4067606,23.5365067 85.4067606,22.7674775 L85.3708732,20.17019 L85.3335211,18.3056569 L85.3335211,17.8703573 Z M102.84507,13.2271619 C108.528451,13.2271619 112,16.7748534 112,22.5208077 C112,28.4118619 108.382704,32.1039278 102.617296,32.1039278 C96.9265915,32.1039278 93.4176901,28.5569618 93.4176901,22.8480079 C93.4272113,16.9199532 97.044507,13.2271619 102.84507,13.2271619 Z M102.727887,27.5623023 C104.910423,27.5623023 106.199437,25.7710445 106.199437,22.6586526 C106.199437,19.5825356 104.94631,17.7542774 102.765239,17.7542774 C100.509465,17.7542774 99.2189859,19.5462607 99.2189859,22.6586526 C99.21Line truncated background-image: url("data:image/svg+xml;utf8,<?xml version='1.0' encoding='utf-8'?><svg width='104px' height='36px' viewBox='0 0 104 36' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:sketch='http://www.bohemiancoding.com/sketch/ns'><g id='Page-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' sketch:type='MSPage'><g id='logo-django' sketch:type='MSArtboardGroup' transform='translate(-8.000000, -5.000000)' fill='{{ theme.logo_color|urlencode }}'><path d='M20.2602817,5 L25.9509859,5 L25.9509859,31.0824248 C23.0360563,31.6338042 20.8901408,31.8507285 18.5684507,31.8507285 C11.6180282,31.8434735 8,28.7383366 8,22.7747325 C8,17.0287781 11.8377465,13.2997118 17.7847887,13.2997118 C18.7076056,13.2997118 19.4107042,13.3722617 20.2602817,13.5899115 L20.2602817,5 L20.2602817,5 Z M20.2602817,18.1242821 C19.5938028,17.9066323 19.044507,17.8340823 18.3414085,17.8340823 C15.4630986,17.8340823 13.8005634,19.5897906 13.8005634,22.6666331 C13.8005634,25.6622196 15.3898592,27.316358 18.3047887,27.316358 C18.9346479,27.316358 19.4473239,27.2808085 20.2602817,27.1719836 L20.2602817,18.1242821 L20.2602817,18.1242821 Z M34.9960563,13.6987364 L34.9960563,26.7577235 C34.9960563,31.2550936 34.6591549,33.417807 33.6704225,35.2823401 C32.7476056,37.0750489 31.531831,38.2053768 29.0197183,39.453961 L23.7391549,36.9654985 C26.2512676,35.7981701 27.4670423,34.7665101 28.2433803,33.1921767 C29.056338,31.5822938 29.3126761,29.7177606 29.3126761,24.8133855 L29.3126761,13.6987364 L34.9960563,13.6987364 Z M29.3126761,5.02901997 L35.0033803,5.02901997 L35.0033803,10.8112493 L29.3126761,10.8112493 L29.3126761,5.02901997 Z M38.4302535,14.9828702 C40.9430986,13.8148163 43.3453521,13.2997118 45.9673239,13.2997118 C48.8895775,13.2997118 50.8077183,14.0687411 51.6580282,15.5705246 C52.1340845,16.4121037 52.2878873,17.5076077 52.2878873,19.8509704 L52.2878873,31.2993491 C49.7398873,31.6620987 46.5239437,31.922553 44.1649014,31.922553 C39.3970141,31.922553 37.2584225,30.2756696 37.2584225,26.6198787 C37.2584225,22.6659076 40.1008451,20.8376494 47.079831,20.2565245 L47.079831,19.0159207 C47.079831,17.9929667 46.559831,17.6229621 45.124338,17.6229621 C43.0223662,17.6229621 40.6567324,18.2106165 38.4375775,19.3423954 L38.4302535,14.9828702 Z M47.336169,23.9420608 C43.571662,24.3048105 42.3485634,24.8931904 42.3485634,26.3579734 C42.3485634,27.4549284 43.051662,27.9693073 44.604338,27.9693073 C45.4539155,27.9693073 46.2302535,27.8967574 47.3354366,27.7153826 L47.3354366,23.9420608 L47.336169,23.9420608 Z M55.056338,14.5765906 C58.4180282,13.6987364 61.1857465,13.2997118 63.9908169,13.2997118 C66.9057465,13.2997118 69.0157746,13.9599162 70.2674366,15.2367949 C71.4458592,16.4411237 71.8208451,17.7615324 71.8208451,20.5764696 L71.8208451,31.6258237 L66.1294085,31.6258237 L66.1294085,20.8013744 C66.1294085,18.6393866 65.3896901,17.8340823 63.3616901,17.8340823 C62.5846197,17.8340823 61.8822535,17.9066323 60.7397183,18.2403619 L60.7397183,31.6265492 L55.056338,31.6265492 L55.056338,14.5765906 Z M74.0326761,34.7012152 C76.0240563,35.7241692 78.0169014,36.1964692 80.1261972,36.1964692 C83.8540845,36.1964692 85.4433803,34.6946857 85.4433803,31.1107193 L85.4433803,31.0018944 C84.3374648,31.5460188 83.223493,31.7716491 81.7513803,31.7716491 C76.764507,31.7716491 73.5932394,28.5141573 73.5932394,23.3558574 C73.5932394,16.9496987 78.2878873,13.3294573 86.5932394,13.3294573 C89.0321127,13.3294573 91.2878873,13.583382 94.0189859,14.1347615 L92.0708169,18.1975575 C90.5562254,17.9073578 91.9463099,18.1540275 90.804507,18.0452026 L90.804507,18.6328571 L90.8777465,21.0124947 L90.9136338,24.0886117 C90.9509859,24.8583664 90.9509859,25.6259447 90.988338,26.3956994 L90.988338,27.9330324 C90.988338,32.7648576 90.5774648,35.0291409 89.3616901,36.900929 C87.5892958,39.6425908 84.5212958,41 80.1620845,41 C77.943662,41 76.0240563,40.6727998 74.0326761,39.9030451 L74.0326761,34.7012152 L74.0326761,34.7012152 Z M85.3335211,17.8703573 L85.1504225,17.8703573 L84.7395493,17.8703573 C83.6336338,17.8340823 82.3380282,18.1242821 81.4510986,18.6756615 C80.0895775,19.4446908 79.3872113,20.8376494 79.3872113,22.8110074 C79.3872113,25.6252192 80.7934085,27.2365531 83.3055211,27.2365531 C84.0811268,27.2365531 84.7117183,27.0921787 85.4441127,26.8738034 L85.4441127,26.4667983 L85.4441127,24.9294653 C85.4441127,24.269261 85.4067606,23.5365067 85.4067606,22.7674775 L85.3708732,20.17019 L85.3335211,18.3056569 L85.3335211,17.8703573 Z M102.84507,13.2271619 C108.528451,13.2271619 112,16.7748534 112,22.5208077 C112,28.4118619 108.382704,32.1039278 102.617296,32.1039278 C96.9265915,32.1039278 93.4176901,28.5569618 93.4176901,22.8480079 C93.4272113,16.9199532 97.044507,13.2271619 102.84507,13.2271619 Z M102.727887,27.5623023 C104.910423,27.5623023 106.199437,25.7710445 106.199437,22.6586526 C106.199437,19.5825356 104.94631,17.7542774 102.765239,17.7542774 C100.509465,17.7542774 99.2189859,19.5462607 99.2189859,22.6586526 C99.21Line truncated
} }
.admin-interface #branding h1 img.logo { .admin-interface #branding h1 img.logo,
.admin-interface.login #header #branding h1 img.logo {
{% if theme.logo_max_width > 0 %} {% if theme.logo_max_width > 0 %}
max-width: {{ theme.logo_max_width }}px; max-width: {{ theme.logo_max_width }}px;
max-width: min({{ theme.logo_max_width }}px, 100%);
{% else %}
max-width: 100%;
{% endif %} {% endif %}
{% if theme.logo_max_height > 0 %} {% if theme.logo_max_height > 0 %}
max-height: {{ theme.logo_max_height }}px; max-height: {{ theme.logo_max_height }}px;
{% endif %} {% endif %}
} }
.admin-interface #header #user-tools a { .admin-interface #header #user-tools a,
.admin-interface #header #user-tools button {
color:{{ theme.css_header_link_color }}; color:{{ theme.css_header_link_color }};
} }
.admin-interface #header #user-tools a:hover, .admin-interface #header #user-tools a:hover,
.admin-interface #header #user-tools a:active { .admin-interface #header #user-tools a:active,
.admin-interface #header #user-tools button:active,
.admin-interface #header #user-tools button:hover {
color:{{ theme.css_header_link_hover_color }}; color:{{ theme.css_header_link_hover_color }};
border-bottom-color:rgba(255, 255, 255, 0.5); border-bottom-color:rgba(255, 255, 255, 0.5);
} }
@@ -431,6 +444,14 @@
border-bottom-right-radius:0; border-bottom-right-radius:0;
{% endif %} {% endif %}
} }
.admin-interface .module.collapse.collapsed h2 {
/* fix collapsed inlines rounded bottom borders */
{% if theme.css_module_rounded_corners %}
border-bottom-left-radius:4px;
border-bottom-right-radius:4px;
{% endif %}
}
/* end fix */ /* end fix */
.admin-interface #content-related { .admin-interface #content-related {
@@ -3,7 +3,7 @@
{% if theme.favicon %} {% if theme.favicon %}
<link rel="icon" href="{{ theme.favicon.url }}"> <link rel="icon" href="{{ theme.favicon.url }}">
{% if theme.env_visible_in_favicon %} {% if theme.env_visible_in_favicon %}
<script type="text/javascript" src="{% static 'admin_interface/favico/favico-0.3.10-patched.min.js' %}?v={{ version }}"></script> <script type="text/javascript" src="{% static 'admin_interface/favico/favico-0.3.10-patched.min.js' %}"></script>
<script type="text/javascript"> <script type="text/javascript">
var favicon = new Favico({ var favicon = new Favico({
type: 'circle', type: 'circle',
@@ -1,6 +1,6 @@
{% load static %} {% load static %}
{% if theme.foldable_apps %} {% if theme.foldable_apps %}
<link rel="stylesheet" type="text/css" href="{% static 'admin_interface/foldable-apps/foldable-apps.css' %}?v={{ version }}"> <link rel="stylesheet" type="text/css" href="{% static 'admin_interface/foldable-apps/foldable-apps.css' %}">
<script type="text/javascript" src="{% static 'admin_interface/foldable-apps/foldable-apps.js' %}?v={{ version }}"></script> <script type="text/javascript" src="{% static 'admin_interface/foldable-apps/foldable-apps.js' %}"></script>
{% endif %} {% endif %}
@@ -1,7 +1,7 @@
{% load static %} {% load static %}
{% if theme.related_modal_active %} {% if theme.related_modal_active %}
<link rel="stylesheet" type="text/css" href="{% static 'admin_interface/magnific-popup/magnific-popup.css' %}?v={{ version }}"> <link rel="stylesheet" type="text/css" href="{% static 'admin_interface/magnific-popup/magnific-popup.css' %}">
<script type="text/javascript" src="{% static 'admin_interface/magnific-popup/jquery.magnific-popup.js' %}?v={{ version }}"></script> <script type="text/javascript" src="{% static 'admin_interface/magnific-popup/jquery.magnific-popup.js' %}"></script>
<script type="text/javascript" src="{% static 'admin_interface/related-modal/related-modal.js' %}?v={{ version }}"></script> <script type="text/javascript" src="{% static 'admin_interface/related-modal/related-modal.js' %}"></script>
{% endif %} {% endif %}
@@ -1,24 +1,22 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import django import django
from django import template, VERSION import hashlib
import re
from django import template
from django.conf import settings from django.conf import settings
if django.VERSION < (1, 10):
from django.core.urlresolvers import NoReverseMatch, reverse
else:
from django.urls import NoReverseMatch, reverse
from django.utils import translation from django.utils import translation
from admin_interface.cache import get_cached_active_theme, set_cached_active_theme from admin_interface.cache import get_cached_active_theme, set_cached_active_theme
from admin_interface.compat import NoReverseMatch, reverse
from admin_interface.models import Theme from admin_interface.models import Theme
from admin_interface.version import __version__ from admin_interface.version import __version__
import re
register = template.Library() register = template.Library()
if VERSION < (1, 9): if django.VERSION < (1, 9):
simple_tag = register.assignment_tag simple_tag = register.assignment_tag
else: else:
simple_tag = register.simple_tag simple_tag = register.simple_tag
@@ -33,16 +31,16 @@ def get_admin_interface_languages(context):
# less than 2 languages # less than 2 languages
return None return None
try: try:
set_language_url = reverse('set_language') set_language_url = reverse("set_language")
except NoReverseMatch: except NoReverseMatch:
# ImproperlyConfigured - must include i18n urls: # ImproperlyConfigured - must include i18n urls:
# urlpatterns += [url(r'^i18n/', include('django.conf.urls.i18n')),] # urlpatterns += [url(r'^i18n/', include('django.conf.urls.i18n')),]
return None return None
request = context.get('request', None) request = context.get("request", None)
if not request: if not request:
return None return None
full_path = request.get_full_path() full_path = request.get_full_path()
admin_nolang_url = re.sub(r'^\/([\w]{2})([\-\_]{1}[\w]{2,4})?\/', '/', full_path) admin_nolang_url = re.sub(r"^\/([\w]{2})([\-\_]{1}[\w]{2,4})?\/", "/", full_path)
if admin_nolang_url == full_path: if admin_nolang_url == full_path:
# ImproperlyConfigured - must include admin urls using i18n_patterns: # ImproperlyConfigured - must include admin urls using i18n_patterns:
# from django.conf.urls.i18n import i18n_patterns # from django.conf.urls.i18n import i18n_patterns
@@ -55,12 +53,13 @@ def get_admin_interface_languages(context):
lang_code = language[0].lower() lang_code = language[0].lower()
lang_name = language[1].title() lang_name = language[1].title()
lang_data = { lang_data = {
'code': lang_code, "code": lang_code,
'name': lang_name, "name": lang_name,
'default': lang_code == default_lang_code, "default": lang_code == default_lang_code,
'active': lang_code == current_lang_code, "active": lang_code == current_lang_code,
'activation_url': '{}?next=/{}{}'.format( "activation_url": "{}?next=/{}{}".format(
set_language_url, lang_code, admin_nolang_url) set_language_url, lang_code, admin_nolang_url
),
} }
langs_data.append(lang_data) langs_data.append(lang_data)
return langs_data return langs_data
@@ -68,13 +67,24 @@ def get_admin_interface_languages(context):
@simple_tag(takes_context=True) @simple_tag(takes_context=True)
def get_admin_interface_theme(context): def get_admin_interface_theme(context):
theme = get_cached_active_theme() # theme = get_cached_active_theme()
if not theme: # if not theme:
theme = Theme.get_active_theme() theme = Theme.get_active_theme()
set_cached_active_theme(theme) # set_cached_active_theme(theme)
return theme return theme
@simple_tag(takes_context=False) @simple_tag(takes_context=False)
def get_admin_interface_version(): def get_admin_interface_version():
return __version__ return __version__
def hash_string(text):
hash_object = hashlib.md5(text.encode())
md5_hash = hash_object.hexdigest()
return md5_hash
@simple_tag(takes_context=False)
def get_admin_interface_nocache():
return hash_string(__version__)
+1 -1
View File
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = '0.18.0' __version__ = "0.19.8"
+4
View File
@@ -0,0 +1,4 @@
codecov
coverage
psycopg2
tox
-3
View File
@@ -1,8 +1,5 @@
codecov
coverage
django>=1.7 django>=1.7
django-colorfield django-colorfield
django-flat-theme django-flat-theme
django-flat-responsive django-flat-responsive
six>=1.9.0 six>=1.9.0
tox
+4 -4
View File
@@ -9,13 +9,13 @@ from django.test.utils import get_runner
def runtests(): def runtests():
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' os.environ["DJANGO_SETTINGS_MODULE"] = "tests.settings"
django.setup() django.setup()
TestRunner = get_runner(settings) TestRunner = get_runner(settings)
test_runner = TestRunner() test_runner = TestRunner()
failures = test_runner.run_tests(['tests']) failures = test_runner.run_tests(["tests"])
sys.exit(bool(failures)) sys.exit(bool(failures))
if __name__ == '__main__':
runtests()
if __name__ == "__main__":
runtests()
+72 -50
View File
@@ -5,72 +5,94 @@ from setuptools import find_packages, setup
import os, sys import os, sys
exec(open('admin_interface/version.py').read()) exec(open("admin_interface/version.py").read())
github_url = 'https://github.com/fabiocaccamo' github_url = "https://github.com/fabiocaccamo"
package_name = 'django-admin-interface' sponsor_url = "https://github.com/sponsors/fabiocaccamo/"
package_url = '{}/{}'.format(github_url, package_name) twitter_url = "https://twitter.com/fabiocaccamo"
package_name = "django-admin-interface"
package_url = "{}/{}".format(github_url, package_name)
package_issues_url = "{}/issues".format(github_url)
package_path = os.path.abspath(os.path.dirname(__file__)) package_path = os.path.abspath(os.path.dirname(__file__))
long_description_file_path = os.path.join(package_path, 'README.md') long_description_file_path = os.path.join(package_path, "README.md")
long_description_content_type = 'text/markdown' long_description_content_type = "text/markdown"
long_description = '' long_description = ""
try: try:
long_description_file_options = {} if sys.version_info[0] < 3 else { 'encoding':'utf-8' } long_description_file_options = (
with open(long_description_file_path, 'r', **long_description_file_options) as f: {} if sys.version_info[0] < 3 else {"encoding": "utf-8"}
)
with open(long_description_file_path, "r", **long_description_file_options) as f:
long_description = f.read() long_description = f.read()
except IOError: except IOError:
pass pass
setup( setup(
name=package_name, name=package_name,
packages=find_packages(exclude=['contrib', 'docs', 'tests*']), packages=find_packages(exclude=["contrib", "docs", "tests*"]),
include_package_data=True, include_package_data=True,
version=__version__, version=__version__,
description='django-admin-interface is a modern responsive flat admin interface customizable by the admin itself.', description="django-admin-interface is a modern responsive flat admin interface customizable by the admin itself.",
long_description=long_description, long_description=long_description,
long_description_content_type=long_description_content_type, long_description_content_type=long_description_content_type,
author='Fabio Caccamo', author="Fabio Caccamo",
author_email='fabio.caccamo@gmail.com', author_email="fabio.caccamo@gmail.com",
url=package_url, url=package_url,
download_url='{}/archive/{}.tar.gz'.format(package_url, __version__), download_url="{}/archive/{}.tar.gz".format(package_url, __version__),
keywords=['django', 'admin', 'interface', 'responsive', 'flat', 'theme', 'custom', 'ui'], project_urls={
requires=['django(>=1.7)'], "Documentation": package_url,
"Issues": package_issues_url,
"Funding": sponsor_url,
"Twitter": twitter_url,
},
keywords=[
"django",
"admin",
"interface",
"responsive",
"flat",
"theme",
"custom",
"ui",
],
requires=["django(>=1.7)"],
install_requires=[ install_requires=[
'django-colorfield >= 0.2, < 1.0', "django-colorfield >= 0.2, < 1.0",
'django-flat-theme >= 1.0, < 2.0', "django-flat-theme >= 1.0, < 2.0",
'django-flat-responsive >= 1.0, < 3.0', "django-flat-responsive >= 1.0, < 3.0",
'six >= 1.9.0, < 2.0.0', "six >= 1.9.0, < 2.0.0",
], ],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', "Development Status :: 5 - Production/Stable",
'Environment :: Web Environment', "Environment :: Web Environment",
'Framework :: Django', "Framework :: Django",
'Framework :: Django :: 1.7', "Framework :: Django :: 1.7",
'Framework :: Django :: 1.8', "Framework :: Django :: 1.8",
'Framework :: Django :: 1.9', "Framework :: Django :: 1.9",
'Framework :: Django :: 1.10', "Framework :: Django :: 1.10",
'Framework :: Django :: 1.11', "Framework :: Django :: 1.11",
'Framework :: Django :: 2.0', "Framework :: Django :: 2.0",
'Framework :: Django :: 2.1', "Framework :: Django :: 2.1",
'Framework :: Django :: 2.2', "Framework :: Django :: 2.2",
'Framework :: Django :: 3.0', "Framework :: Django :: 3.0",
'Framework :: Django :: 3.1', "Framework :: Django :: 3.1",
'Framework :: Django :: 3.2', "Framework :: Django :: 3.2",
'Intended Audience :: Developers', "Framework :: Django :: 4.0",
'License :: OSI Approved :: MIT License', "Intended Audience :: Developers",
'Natural Language :: English', "License :: OSI Approved :: MIT License",
'Operating System :: OS Independent', "Natural Language :: English",
'Programming Language :: Python :: 2', "Operating System :: OS Independent",
'Programming Language :: Python :: 2.7', "Programming Language :: Python :: 2",
'Programming Language :: Python :: 3', "Programming Language :: Python :: 2.7",
'Programming Language :: Python :: 3.4', "Programming Language :: Python :: 3",
'Programming Language :: Python :: 3.5', "Programming Language :: Python :: 3.4",
'Programming Language :: Python :: 3.6', "Programming Language :: Python :: 3.5",
'Programming Language :: Python :: 3.7', "Programming Language :: Python :: 3.6",
'Programming Language :: Python :: 3.8', "Programming Language :: Python :: 3.7",
'Programming Language :: Python :: 3.9', "Programming Language :: Python :: 3.8",
'Topic :: Software Development :: Build Tools', "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Software Development :: Build Tools",
], ],
license='MIT', license="MIT",
test_suite='runtests.runtests' test_suite="runtests.runtests",
) )
+64 -51
View File
@@ -7,69 +7,71 @@ import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = 'django-admin-interface' SECRET_KEY = "django-admin-interface"
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ["*"]
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'admin_interface', "admin_interface",
'colorfield', "colorfield",
] ]
if django.VERSION < (1, 9): if django.VERSION < (1, 9):
# ONLY if django version < 1.9 # ONLY if django version < 1.9
INSTALLED_APPS += [ INSTALLED_APPS += [
'flat', "flat",
] ]
if django.VERSION < (2, 0): if django.VERSION < (2, 0):
# ONLY if django version < 2.0 # ONLY if django version < 2.0
INSTALLED_APPS += [ INSTALLED_APPS += [
'flat_responsive', "flat_responsive",
] ]
INSTALLED_APPS += [ INSTALLED_APPS += [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.sessions', "django.contrib.sessions",
] ]
if django.VERSION < (2, 0): if django.VERSION < (2, 0):
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware' "django.contrib.messages.middleware.MessageMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
] ]
else: else:
MIDDLEWARE = [ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
] ]
TEMPLATES = [{ TEMPLATES = [
'BACKEND': 'django.template.backends.django.DjangoTemplates', {
'DIRS': [], "BACKEND": "django.template.backends.django.DjangoTemplates",
'APP_DIRS': True, "DIRS": [],
'OPTIONS': { "APP_DIRS": True,
'context_processors': [ "OPTIONS": {
'django.contrib.auth.context_processors.auth', "context_processors": [
'django.contrib.messages.context_processors.messages', "django.contrib.auth.context_processors.auth",
'django.template.context_processors.request', "django.contrib.messages.context_processors.messages",
"django.template.context_processors.request",
] ]
}, },
},] },
]
database_engine = os.environ.get('DATABASE_ENGINE', 'sqlite') database_engine = os.environ.get("DATABASE_ENGINE", "sqlite")
database_config = { database_config = {
'sqlite': { "sqlite": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': ':memory:', "NAME": ":memory:",
}, },
# 'mysql': { # 'mysql': {
# 'ENGINE': 'django.db.backends.mysql', # 'ENGINE': 'django.db.backends.mysql',
@@ -79,32 +81,43 @@ database_config = {
# 'HOST': '', # 'HOST': '',
# 'PORT': '', # 'PORT': '',
# }, # },
'postgres': { "postgres": {
'ENGINE': 'django.db.backends.postgresql_psycopg2', "ENGINE": "django.db.backends.postgresql_psycopg2",
'NAME': 'admin_interface', "NAME": "admin_interface",
'USER': 'postgres', "USER": "postgres",
'PASSWORD': 'postgres', "PASSWORD": "postgres",
'HOST': '', "HOST": "",
'PORT': '', "PORT": "",
} },
} }
github_workflow = os.environ.get("GITHUB_WORKFLOW")
if github_workflow:
database_config["postgres"]["NAME"] = "postgres"
database_config["postgres"]["HOST"] = "127.0.0.1"
database_config["postgres"]["PORT"] = "5432"
DATABASES = { DATABASES = {
'default': database_config.get(database_engine), "default": database_config.get(database_engine),
} }
USE_I18N = True USE_I18N = True
LANGUAGES = ( LANGUAGES = (
('en', 'English', ), (
('it', 'Italian', ), "en",
"English",
),
(
"it",
"Italian",
),
) )
LANGUAGE_CODE = 'en' LANGUAGE_CODE = "en"
ROOT_URLCONF = 'tests.urls' ROOT_URLCONF = "tests.urls"
MEDIA_ROOT = os.path.join(BASE_DIR, 'admin_interface/public/media/') MEDIA_ROOT = os.path.join(BASE_DIR, "admin_interface/public/media/")
MEDIA_URL = '/media/' MEDIA_URL = "/media/"
STATIC_ROOT = os.path.join(BASE_DIR, 'admin_interface/public/static/')
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "admin_interface/public/static/")
STATIC_URL = "/static/"
+20 -21
View File
@@ -9,7 +9,6 @@ from admin_interface.models import Theme
class AdminInterfaceFixturesTestCase(TestCase): class AdminInterfaceFixturesTestCase(TestCase):
def setUp(self): def setUp(self):
pass pass
@@ -17,36 +16,36 @@ class AdminInterfaceFixturesTestCase(TestCase):
pass pass
def __load_theme(self, theme_name): def __load_theme(self, theme_name):
call_command('loaddata', 'admin_interface_theme_%s.json' % (theme_name, )) call_command("loaddata", "admin_interface_theme_%s.json" % (theme_name,))
def test_import_initial_data(self): def test_import_initial_data(self):
call_command('loaddata', 'initial_data.json') call_command("loaddata", "initial_data.json")
self.assertEqual(Theme.objects.count(), 1); self.assertEqual(Theme.objects.count(), 1)
def test_import_all(self): def test_import_all(self):
self.__load_theme('django') self.__load_theme("django")
self.__load_theme('bootstrap') self.__load_theme("bootstrap")
self.__load_theme('foundation') self.__load_theme("foundation")
self.__load_theme('uswds') self.__load_theme("uswds")
self.assertEqual(Theme.objects.count(), 4); self.assertEqual(Theme.objects.count(), 4)
def test_import_idempotency(self): def test_import_idempotency(self):
self.__load_theme('django') self.__load_theme("django")
self.__load_theme('django') self.__load_theme("django")
self.__load_theme('django') self.__load_theme("django")
self.__load_theme('django') self.__load_theme("django")
self.__load_theme('django') self.__load_theme("django")
self.assertEqual(Theme.objects.count(), 1); self.assertEqual(Theme.objects.count(), 1)
self.__load_theme('bootstrap') self.__load_theme("bootstrap")
self.__load_theme('bootstrap') self.__load_theme("bootstrap")
self.__load_theme('bootstrap') self.__load_theme("bootstrap")
self.assertEqual(Theme.objects.count(), 2); self.assertEqual(Theme.objects.count(), 2)
def test_import_override(self): def test_import_override(self):
obj1 = Theme.get_active_theme() obj1 = Theme.get_active_theme()
obj1.title = 'Custom 1' obj1.title = "Custom 1"
obj1.save() obj1.save()
self.__load_theme('django') self.__load_theme("django")
obj2 = Theme.get_active_theme() obj2 = Theme.get_active_theme()
self.assertEqual(obj1.pk, obj2.pk) self.assertEqual(obj1.pk, obj2.pk)
self.assertTrue(obj1.title != obj2.title) self.assertTrue(obj1.title != obj2.title)
+16 -17
View File
@@ -12,7 +12,6 @@ from admin_interface.models import Theme
class AdminInterfaceModelsTestCase(TestCase): class AdminInterfaceModelsTestCase(TestCase):
def setUp(self): def setUp(self):
pass pass
@@ -24,7 +23,7 @@ class AdminInterfaceModelsTestCase(TestCase):
print(theme) print(theme)
self.assertTrue(theme != None) self.assertTrue(theme != None)
self.assertTrue(theme.active) self.assertTrue(theme.active)
self.assertEqual(Theme.objects.filter(active=True).count(), 1); self.assertEqual(Theme.objects.filter(active=True).count(), 1)
def test_default_theme_created_if_no_themes(self): def test_default_theme_created_if_no_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
@@ -48,36 +47,36 @@ class AdminInterfaceModelsTestCase(TestCase):
def test_default_theme_activated_after_update_if_multiple_active_themes(self): def test_default_theme_activated_after_update_if_multiple_active_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create(name='Custom 1', active=True) theme_1 = Theme.objects.create(name="Custom 1", active=True)
theme_2 = Theme.objects.create(name='Custom 2', active=True) theme_2 = Theme.objects.create(name="Custom 2", active=True)
theme_3 = Theme.objects.create(name='Custom 3', active=True) theme_3 = Theme.objects.create(name="Custom 3", active=True)
Theme.objects.update(active=False) Theme.objects.update(active=False)
Theme.objects.update(active=True) Theme.objects.update(active=True)
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_activated_on_active_theme_deleted(self): def test_default_theme_activated_on_active_theme_deleted(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create(name='Custom 1', active=True) theme_1 = Theme.objects.create(name="Custom 1", active=True)
theme_2 = Theme.objects.create(name='Custom 2', active=True) theme_2 = Theme.objects.create(name="Custom 2", active=True)
theme_3 = Theme.objects.create(name='Custom 3', active=True) theme_3 = Theme.objects.create(name="Custom 3", active=True)
Theme.objects.filter(pk=Theme.get_active_theme().pk).delete() Theme.objects.filter(pk=Theme.get_active_theme().pk).delete()
self.__test_active_theme() self.__test_active_theme()
def test_last_theme_activated_on_multiple_themes_created(self): def test_last_theme_activated_on_multiple_themes_created(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create(name='Custom 1', active=True) theme_1 = Theme.objects.create(name="Custom 1", active=True)
theme_2 = Theme.objects.create(name='Custom 2', active=True) theme_2 = Theme.objects.create(name="Custom 2", active=True)
theme_3 = Theme.objects.create(name='Custom 3', active=True) theme_3 = Theme.objects.create(name="Custom 3", active=True)
self.assertEqual(Theme.get_active_theme().pk, theme_3.pk) self.assertEqual(Theme.get_active_theme().pk, theme_3.pk)
self.__test_active_theme() self.__test_active_theme()
def test_last_theme_activated_on_multiple_themes_activated(self): def test_last_theme_activated_on_multiple_themes_activated(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create(name='Custom 1', active=True) theme_1 = Theme.objects.create(name="Custom 1", active=True)
theme_2 = Theme.objects.create(name='Custom 2', active=True) theme_2 = Theme.objects.create(name="Custom 2", active=True)
theme_3 = Theme.objects.create(name='Custom 3', active=True) theme_3 = Theme.objects.create(name="Custom 3", active=True)
theme_4 = Theme.objects.create(name='Custom 4', active=True) theme_4 = Theme.objects.create(name="Custom 4", active=True)
theme_5 = Theme.objects.create(name='Custom 5', active=True) theme_5 = Theme.objects.create(name="Custom 5", active=True)
themes = [theme_1, theme_2, theme_3, theme_4, theme_5] themes = [theme_1, theme_2, theme_3, theme_4, theme_5]
for i in range(5): for i in range(5):
random.shuffle(themes) random.shuffle(themes)
@@ -88,4 +87,4 @@ class AdminInterfaceModelsTestCase(TestCase):
def test_repr(self): def test_repr(self):
theme = Theme.get_active_theme() theme = Theme.get_active_theme()
self.assertEqual('{0}'.format(theme), 'Django') self.assertEqual("{0}".format(theme), "Django")
+31 -28
View File
@@ -13,11 +13,11 @@ from admin_interface.settings import check_installed_apps
class AdminInterfaceSettingsTestCase(TestCase): class AdminInterfaceSettingsTestCase(TestCase):
DJANGO_APPS = [ DJANGO_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.sessions', "django.contrib.sessions",
] ]
def setUp(self): def setUp(self):
@@ -30,19 +30,19 @@ class AdminInterfaceSettingsTestCase(TestCase):
dj_version = django.VERSION dj_version = django.VERSION
installed_apps = settings.INSTALLED_APPS installed_apps = settings.INSTALLED_APPS
if 'colorfield' not in installed_apps: if "colorfield" not in installed_apps:
self.assertRaises(ImproperlyConfigured, check_installed_apps) self.assertRaises(ImproperlyConfigured, check_installed_apps)
elif 'flat' not in installed_apps and dj_version < (1, 9): elif "flat" not in installed_apps and dj_version < (1, 9):
self.assertRaises(ImproperlyConfigured, check_installed_apps) self.assertRaises(ImproperlyConfigured, check_installed_apps)
elif 'flat' in installed_apps and dj_version >= (1, 9): elif "flat" in installed_apps and dj_version >= (1, 9):
self.assertRaises(ImproperlyConfigured, check_installed_apps) self.assertRaises(ImproperlyConfigured, check_installed_apps)
elif 'flat_responsive' not in installed_apps and dj_version < (2, 0): elif "flat_responsive" not in installed_apps and dj_version < (2, 0):
self.assertRaises(ImproperlyConfigured, check_installed_apps) self.assertRaises(ImproperlyConfigured, check_installed_apps)
elif 'flat_responsive' in installed_apps and dj_version >= (2, 0): elif "flat_responsive" in installed_apps and dj_version >= (2, 0):
self.assertRaises(ImproperlyConfigured, check_installed_apps) self.assertRaises(ImproperlyConfigured, check_installed_apps)
else: else:
@@ -50,45 +50,48 @@ class AdminInterfaceSettingsTestCase(TestCase):
@override_settings( @override_settings(
INSTALLED_APPS=[ INSTALLED_APPS=[
'admin_interface', "admin_interface",
'colorfield', "colorfield",
'flat', "flat",
'flat_responsive', "flat_responsive",
] + DJANGO_APPS ]
+ DJANGO_APPS
) )
def test_installed_apps_all(self): def test_installed_apps_all(self):
self.__test_installed_apps() self.__test_installed_apps()
@override_settings( @override_settings(
INSTALLED_APPS=[ INSTALLED_APPS=[
'admin_interface', "admin_interface",
# 'colorfield', # 'colorfield',
'flat', "flat",
'flat_responsive', "flat_responsive",
] + DJANGO_APPS ]
+ DJANGO_APPS
) )
def test_installed_apps_no_colorfield(self): def test_installed_apps_no_colorfield(self):
self.__test_installed_apps() self.__test_installed_apps()
@override_settings( @override_settings(
INSTALLED_APPS=[ INSTALLED_APPS=[
'admin_interface', "admin_interface",
'colorfield', "colorfield",
# 'flat', # 'flat',
'flat_responsive', "flat_responsive",
] + DJANGO_APPS ]
+ DJANGO_APPS
) )
def test_installed_apps_no_flat(self): def test_installed_apps_no_flat(self):
self.__test_installed_apps() self.__test_installed_apps()
@override_settings( @override_settings(
INSTALLED_APPS=[ INSTALLED_APPS=[
'admin_interface', "admin_interface",
'colorfield', "colorfield",
'flat', "flat",
# 'flat_responsive', # 'flat_responsive',
] + DJANGO_APPS ]
+ DJANGO_APPS
) )
def test_installed_apps_no_flat_responsive(self): def test_installed_apps_no_flat_responsive(self):
self.__test_installed_apps() self.__test_installed_apps()
+73 -38
View File
@@ -8,11 +8,11 @@ from django.template import Context, Template
from admin_interface.models import Theme from admin_interface.models import Theme
from admin_interface.templatetags import admin_interface_tags as templatetags from admin_interface.templatetags import admin_interface_tags as templatetags
from admin_interface.templatetags.admin_interface_tags import hash_string
from admin_interface.version import __version__ from admin_interface.version import __version__
class AdminInterfaceTemplateTagsTestCase(TestCase): class AdminInterfaceTemplateTagsTestCase(TestCase):
def setUp(self): def setUp(self):
self.request_factory = RequestFactory() self.request_factory = RequestFactory()
@@ -23,13 +23,27 @@ class AdminInterfaceTemplateTagsTestCase(TestCase):
return Template(string).render(Context(context or {})) return Template(string).render(Context(context or {}))
def test_get_admin_interface_languages(self): def test_get_admin_interface_languages(self):
context = Context({ context = Context(
'request': self.request_factory.get('/en/admin/'), {
}) "request": self.request_factory.get("/en/admin/"),
}
)
languages = templatetags.get_admin_interface_languages(context) languages = templatetags.get_admin_interface_languages(context)
expected_languages = [ expected_languages = [
{'code': 'en', 'name': 'English', 'default': True, 'active': True, 'activation_url': '/i18n/setlang/?next=/en/admin/'}, {
{'code': 'it', 'name': 'Italian', 'default': False, 'active': False, 'activation_url': '/i18n/setlang/?next=/it/admin/'} "code": "en",
"name": "English",
"default": True,
"active": True,
"activation_url": "/i18n/setlang/?next=/en/admin/",
},
{
"code": "it",
"name": "Italian",
"default": False,
"active": False,
"activation_url": "/i18n/setlang/?next=/it/admin/",
},
] ]
self.assertEqual(len(languages), len(expected_languages)) self.assertEqual(len(languages), len(expected_languages))
self.assertEqual(languages[0], expected_languages[0]) self.assertEqual(languages[0], expected_languages[0])
@@ -39,31 +53,35 @@ class AdminInterfaceTemplateTagsTestCase(TestCase):
USE_I18N=False, USE_I18N=False,
) )
def test_get_admin_interface_languages_with_i18n_disabled(self): def test_get_admin_interface_languages_with_i18n_disabled(self):
context = Context({ context = Context(
'request': self.request_factory.get('/en/admin/'), {
}) "request": self.request_factory.get("/en/admin/"),
}
)
languages = templatetags.get_admin_interface_languages(context) languages = templatetags.get_admin_interface_languages(context)
self.assertEqual(languages, None) self.assertEqual(languages, None)
@override_settings( @override_settings(
ROOT_URLCONF = 'tests.urls_without_i18n_patterns', ROOT_URLCONF="tests.urls_without_i18n_patterns",
) )
def test_get_admin_interface_languages_without_i18n_url_patterns(self): def test_get_admin_interface_languages_without_i18n_url_patterns(self):
context = Context({ context = Context(
'request': self.request_factory.get('/en/admin/'), {
}) "request": self.request_factory.get("/en/admin/"),
}
)
languages = templatetags.get_admin_interface_languages(context) languages = templatetags.get_admin_interface_languages(context)
self.assertEqual(languages, None) self.assertEqual(languages, None)
@override_settings( @override_settings(
LANGUAGES = ( LANGUAGES=(("en", "English"),),
('en', 'English'),
),
) )
def test_get_admin_interface_languages_without_multiple_languages(self): def test_get_admin_interface_languages_without_multiple_languages(self):
context = Context({ context = Context(
'request': self.request_factory.get('/en/admin/'), {
}) "request": self.request_factory.get("/en/admin/"),
}
)
languages = templatetags.get_admin_interface_languages(context) languages = templatetags.get_admin_interface_languages(context)
self.assertEqual(languages, None) self.assertEqual(languages, None)
@@ -73,9 +91,11 @@ class AdminInterfaceTemplateTagsTestCase(TestCase):
self.assertEqual(languages, None) self.assertEqual(languages, None)
def test_get_admin_interface_languages_without_language_prefix_in_url(self): def test_get_admin_interface_languages_without_language_prefix_in_url(self):
context = Context({ context = Context(
'request': self.request_factory.get('/admin/'), {
}) "request": self.request_factory.get("/admin/"),
}
)
languages = templatetags.get_admin_interface_languages(context) languages = templatetags.get_admin_interface_languages(context)
self.assertEqual(languages, None) self.assertEqual(languages, None)
@@ -83,31 +103,46 @@ class AdminInterfaceTemplateTagsTestCase(TestCase):
Theme.objects.all().delete() Theme.objects.all().delete()
context = Context({}) context = Context({})
theme = templatetags.get_admin_interface_theme(context) theme = templatetags.get_admin_interface_theme(context)
self.assertEqual(theme.name, 'Django') self.assertEqual(theme.name, "Django")
rendered = self.__render_template( rendered = self.__render_template(
'{% load admin_interface_tags %}'\ "{% load admin_interface_tags %}"
'{% get_admin_interface_theme as theme %}'\ "{% get_admin_interface_theme as theme %}"
'{{ theme.name }}', context) "{{ theme.name }}",
self.assertEqual(rendered, 'Django') context,
)
self.assertEqual(rendered, "Django")
def test_get_theme_with_request(self): def test_get_theme_with_request(self):
Theme.objects.all().delete() Theme.objects.all().delete()
context = Context({ context = Context({"request": self.request_factory.get("/")})
'request': self.request_factory.get('/')
})
theme = templatetags.get_admin_interface_theme(context) theme = templatetags.get_admin_interface_theme(context)
self.assertEqual(theme.name, 'Django') self.assertEqual(theme.name, "Django")
rendered = self.__render_template( rendered = self.__render_template(
'{% load admin_interface_tags %}'\ "{% load admin_interface_tags %}"
'{% get_admin_interface_theme as theme %}'\ "{% get_admin_interface_theme as theme %}"
'{{ theme.name }}', context) "{{ theme.name }}",
self.assertEqual(rendered, 'Django') context,
)
self.assertEqual(rendered, "Django")
def test_get_version(self): def test_get_version(self):
version = templatetags.get_admin_interface_version() version = templatetags.get_admin_interface_version()
self.assertEqual(version, __version__) self.assertEqual(version, __version__)
rendered = self.__render_template( rendered = self.__render_template(
'{% load admin_interface_tags %}'\ "{% load admin_interface_tags %}"
'{% get_admin_interface_version as version %}'\ "{% get_admin_interface_version as version %}"
'{{ version }}') "{{ version }}"
)
self.assertEqual(rendered, __version__) self.assertEqual(rendered, __version__)
def test_get_version_nocache(self):
hash_from_tag = templatetags.get_admin_interface_nocache()
hash_manual = hash_string(__version__)
self.assertEqual(hash_from_tag, hash_manual)
rendered = self.__render_template(
"{% load admin_interface_tags %}"
"{% get_admin_interface_nocache as version_md5_hash %}"
"{{ version_md5_hash }}"
)
self.assertEqual(rendered, hash_manual)
+3 -2
View File
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import django import django
from django.contrib import admin from django.contrib import admin
if django.VERSION < (2, 0): if django.VERSION < (2, 0):
from django.conf.urls import include, url as re_path from django.conf.urls import include, url as re_path
else: else:
@@ -13,8 +14,8 @@ from django.conf.urls.i18n import i18n_patterns
urlpatterns = [] urlpatterns = []
urlpatterns += [ urlpatterns += [
re_path(r'^i18n/', include('django.conf.urls.i18n')), re_path(r"^i18n/", include("django.conf.urls.i18n")),
] ]
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
re_path(r'^admin/', admin.site.urls), re_path(r"^admin/", admin.site.urls),
) )
+2 -1
View File
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import django import django
from django.contrib import admin from django.contrib import admin
if django.VERSION < (2, 0): if django.VERSION < (2, 0):
from django.conf.urls import url as re_path from django.conf.urls import url as re_path
else: else:
@@ -11,5 +12,5 @@ else:
urlpatterns = [ urlpatterns = [
re_path(r'^admin/', admin.site.urls), re_path(r"^admin/", admin.site.urls),
] ]
+17 -7
View File
@@ -1,13 +1,23 @@
[tox] [tox]
envlist = envlist =
py27-{dj17,dj18,dj19,dj110,dj111}-{sqlite,postgres}, py27-{dj17,dj18,dj19,dj110,dj111}-{sqlite,postgres},
py35-{dj18,dj19,dj110,dj111,dj20,dj21,dj22}-{sqlite,postgres}, py36-{dj18,dj19,dj110,dj111,dj20,dj21,dj22,dj30,dj31,dj32}-{sqlite,postgres},
py36-{dj18,dj19,dj110,dj111,dj20,dj21,dj22,dj30,dj31,dj32,djmaster}-{sqlite,postgres}, py37-{dj20,dj21,dj22,dj30,dj31,dj32}-{sqlite,postgres},
py37-{dj20,dj21,dj22,dj30,dj31,dj32,djmaster}-{sqlite,postgres}, py38-{dj22,dj30,dj31,dj32}-{sqlite,postgres},
py38-{dj22,dj30,dj31,dj32,djmaster}-{sqlite,postgres}, py39-{dj22,dj30,dj31,dj32}-{sqlite,postgres},
py39-{dj22,dj30,dj31,dj32,djmaster}-{sqlite,postgres}, py310-{dj32,dj40}-{sqlite,postgres},
[gh-actions]
python =
2.7: py27
3.6: py36
3.7: py37
3.8: py38
3.9: py39
3.10: py310
[testenv] [testenv]
passenv = CI TRAVIS TRAVIS_* passenv = CI GITHUB_WORKFLOW
deps = deps =
dj17: Django == 1.7.* dj17: Django == 1.7.*
dj18: Django == 1.8.* dj18: Django == 1.8.*
@@ -20,7 +30,7 @@ deps =
dj30: Django == 3.0.* dj30: Django == 3.0.*
dj31: Django == 3.1.* dj31: Django == 3.1.*
dj32: Django == 3.2.* dj32: Django == 3.2.*
djmaster: https://github.com/django/django/archive/master.tar.gz dj40: Django == 4.0.*
# mysql: mysqlclient # mysql: mysqlclient
postgres: psycopg2-binary postgres: psycopg2-binary
coverage coverage