django-cachex 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_cachex-0.4.1 → django_cachex-0.4.2}/PKG-INFO +2 -2
- {django_cachex-0.4.1 → django_cachex-0.4.2}/crates/django-cachex-redis-rs/pyproject.toml +1 -1
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/cas.py +36 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/helpers.py +36 -31
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/cache/styles.css +48 -8
- django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_hash.html +73 -0
- django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_list.html +114 -0
- django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_set.html +79 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_stream.html +17 -11
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_string.html +3 -9
- django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_value_input.html +18 -0
- django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_zset.html +98 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/views/key_detail.py +103 -2
- {django_cachex-0.4.1 → django_cachex-0.4.2}/pyproject.toml +2 -2
- django_cachex-0.4.1/django_cachex/admin/templates/admin/django_cachex/key/key_detail_hash.html +0 -101
- django_cachex-0.4.1/django_cachex/admin/templates/admin/django_cachex/key/key_detail_list.html +0 -127
- django_cachex-0.4.1/django_cachex/admin/templates/admin/django_cachex/key/key_detail_set.html +0 -57
- django_cachex-0.4.1/django_cachex/admin/templates/admin/django_cachex/key/key_detail_zset.html +0 -85
- {django_cachex-0.4.1 → django_cachex-0.4.2}/.gitignore +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/LICENSE +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/README.md +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/benchmarks/README.md +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/crates/django-cachex-redis-rs/LICENSE +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/crates/django-cachex-redis-rs/README.md +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/_async_helpers.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/_pipeline_parsers.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/pipeline.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/protocols.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/redis_py.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/redis_rs.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/valkey_glide.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/adapters/valkey_py.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/admin.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/apps.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/models.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/queryset.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/cache/change_form.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/cache/change_list.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/_key_detail_actions.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/add_form.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/change_form.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/change_list.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_pagination.html +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/views/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/views/base.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/views/cache_detail.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/admin/views/key_add.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/_semaphore_lua.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/base.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/database.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/locmem.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/redis_py.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/redis_rs.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/resp.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/stream.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/tiered.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/valkey_glide.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/cache/valkey_py.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/base.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/gzip.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/lz4.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/lzma.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/zlib.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/compressors/zstd.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/exceptions.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/lock.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/py.typed +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/script.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/semaphore.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/__init__.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/base.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/json.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/msgpack.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/orjson.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/ormsgpack.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/serializers/pickle.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/stampede.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/types.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/django_cachex/utils.py +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/examples/README.md +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/examples/full/README.md +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/examples/full/pyproject.toml +0 -0
- {django_cachex-0.4.1 → django_cachex-0.4.2}/examples/simple/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: django-cachex
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Full featured Valkey and Redis cache backend for Django
|
|
5
5
|
Project-URL: Homepage, https://github.com/oliverhaas/django-cachex
|
|
6
6
|
Project-URL: Documentation, https://oliverhaas.github.io/django-cachex/
|
|
@@ -44,7 +44,7 @@ Requires-Dist: ormsgpack>=1.10.0; extra == 'ormsgpack'
|
|
|
44
44
|
Provides-Extra: redis-py
|
|
45
45
|
Requires-Dist: redis<9,>=6; extra == 'redis-py'
|
|
46
46
|
Provides-Extra: redis-rs
|
|
47
|
-
Requires-Dist: django-cachex-redis-rs==0.4.
|
|
47
|
+
Requires-Dist: django-cachex-redis-rs==0.4.2; extra == 'redis-rs'
|
|
48
48
|
Provides-Extra: valkey-glide
|
|
49
49
|
Requires-Dist: valkey-glide-sync<3,>=2.3; extra == 'valkey-glide'
|
|
50
50
|
Requires-Dist: valkey-glide<3,>=2.3; extra == 'valkey-glide'
|
|
@@ -8,6 +8,7 @@ Each CAS function returns:
|
|
|
8
8
|
1: success (value matched, update applied)
|
|
9
9
|
0: conflict (value changed since page load)
|
|
10
10
|
-1: gone (key/field/index no longer exists)
|
|
11
|
+
-2: target name already taken (hash field rename only)
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
14
|
from typing import TYPE_CHECKING, Any
|
|
@@ -91,6 +92,16 @@ end
|
|
|
91
92
|
return 0
|
|
92
93
|
"""
|
|
93
94
|
|
|
95
|
+
_CAS_HASH_RENAME = """\
|
|
96
|
+
local v = redis.call('HGET', KEYS[1], ARGV[1])
|
|
97
|
+
if v == false then return -1 end
|
|
98
|
+
if redis.sha1hex(v) ~= ARGV[3] then return 0 end
|
|
99
|
+
if redis.call('HEXISTS', KEYS[1], ARGV[2]) == 1 then return -2 end
|
|
100
|
+
redis.call('HSET', KEYS[1], ARGV[2], ARGV[4])
|
|
101
|
+
redis.call('HDEL', KEYS[1], ARGV[1])
|
|
102
|
+
return 1
|
|
103
|
+
"""
|
|
104
|
+
|
|
94
105
|
_CAS_ZSET_SCORE_UPDATE = """\
|
|
95
106
|
local v = redis.call('ZSCORE', KEYS[1], ARGV[1])
|
|
96
107
|
if v == false then return -1 end
|
|
@@ -243,6 +254,31 @@ def cas_update_hash_field(
|
|
|
243
254
|
)
|
|
244
255
|
|
|
245
256
|
|
|
257
|
+
def cas_rename_hash_field(
|
|
258
|
+
cache: RespCache,
|
|
259
|
+
key: str,
|
|
260
|
+
field: str,
|
|
261
|
+
new_field: str,
|
|
262
|
+
expected_sha1: str,
|
|
263
|
+
new_value: Any,
|
|
264
|
+
) -> int:
|
|
265
|
+
"""Atomically move a hash field to a new name if its value hasn't changed.
|
|
266
|
+
|
|
267
|
+
Redis has no HRENAME, so a rename is HSET plus HDEL. Running the pair in a
|
|
268
|
+
script keeps it atomic and costs a single round trip.
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
1 = success, 0 = conflict, -1 = field gone, -2 = new name already taken.
|
|
272
|
+
"""
|
|
273
|
+
encoded = cache.encode(new_value)
|
|
274
|
+
return cache.eval_script(
|
|
275
|
+
_CAS_HASH_RENAME,
|
|
276
|
+
keys=[key],
|
|
277
|
+
args=[field, new_field, expected_sha1, encoded],
|
|
278
|
+
pre_hook=keys_only_pre,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
246
282
|
def cas_update_zset_score(
|
|
247
283
|
cache: RespCache,
|
|
248
284
|
key: str,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Helper functions for cache admin views."""
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import logging
|
|
5
4
|
from datetime import UTC, datetime
|
|
6
5
|
from typing import TYPE_CHECKING, Any
|
|
@@ -204,22 +203,18 @@ def get_type_data(
|
|
|
204
203
|
return result
|
|
205
204
|
|
|
206
205
|
|
|
207
|
-
def
|
|
208
|
-
"""Format
|
|
206
|
+
def _format_entry(value: Any) -> tuple[str, bool]:
|
|
207
|
+
"""Format one container entry as (display_string, editable).
|
|
209
208
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
Shares ``format_value_for_display`` with the string editor so containers and
|
|
210
|
+
strings agree on what is round-trippable. Entries that fall back to repr()
|
|
211
|
+
are marked non-editable: submitting the repr back would store the repr text.
|
|
213
212
|
"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return serialized
|
|
220
|
-
except TypeError, ValueError, OverflowError:
|
|
221
|
-
pass
|
|
222
|
-
return repr(value)
|
|
213
|
+
# Imported lazily: views.base is reachable from views/__init__, which
|
|
214
|
+
# imports the modules that import this one.
|
|
215
|
+
from django_cachex.admin.views.base import format_value_for_display
|
|
216
|
+
|
|
217
|
+
return format_value_for_display(value)
|
|
223
218
|
|
|
224
219
|
|
|
225
220
|
def _fetch_type_data(cache: Any, key: str, key_type: str, *, page: int = 1) -> dict[str, Any]: # noqa: PLR0911
|
|
@@ -231,19 +226,25 @@ def _fetch_type_data(cache: Any, key: str, key_type: str, *, page: int = 1) -> d
|
|
|
231
226
|
pagination = _paginate(length, page)
|
|
232
227
|
start = pagination["start_index"]
|
|
233
228
|
stop = pagination["end_index"] - 1 # LRANGE stop is inclusive
|
|
234
|
-
|
|
235
|
-
#
|
|
236
|
-
item_entries = [
|
|
237
|
-
|
|
229
|
+
# Every entry carries an empty SHA1 slot that CAS fills in later, so
|
|
230
|
+
# the template sees the same tuple shape on backends without scripting.
|
|
231
|
+
item_entries = []
|
|
232
|
+
for i, raw in enumerate(cache.lrange(key, start, stop)):
|
|
233
|
+
item, editable = _format_entry(raw)
|
|
234
|
+
item_entries.append((start + i, item, "", editable))
|
|
235
|
+
return {"length": length, "pagination": pagination, "item_entries": item_entries}
|
|
238
236
|
case KeyType.HASH:
|
|
239
|
-
fields = {str(k):
|
|
237
|
+
fields = {str(k): v for k, v in cache.hgetall(key).items()}
|
|
240
238
|
length = len(fields)
|
|
241
239
|
pagination = _paginate(length, page)
|
|
242
240
|
s, e = pagination["start_index"], pagination["end_index"]
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
field_entries = []
|
|
242
|
+
for field, raw in list(fields.items())[s:e]:
|
|
243
|
+
value, editable = _format_entry(raw)
|
|
244
|
+
field_entries.append((field, value, "", editable))
|
|
245
|
+
return {"length": length, "pagination": pagination, "field_entries": field_entries}
|
|
245
246
|
case KeyType.SET:
|
|
246
|
-
members = sorted(
|
|
247
|
+
members = sorted(_format_entry(m) for m in cache.smembers(key))
|
|
247
248
|
length = len(members)
|
|
248
249
|
pagination = _paginate(length, page)
|
|
249
250
|
s, e = pagination["start_index"], pagination["end_index"]
|
|
@@ -253,7 +254,10 @@ def _fetch_type_data(cache: Any, key: str, key_type: str, *, page: int = 1) -> d
|
|
|
253
254
|
pagination = _paginate(length, page)
|
|
254
255
|
start = pagination["start_index"]
|
|
255
256
|
stop = pagination["end_index"] - 1 # ZRANGE stop is inclusive
|
|
256
|
-
zset_members = [
|
|
257
|
+
zset_members = []
|
|
258
|
+
for raw, score in cache.zrange(key, start, stop, withscores=True):
|
|
259
|
+
member, editable = _format_entry(raw)
|
|
260
|
+
zset_members.append((member, score, editable))
|
|
257
261
|
return {"members": zset_members, "length": length, "pagination": pagination}
|
|
258
262
|
case KeyType.STREAM if hasattr(cache, "xrange"):
|
|
259
263
|
length = cache.xlen(key)
|
|
@@ -288,22 +292,23 @@ def _add_cas_fingerprints(cache: Any, key: str, key_type: str | None, result: di
|
|
|
288
292
|
from django_cachex.admin.cas import get_list_sha1s
|
|
289
293
|
|
|
290
294
|
list_sha1s = get_list_sha1s(cache, key)
|
|
291
|
-
items = result.get("items", [])
|
|
292
|
-
offset = pagination["start_index"] if pagination else 0
|
|
293
295
|
result["item_entries"] = [
|
|
294
|
-
(
|
|
296
|
+
(index, item, list_sha1s[i] if i < len(list_sha1s) else "", editable)
|
|
297
|
+
for i, (index, item, _, editable) in enumerate(result.get("item_entries", []))
|
|
295
298
|
]
|
|
296
299
|
case KeyType.HASH:
|
|
297
|
-
|
|
298
|
-
if pagination and
|
|
300
|
+
entries = result.get("field_entries", [])
|
|
301
|
+
if pagination and entries:
|
|
299
302
|
from django_cachex.admin.cas import get_hash_field_sha1s_for
|
|
300
303
|
|
|
301
|
-
hash_sha1s = get_hash_field_sha1s_for(cache, key,
|
|
304
|
+
hash_sha1s = get_hash_field_sha1s_for(cache, key, [field for field, *_ in entries])
|
|
302
305
|
else:
|
|
303
306
|
from django_cachex.admin.cas import get_hash_field_sha1s
|
|
304
307
|
|
|
305
308
|
hash_sha1s = get_hash_field_sha1s(cache, key)
|
|
306
|
-
result["field_entries"] = [
|
|
309
|
+
result["field_entries"] = [
|
|
310
|
+
(field, value, hash_sha1s.get(field, ""), editable) for field, value, _, editable in entries
|
|
311
|
+
]
|
|
307
312
|
except NotSupportedError:
|
|
308
313
|
# ``BaseCachex`` declares ``eval_script`` and raises, so LocMem and
|
|
309
314
|
# Database land here: render without CAS fingerprints.
|
|
@@ -172,18 +172,58 @@
|
|
|
172
172
|
color: var(--error-fg);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
/*
|
|
175
|
+
/* ===== VALUE INPUTS ===== */
|
|
176
|
+
/* Shared textarea for every value, item and member editor. Height comes from
|
|
177
|
+
the rows attribute, which differs per context; width fills the container. */
|
|
176
178
|
/* border-box: admin textareas carry a 1px border and 8px of side padding, which
|
|
177
179
|
would otherwise sit outside the 100% width and clip the right edge */
|
|
178
|
-
|
|
179
|
-
#id_list_values,
|
|
180
|
-
#id_set_members,
|
|
181
|
-
#id_hash_value,
|
|
182
|
-
#id_zset_value {
|
|
183
|
-
font-family: var(--font-family-monospace);
|
|
180
|
+
.cachex-value-input {
|
|
184
181
|
width: 100%;
|
|
185
182
|
box-sizing: border-box;
|
|
186
|
-
|
|
183
|
+
resize: vertical;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* The admin's fieldset.monospace rule covers textareas only, but the hash field
|
|
187
|
+
name and the zset score sit next to one and should read the same. */
|
|
188
|
+
fieldset.monospace input.cachex-value-input {
|
|
189
|
+
font-family: var(--font-family-monospace);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Submit row under a value textarea */
|
|
193
|
+
.cachex-value-actions {
|
|
194
|
+
margin-top: 10px;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Field-name input above a value textarea. A <p> wrapper would pick up the
|
|
198
|
+
admin's .aligned padding-left and sit indented against the textarea. */
|
|
199
|
+
.cachex-name-row {
|
|
200
|
+
margin-bottom: 6px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.cachex-name-row input {
|
|
204
|
+
width: 20em;
|
|
205
|
+
max-width: 100%;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* In an entry table the stacked buttons are taller than a two-row field, so let
|
|
209
|
+
the field grow to the row height rather than leaving a gap under it. The 1px
|
|
210
|
+
cell height is the usual table trick: a percentage height on the child only
|
|
211
|
+
resolves once the cell itself has a specified one, and content still wins. */
|
|
212
|
+
.cachex-entry-table tbody td {
|
|
213
|
+
height: 1px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.cachex-entry-table td textarea.cachex-value-input {
|
|
217
|
+
height: 100%;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Row actions sit beside the value in a table row, stacked so that two buttons
|
|
221
|
+
line up with the value field instead of widening the row. */
|
|
222
|
+
.cachex-row-actions {
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
gap: 4px;
|
|
226
|
+
align-items: stretch;
|
|
187
227
|
}
|
|
188
228
|
|
|
189
229
|
/* ===== NOTES ===== */
|
django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_hash.html
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
{% with input_tpl="admin/django_cachex/key/key_detail_value_input.html#value-input" %}
|
|
3
|
+
<!-- Hash Operations -->
|
|
4
|
+
<fieldset class="module aligned monospace">
|
|
5
|
+
<h2>{% trans 'Operations' %}</h2>
|
|
6
|
+
<div class="form-row">
|
|
7
|
+
<div>
|
|
8
|
+
<label for="id_hset_value">{% trans 'Set Field:' %}</label>
|
|
9
|
+
<form method="post">
|
|
10
|
+
{% csrf_token %}
|
|
11
|
+
<input type="hidden" name="action" value="hset">
|
|
12
|
+
<div class="cachex-name-row"><input type="text" name="field" placeholder="{% trans 'field' %}" class="vTextField"></div>
|
|
13
|
+
{% include input_tpl with name="field_value" rows=4 field_id="id_hset_value" placeholder=_("value") editable=True only %}
|
|
14
|
+
<div class="cachex-value-actions">
|
|
15
|
+
<button type="submit" class="button btn-small">{% trans 'Set' %}</button>
|
|
16
|
+
</div>
|
|
17
|
+
</form>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</fieldset>
|
|
21
|
+
<!-- Hash Fields -->
|
|
22
|
+
<fieldset class="module aligned monospace">
|
|
23
|
+
<h2>{% trans 'Hash Fields' %}{% if type_data.length %} ({{ type_data.length }}){% endif %}</h2>
|
|
24
|
+
{% if type_data.field_entries %}
|
|
25
|
+
<div class="results">
|
|
26
|
+
<table id="result_list" class="cachex-entry-table" style="width: 100%;">
|
|
27
|
+
<thead>
|
|
28
|
+
<tr>
|
|
29
|
+
<th scope="col" style="width: 25%;">{% trans 'Field' %}</th>
|
|
30
|
+
<th scope="col">{% trans 'Value' %}</th>
|
|
31
|
+
<th scope="col" style="width: 110px;">{% trans 'Actions' %}</th>
|
|
32
|
+
</tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
{% for field, value, sha1, editable in type_data.field_entries %}
|
|
36
|
+
<tr class="{% cycle 'row1' 'row2' %}">
|
|
37
|
+
<td><input type="text" name="new_field" value="{{ field }}" class="cachex-value-input" form="hash-update-{{ forloop.counter0 }}"{% if not editable %} readonly title="{% trans 'Not JSON-serializable, so this row cannot be edited safely.' %}"{% endif %}></td>
|
|
38
|
+
<td>{% include input_tpl with name="field_value" value=value rows=2 form_id="hash-update-" row_index=forloop.counter0 editable=editable only %}</td>
|
|
39
|
+
<td>
|
|
40
|
+
<div class="cachex-row-actions">
|
|
41
|
+
{% if editable %}
|
|
42
|
+
<button type="submit" form="hash-update-{{ forloop.counter0 }}" class="button btn-small">{% trans 'Update' %}</button>
|
|
43
|
+
{% else %}
|
|
44
|
+
<button type="button" class="button btn-small" disabled title="{% trans 'Not JSON-serializable, so this value cannot be edited safely.' %}">{% trans 'Update' %}</button>
|
|
45
|
+
{% endif %}
|
|
46
|
+
<button type="submit" form="hash-delete-{{ forloop.counter0 }}" class="button delete-btn btn-small" onclick="return confirm('{% trans 'Delete this field?' %}');">{% trans 'Delete' %}</button>
|
|
47
|
+
</div>
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
{% endfor %}
|
|
51
|
+
</tbody>
|
|
52
|
+
</table>
|
|
53
|
+
</div>
|
|
54
|
+
<!-- Forms for hash operations (outside table for valid HTML) -->
|
|
55
|
+
{% for field, value, sha1, editable in type_data.field_entries %}
|
|
56
|
+
<form id="hash-update-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
57
|
+
{% csrf_token %}
|
|
58
|
+
<input type="hidden" name="action" value="hupdate">
|
|
59
|
+
<input type="hidden" name="field" value="{{ field }}">
|
|
60
|
+
{% if sha1 %}<input type="hidden" name="original_sha1" value="{{ sha1 }}">{% endif %}
|
|
61
|
+
</form>
|
|
62
|
+
<form id="hash-delete-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
63
|
+
{% csrf_token %}
|
|
64
|
+
<input type="hidden" name="action" value="hdel">
|
|
65
|
+
<input type="hidden" name="field" value="{{ field }}">
|
|
66
|
+
</form>
|
|
67
|
+
{% endfor %}
|
|
68
|
+
{% else %}
|
|
69
|
+
<p class="quiet" style="padding: 10px;">{% trans 'Hash is empty.' %}</p>
|
|
70
|
+
{% endif %}
|
|
71
|
+
{% include "admin/django_cachex/key/key_detail_pagination.html" %}
|
|
72
|
+
</fieldset>
|
|
73
|
+
{% endwith %}
|
django_cachex-0.4.2/django_cachex/admin/templates/admin/django_cachex/key/key_detail_list.html
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
{% with input_tpl="admin/django_cachex/key/key_detail_value_input.html#value-input" %}
|
|
3
|
+
<!-- List Operations -->
|
|
4
|
+
<fieldset class="module aligned monospace">
|
|
5
|
+
<h2>{% trans 'Operations' %}</h2>
|
|
6
|
+
<div class="form-row">
|
|
7
|
+
<div>
|
|
8
|
+
<label for="id_lpush_value">{% trans 'Push Left:' %}</label>
|
|
9
|
+
<form method="post">
|
|
10
|
+
{% csrf_token %}
|
|
11
|
+
<input type="hidden" name="action" value="lpush">
|
|
12
|
+
{% include input_tpl with name="value" rows=4 field_id="id_lpush_value" placeholder=_("value") editable=True only %}
|
|
13
|
+
<div class="cachex-value-actions">
|
|
14
|
+
<button type="submit" class="button btn-small">{% trans 'Push' %}</button>
|
|
15
|
+
</div>
|
|
16
|
+
</form>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="form-row">
|
|
20
|
+
<div>
|
|
21
|
+
<label for="id_rpush_value">{% trans 'Push Right:' %}</label>
|
|
22
|
+
<form method="post">
|
|
23
|
+
{% csrf_token %}
|
|
24
|
+
<input type="hidden" name="action" value="rpush">
|
|
25
|
+
{% include input_tpl with name="value" rows=4 field_id="id_rpush_value" placeholder=_("value") editable=True only %}
|
|
26
|
+
<div class="cachex-value-actions">
|
|
27
|
+
<button type="submit" class="button btn-small">{% trans 'Push' %}</button>
|
|
28
|
+
</div>
|
|
29
|
+
</form>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="form-row">
|
|
33
|
+
<label>{% trans 'Pop Left:' %}</label>
|
|
34
|
+
<form method="post" style="display: inline;">
|
|
35
|
+
{% csrf_token %}
|
|
36
|
+
<input type="hidden" name="action" value="lpop">
|
|
37
|
+
<input type="number" name="pop_count" value="1" min="1" class="vIntegerField" style="width: 50px;" title="{% trans 'Count' %}">
|
|
38
|
+
<button type="submit" class="button btn-small">{% trans 'Pop' %}</button>
|
|
39
|
+
</form>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="form-row">
|
|
42
|
+
<label>{% trans 'Pop Right:' %}</label>
|
|
43
|
+
<form method="post" style="display: inline;">
|
|
44
|
+
{% csrf_token %}
|
|
45
|
+
<input type="hidden" name="action" value="rpop">
|
|
46
|
+
<input type="number" name="pop_count" value="1" min="1" class="vIntegerField" style="width: 50px;" title="{% trans 'Count' %}">
|
|
47
|
+
<button type="submit" class="button btn-small">{% trans 'Pop' %}</button>
|
|
48
|
+
</form>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="form-row">
|
|
51
|
+
<label>{% trans 'Trim:' %}</label>
|
|
52
|
+
<form method="post" style="display: inline;">
|
|
53
|
+
{% csrf_token %}
|
|
54
|
+
<input type="hidden" name="action" value="ltrim">
|
|
55
|
+
<input type="number" name="trim_start" value="0" class="vIntegerField" style="width: 60px;" title="{% trans 'Start index' %}" placeholder="{% trans 'start' %}">
|
|
56
|
+
<input type="number" name="trim_stop" value="-1" class="vIntegerField" style="width: 60px;" title="{% trans 'Stop index (-1 for last)' %}" placeholder="{% trans 'stop' %}">
|
|
57
|
+
<button type="submit" class="button btn-small" onclick="return confirm('{% trans 'Trim list to this range? Elements outside the range will be removed.' %}');">{% trans 'Trim' %}</button>
|
|
58
|
+
</form>
|
|
59
|
+
</div>
|
|
60
|
+
</fieldset>
|
|
61
|
+
<!-- List Items -->
|
|
62
|
+
<fieldset class="module aligned monospace">
|
|
63
|
+
<h2>{% trans 'List Items' %}{% if type_data.length %} ({{ type_data.length }}){% endif %}</h2>
|
|
64
|
+
{% if type_data.item_entries %}
|
|
65
|
+
<div class="results">
|
|
66
|
+
<table id="result_list" class="cachex-entry-table" style="width: 100%;">
|
|
67
|
+
<thead>
|
|
68
|
+
<tr>
|
|
69
|
+
<th scope="col" style="width: 60px;">{% trans 'Index' %}</th>
|
|
70
|
+
<th scope="col">{% trans 'Value' %}</th>
|
|
71
|
+
<th scope="col" style="width: 110px;">{% trans 'Actions' %}</th>
|
|
72
|
+
</tr>
|
|
73
|
+
</thead>
|
|
74
|
+
<tbody>
|
|
75
|
+
{% for index, item, sha1, editable in type_data.item_entries %}
|
|
76
|
+
<tr class="{% cycle 'row1' 'row2' %}">
|
|
77
|
+
<td class="quiet">{{ index }}</td>
|
|
78
|
+
<td>{% include input_tpl with name="value" value=item rows=2 form_id="list-update-" row_index=forloop.counter0 editable=editable only %}</td>
|
|
79
|
+
<td>
|
|
80
|
+
<div class="cachex-row-actions">
|
|
81
|
+
{% if editable %}
|
|
82
|
+
<button type="submit" form="list-update-{{ forloop.counter0 }}" class="button btn-small">{% trans 'Update' %}</button>
|
|
83
|
+
<button type="submit" form="list-remove-{{ forloop.counter0 }}" class="button delete-btn btn-small" onclick="return confirm('{% trans 'Remove this item?' %}');">{% trans 'Remove' %}</button>
|
|
84
|
+
{% else %}
|
|
85
|
+
<button type="button" class="button btn-small" disabled title="{% trans 'Not JSON-serializable, so this item cannot be edited or matched for removal.' %}">{% trans 'Update' %}</button>
|
|
86
|
+
<button type="button" class="button delete-btn btn-small" disabled title="{% trans 'Not JSON-serializable, so this item cannot be edited or matched for removal.' %}">{% trans 'Remove' %}</button>
|
|
87
|
+
{% endif %}
|
|
88
|
+
</div>
|
|
89
|
+
</td>
|
|
90
|
+
</tr>
|
|
91
|
+
{% endfor %}
|
|
92
|
+
</tbody>
|
|
93
|
+
</table>
|
|
94
|
+
</div>
|
|
95
|
+
<!-- Forms for list operations (outside table for valid HTML) -->
|
|
96
|
+
{% for index, item, sha1, editable in type_data.item_entries %}
|
|
97
|
+
<form id="list-update-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
98
|
+
{% csrf_token %}
|
|
99
|
+
<input type="hidden" name="action" value="lset">
|
|
100
|
+
<input type="hidden" name="index" value="{{ index }}">
|
|
101
|
+
{% if sha1 %}<input type="hidden" name="original_sha1" value="{{ sha1 }}">{% endif %}
|
|
102
|
+
</form>
|
|
103
|
+
<form id="list-remove-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
104
|
+
{% csrf_token %}
|
|
105
|
+
<input type="hidden" name="action" value="lrem">
|
|
106
|
+
<input type="hidden" name="value" value="{{ item }}">
|
|
107
|
+
</form>
|
|
108
|
+
{% endfor %}
|
|
109
|
+
{% else %}
|
|
110
|
+
<p class="quiet" style="padding: 10px;">{% trans 'List is empty.' %}</p>
|
|
111
|
+
{% endif %}
|
|
112
|
+
{% include "admin/django_cachex/key/key_detail_pagination.html" %}
|
|
113
|
+
</fieldset>
|
|
114
|
+
{% endwith %}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
{% with input_tpl="admin/django_cachex/key/key_detail_value_input.html#value-input" %}
|
|
3
|
+
<!-- Set Operations -->
|
|
4
|
+
<fieldset class="module aligned monospace">
|
|
5
|
+
<h2>{% trans 'Operations' %}</h2>
|
|
6
|
+
<div class="form-row">
|
|
7
|
+
<div>
|
|
8
|
+
<label for="id_sadd_member">{% trans 'Add:' %}</label>
|
|
9
|
+
<form method="post">
|
|
10
|
+
{% csrf_token %}
|
|
11
|
+
<input type="hidden" name="action" value="sadd">
|
|
12
|
+
{% include input_tpl with name="member" rows=4 field_id="id_sadd_member" placeholder=_("member") editable=True only %}
|
|
13
|
+
<div class="cachex-value-actions">
|
|
14
|
+
<button type="submit" class="button btn-small">{% trans 'Add' %}</button>
|
|
15
|
+
</div>
|
|
16
|
+
</form>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="form-row">
|
|
20
|
+
<label>{% trans 'Pop:' %}</label>
|
|
21
|
+
<form method="post" style="display: inline;">
|
|
22
|
+
{% csrf_token %}
|
|
23
|
+
<input type="hidden" name="action" value="spop">
|
|
24
|
+
<input type="number" name="pop_count" value="1" min="1" class="vIntegerField" style="width: 50px;" title="{% trans 'Count' %}">
|
|
25
|
+
<button type="submit" class="button btn-small" onclick="return confirm('{% trans 'Pop random members? They will be removed from the set.' %}');">{% trans 'Random' %}</button>
|
|
26
|
+
</form>
|
|
27
|
+
</div>
|
|
28
|
+
</fieldset>
|
|
29
|
+
<!-- Set Members -->
|
|
30
|
+
<fieldset class="module aligned monospace">
|
|
31
|
+
<h2>{% trans 'Set Members' %}{% if type_data.length %} ({{ type_data.length }}){% endif %}</h2>
|
|
32
|
+
{% if type_data.members %}
|
|
33
|
+
<div class="results">
|
|
34
|
+
<table id="result_list" class="cachex-entry-table" style="width: 100%;">
|
|
35
|
+
<thead>
|
|
36
|
+
<tr>
|
|
37
|
+
<th scope="col">{% trans 'Member' %}</th>
|
|
38
|
+
<th scope="col" style="width: 110px;">{% trans 'Actions' %}</th>
|
|
39
|
+
</tr>
|
|
40
|
+
</thead>
|
|
41
|
+
<tbody>
|
|
42
|
+
{% for member, editable in type_data.members %}
|
|
43
|
+
<tr class="{% cycle 'row1' 'row2' %}">
|
|
44
|
+
<td>{% include input_tpl with name="new_member" value=member rows=2 form_id="set-update-" row_index=forloop.counter0 editable=editable only %}</td>
|
|
45
|
+
<td>
|
|
46
|
+
<div class="cachex-row-actions">
|
|
47
|
+
{% if editable %}
|
|
48
|
+
<button type="submit" form="set-update-{{ forloop.counter0 }}" class="button btn-small">{% trans 'Update' %}</button>
|
|
49
|
+
<button type="submit" form="set-remove-{{ forloop.counter0 }}" class="button delete-btn btn-small" onclick="return confirm('{% trans 'Remove this member?' %}');">{% trans 'Remove' %}</button>
|
|
50
|
+
{% else %}
|
|
51
|
+
<button type="button" class="button btn-small" disabled title="{% trans 'Not JSON-serializable, so this member cannot be edited or matched for removal.' %}">{% trans 'Update' %}</button>
|
|
52
|
+
<button type="button" class="button delete-btn btn-small" disabled title="{% trans 'Not JSON-serializable, so this member cannot be edited or matched for removal.' %}">{% trans 'Remove' %}</button>
|
|
53
|
+
{% endif %}
|
|
54
|
+
</div>
|
|
55
|
+
</td>
|
|
56
|
+
</tr>
|
|
57
|
+
{% endfor %}
|
|
58
|
+
</tbody>
|
|
59
|
+
</table>
|
|
60
|
+
</div>
|
|
61
|
+
<!-- Forms for set operations (outside table for valid HTML) -->
|
|
62
|
+
{% for member, editable in type_data.members %}
|
|
63
|
+
<form id="set-update-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
64
|
+
{% csrf_token %}
|
|
65
|
+
<input type="hidden" name="action" value="supdate">
|
|
66
|
+
<input type="hidden" name="member" value="{{ member }}">
|
|
67
|
+
</form>
|
|
68
|
+
<form id="set-remove-{{ forloop.counter0 }}" method="post" style="display: none;">
|
|
69
|
+
{% csrf_token %}
|
|
70
|
+
<input type="hidden" name="action" value="srem">
|
|
71
|
+
<input type="hidden" name="member" value="{{ member }}">
|
|
72
|
+
</form>
|
|
73
|
+
{% endfor %}
|
|
74
|
+
{% else %}
|
|
75
|
+
<p class="quiet" style="padding: 10px;">{% trans 'Set is empty.' %}</p>
|
|
76
|
+
{% endif %}
|
|
77
|
+
{% include "admin/django_cachex/key/key_detail_pagination.html" %}
|
|
78
|
+
</fieldset>
|
|
79
|
+
{% endwith %}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
{% load i18n %}
|
|
2
|
+
{% with input_tpl="admin/django_cachex/key/key_detail_value_input.html#value-input" %}
|
|
2
3
|
<!-- Stream Operations -->
|
|
3
|
-
<fieldset class="module aligned">
|
|
4
|
+
<fieldset class="module aligned monospace">
|
|
4
5
|
<h2>{% trans 'Operations' %}</h2>
|
|
5
6
|
<div class="form-row">
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
<div>
|
|
8
|
+
<label for="id_xadd_value">{% trans 'Add Entry:' %}</label>
|
|
9
|
+
<form method="post">
|
|
10
|
+
{% csrf_token %}
|
|
11
|
+
<input type="hidden" name="action" value="xadd">
|
|
12
|
+
<div class="cachex-name-row"><input type="text" name="field" placeholder="{% trans 'field' %}" class="vTextField"></div>
|
|
13
|
+
{% include input_tpl with name="field_value" rows=4 field_id="id_xadd_value" placeholder=_("value") editable=True only %}
|
|
14
|
+
<div class="cachex-value-actions">
|
|
15
|
+
<button type="submit" class="button btn-small">{% trans 'Add' %}</button>
|
|
16
|
+
</div>
|
|
17
|
+
</form>
|
|
18
|
+
</div>
|
|
14
19
|
</div>
|
|
15
20
|
<div class="form-row">
|
|
16
21
|
<label>{% trans 'Trim:' %}</label>
|
|
@@ -23,11 +28,11 @@
|
|
|
23
28
|
</div>
|
|
24
29
|
</fieldset>
|
|
25
30
|
<!-- Stream Entries -->
|
|
26
|
-
<fieldset class="module aligned">
|
|
31
|
+
<fieldset class="module aligned monospace">
|
|
27
32
|
<h2>{% trans 'Stream Entries' %}{% if type_data.length %} ({{ type_data.length }}){% endif %}</h2>
|
|
28
33
|
{% if type_data.entries %}
|
|
29
34
|
<div class="results">
|
|
30
|
-
<table id="result_list" style="width: 100%;">
|
|
35
|
+
<table id="result_list" class="cachex-entry-table" style="width: 100%;">
|
|
31
36
|
<thead>
|
|
32
37
|
<tr>
|
|
33
38
|
<th scope="col" style="width: 180px;">{% trans 'Entry ID' %}</th>
|
|
@@ -58,3 +63,4 @@
|
|
|
58
63
|
{% endif %}
|
|
59
64
|
{% include "admin/django_cachex/key/key_detail_pagination.html" %}
|
|
60
65
|
</fieldset>
|
|
66
|
+
{% endwith %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{% load i18n %}
|
|
2
2
|
<!-- String Value Editor (default for string type or when type data not available) -->
|
|
3
|
-
<fieldset class="module aligned">
|
|
3
|
+
<fieldset class="module aligned monospace">
|
|
4
4
|
<h2>{% trans 'Value' %}{% if value_is_editable %} <span class="quiet" style="font-weight: normal; font-size: 0.85em;">(JSON)</span>{% else %} <span class="quiet" style="font-weight: normal; font-size: 0.85em;">({% trans 'read-only' %})</span>{% endif %}</h2>
|
|
5
5
|
{% if not value_is_editable %}
|
|
6
6
|
<div class="warningnote">
|
|
@@ -15,15 +15,9 @@
|
|
|
15
15
|
<div class="form-row">
|
|
16
16
|
<div>
|
|
17
17
|
<label for="id_value" class="{% if not value_is_editable %}readonly{% endif %}">{% trans 'Value:' %}</label>
|
|
18
|
-
|
|
19
|
-
id="id_value"
|
|
20
|
-
name="value"
|
|
21
|
-
rows="12"
|
|
22
|
-
class="vLargeTextField"
|
|
23
|
-
{% if not value_is_editable %}readonly{% endif %}
|
|
24
|
-
>{{ value_display }}</textarea>
|
|
18
|
+
{% include "admin/django_cachex/key/key_detail_value_input.html#value-input" with name="value" value=value_display rows=12 field_id="id_value" editable=value_is_editable only %}
|
|
25
19
|
{% if value_is_editable %}
|
|
26
|
-
<div
|
|
20
|
+
<div class="cachex-value-actions">
|
|
27
21
|
<button type="submit" class="button btn-small">{% trans 'Update' %}</button>
|
|
28
22
|
</div>
|
|
29
23
|
{% endif %}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
{% comment %}
|
|
3
|
+
Shared value textarea for every editor on the key detail page.
|
|
4
|
+
|
|
5
|
+
Parameters:
|
|
6
|
+
name POST field name (required)
|
|
7
|
+
value current text
|
|
8
|
+
rows visible rows: 12 for the string editor, 4 for the operations
|
|
9
|
+
forms, 2 for the compact rows in a member/item table
|
|
10
|
+
form_id id of the out-of-table <form> the field belongs to; in a table
|
|
11
|
+
it is a prefix that row_index completes
|
|
12
|
+
row_index row number appended to form_id, for per-row forms
|
|
13
|
+
field_id id attribute, for a <label for="...">
|
|
14
|
+
placeholder placeholder text
|
|
15
|
+
editable always pass explicitly: False renders the field read-only,
|
|
16
|
+
which is what a value that is not JSON-serializable needs
|
|
17
|
+
{% endcomment %}
|
|
18
|
+
{% partialdef value-input %}<textarea{% if field_id %} id="{{ field_id }}"{% endif %} name="{{ name }}" rows="{{ rows|default:2 }}" class="cachex-value-input"{% if form_id %} form="{{ form_id }}{{ row_index }}"{% endif %}{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}{% if not editable %} readonly title="{% trans 'Not JSON-serializable, so this is a Python repr() and cannot be edited safely.' %}"{% endif %}>{{ value }}</textarea>{% endpartialdef %}
|