My collection of things for working with Django.
Project description
My collection of things for working with Django.
Latest release 20251231: New IndexByPK mixin for Models, supporting Model[pk].
Presently this provides:
BaseCommand: a drop in replacement fordjango.core.management.base.BaseCommandwhich uses acs.cmdutils.BaseCommandstyle of implementationmodel_batches_qs: a generator yieldingQuerySets for batches of aModel
Short summary:
BaseCommand: A drop in class fordjango.core.management.base.BaseCommandwhich subclassescs.cmdutils.BaseCommand.DjangoSpecificSubCommand: A subclass ofcs.cmdutils.SubCommandwith additional support for Django'sBaseCommand.IndexByPK: A mixin forModelclasses which povides a__class_getitem__method to fetch an instance by itspk.model_batches_qs: A generator yieldingQuerySets which produce nonoverlapping batches ofModelinstances.model_instances: A generator yieldingModelinstances. This is a wrapper formodel_batches_qsand accepts the same arguments, and some additional parameters.
Module contents:
-
class BaseCommand(cs.cmdutils.BaseCommand, django.core.management.base.BaseCommand): A drop in class fordjango.core.management.base.BaseCommandwhich subclassescs.cmdutils.BaseCommand.This lets me write management commands more easily, particularly if there are subcommands.
This is a drop in in the sense that you still make a management command in nearly the same way:
from cs.djutils import BaseCommand class Command(BaseCommand):and
manage.pywill find it and run it as normal. But from that point on the style is as forcs.cmdutils.BaseCommand:- no
argparsesetup - direct support for subcommands as methods
- succinct option parsing, if you want additional command line options
- usage text in the subcommand method docstring
A simple command looks like this:
class Command(BaseCommand): def main(self, argv): """ Usage: {cmd} ....... Do the main thing. """ ... do stuff based on the CLI args `argv` ...A command with subcommands looks like this:
class Command(BaseCommand): def cmd_this(self, argv): """ Usage: {cmd} ...... Do this. """ ... do the "this" subcommand ... def cmd_that(self, argv): """ Usage: {cmd} ...... Do that. """ ... do the "that" subcommand ...If want some kind of app/client specific "overcommand" composed from other management commands you can import them and make them subcommands of the overcommand:
from .other_command import Command as OtherCommand class Command(BaseCommand): # provide it as the "other" subcommand cmd_other = OtherCommandOption parsing is inline in the command.
selfcomes presupplied with a.optionsattribute which is an instance ofcs.cmdutils.BaseCommandOptions(or some subclass).Parsing options is light weight and automatically updates the usage text. This example adds command line switches to the default switches:
-x: a Boolean, settingself.options.x--thing-limitn: anint, settingself.options.thing_limit=n--modeblah: a string, settingself.options.mode=blah
Code sketch:
from cs.cmdutils import popopts class Command(BaseCommand): @popopts( x=None, thing_limit_=int, mode_='The run mode.', ) def cmd_this(self, argv): """ Usage: {cmd} Do this thing. """ options = self.options ... now consult options.x or whatever ... argv is now the remaining arguments after the optionsA drop in class for `django.core.management.base.BaseCommand`which subclasses
cs.cmdutils.BaseCommand.This lets me write management commands more easily, particularly if there are subcommands.
This is a drop in in the sense that you still make a management command in nearly the same way:
from cs.djutils import BaseCommand class Command(BaseCommand):and
manage.pywill find it and run it as normal. But from that point on the style is as forcs.cmdutils.BaseCommand:- no
argparsesetup - direct support for subcommands as methods
- succinct option parsing, if you want additional command line options
- usage text in the subcommand method docstring
A simple command looks like this:
class Command(BaseCommand): def main(self, argv): """ A command with subcommands looks like this: class Command(BaseCommand): def cmd_this(self, argv): """ Usage: {cmd} ...... Do this. """ ... do the "this" subcommand ... def cmd_that(self, argv): """ Usage: {cmd} ...... Do that. """ ... do the "that" subcommand ...If want some kind of app/client specific "overcommand" composed from other management commands you can import them and make them subcommands of the overcommand:
from .other_command import Command as OtherCommand class Command(BaseCommand): # provide it as the "other" subcommand cmd_other = OtherCommandOption parsing is inline in the command.
selfcomes presupplied with a.optionsattribute which is an instance ofcs.cmdutils.BaseCommandOptions(or some subclass).Parsing options is light weight and automatically updates the usage text. This example adds command line switches to the default switches:
-x: a Boolean, settingself.options.x--thing-limitn: anint, settingself.options.thing_limit=n--modeblah: a string, settingself.options.mode=blah
Code sketch:
from cs.cmdutils import popopts class Command(BaseCommand): @popopts( x=None, thing_limit_=int, mode_='The run mode.', ) def cmd_this(self, argv): """ Usage: {cmd} Do this thing. """ options = self.options ... now consult options.x or whatever ... argv is now the remaining arguments after the optionsUsage summary:
Usage: base [common-options...] ....... Do the main thing. """ ... do stuff based on the CLI args `argv` ... - no
BaseCommand.Options
BaseCommand.SubCommandClass
BaseCommand.add_arguments(self, parser):
Add the Options.COMMON_OPT_SPECS to the argparse parser.
This is basicly to support the Django call_command function.
BaseCommand.handle(*, argv, **options):
The Django BaseComand.handle method.
This creates another instance for argv and runs it.
BaseCommand.run_from_argv(argv):
Intercept django.core.management.base.BaseCommand.run_from_argv.
Construct an instance of cs.djutils.DjangoBaseCommand and run it.
class DjangoSpecificSubCommand(cs.cmdutils.SubCommand): A subclass ofcs.cmdutils.SubCommandwith additional support for Django'sBaseCommand.
DjangoSpecificSubCommand.__call__(self, argv: List[str]):
Run this SubCommand with argv.
This calls Django's BaseCommand.run_from_argv for pure Django commands.
DjangoSpecificSubCommand.is_pure_django_command:
Whether this subcommand is a pure Django BaseCommand.
DjangoSpecificSubCommand.usage_text(self, *, cmd=None, **kw):
Return the usage text for this subcommand.
-
class IndexByPK: A mixin forModelclasses which povides a__class_getitem__method to fetch an instance by itspk.Example:
book9 = BookModel[9]
IndexByPK.__class_getitem__(pk):
Index the class by pk, a primary key value.
This is just a shim for:
cls.objects.get(pk=pk)
-
model_batches_qs(model: django.db.models.base.Model, field_name='pk', *, after=None, chunk_size=1024, desc=False, exclude=None, filter=None, only=None, yield_base_qs=False) -> Iterable[django.db.models.query.QuerySet]: A generator yieldingQuerySets which produce nonoverlapping batches ofModelinstances.Efficient behaviour requires the field to be indexed. Correct behaviour requires the field values to be unique.
See
model_instancesfor an iterable of instances wrapper of this function, where you have no need to further amend theQuerySets or to be aware of the batches.Parameters:
model: theModelto queryfield_name: default'pk', the name of the field on which to order the batchesafter: an optional field value - iteration commences immediately after this value; this may also be aModelinstance, in which case the value is obtained viagetattr(after,field_name)chunk_size: the maximum size of each chunkdesc: defaultFalse; if true then order the batches in descending order instead of ascending orderexclude: optional mapping of Django query terms to exclude byfilter: optional mapping of Django query terms to filter byonly: optional sequence of field names for a Django query.only()yield_base_qs: if true (defaultFalse) yield the baseQuerySetahead of theQuerySets for each batch; this can be useful for a count or other preanalysis
Example iteration of a
Modelwould look like:from itertools import chain from cs.djutils import model_batches_qs for instance in chain.from_iterable(model_batches_qs(MyModel)): ... work with instance ...By returning
QuerySets it is possible to further alter each query:from cs.djutils import model_batches_qs for batch_qs in model_batches_qs(MyModel): for result in batch_qs.filter( some_field__gt=10 ).select_related(.......): ... work with each result in the batch ...or:
from itertools import chain from cs.djutils import model_batches_qs for result in chain.from_iterable( batch_qs.filter( some_field__gt=10 ).select_related(.......) for batch_qs in model_batches_qs(MyModel) ): ... work with each result ... -
model_instances(model: django.db.models.base.Model, field_name='pk', prefetch_related=None, select_related=None, yield_base_qs=False, **mbqs_kw) -> Iterable[django.db.models.base.Model]: A generator yieldingModelinstances. This is a wrapper formodel_batches_qsand accepts the same arguments, and some additional parameters.If you need to extend the
QuerySets beyond what themodel_batches_qsparameters support it may be better to use that and extend each returnedQuerySet.If
yield_base_qsis true (defaultFalse), yield the baseQuerySetahead of the model instances; this can be useful for a count or other preanalysis.Additional parameters beyond those for
model_batches_qs:prefetch_related: an optional list of fields to apply to each query with.prefetch_related()select_related: an optional list of fields to apply to each query with.select_related()
Efficient behaviour requires the field to be indexed. Correct behaviour requires the field values to be unique.
Release Log
Release 20251231: New IndexByPK mixin for Models, supporting Model[pk].
Release 20250724: model_batches_qs (and therefore also model_instances): after may also be a Model instance.
Release 20250609:
- model_batches_qs: new yield_base_qs=False parameter to yield the base QuerySet ahead of the batch QuerySets.
- model_instances: new yield_base_qs=False parameter to yield the base QuerySet ahead of the Model instances.
Release 20250606:
- model_batches_qs: new after=None parameter to indicate preiteration point.
- model_instances: new optional parameters prefetch_related and select_related to augument the querysets before iteration.
Release 20250219:
- model_batches_qs: accept a nonmapping for exclude= or filter= eg a Q() function.
- model_batches_qs: new optional only= parameter.
Release 20250213: New model_instances() wrapper for model_batches_qs() returning an iterable of Model instances.
Release 20250113.2: model_batches_qs: bugfix second and following QuerySet construction.
Release 20250113.1: model_batches_qs: new exclude=dict and filter=dict optional parameters to filter before the slice.
Release 20250113: model_batches_qs: improve the query which measures the current batch.
Release 20250111.1: Documentation update.
Release 20250111: New model_batches_qs() generator yielding QuerySets for batches of a Model.
Release 20241222.3: Autocall settings.configure() if required because Django's settings object is a royal PITA.
Release 20241222.2: BaseCommand.Options.settings: call settings.configure() on init if that has not already been done.
Release 20241222.1: Placate the dataclass - upgrade BaseCommand.Options.settings to be a field() with a default_factory.
Release 20241222: BaseCommand.Options: include .settings with the public django.conf.settings names, mostly for cmd_info and cmd_repl.
Release 20241119: New DjangoSpecificSubCommand(CSBaseCommand.SubCommandClass) to include support for pure Django BaseCommands.
Release 20241111:
Rename DjangoBaseCommand to just BaseCommand so that we go from cs.djutils import BaseCommand. Less confusing.
Release 20241110: Initial PyPI release with DjangoBaseCommand, cs.cmdutils.BaseCommand subclass suppplanting django.core.management.base.BaseCommand.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cs_djutils-20251231.tar.gz.
File metadata
- Download URL: cs_djutils-20251231.tar.gz
- Upload date:
- Size: 7.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9eb6a0ae16f44020e01cd7af1884f072f9be1d98c09669b79db15df6560c27ec
|
|
| MD5 |
e902340c1f71ae3a58fa02d3cfff9a05
|
|
| BLAKE2b-256 |
d3a5bee4b6edc1e888875ddb260e70f05ee9de010c3ae555bb38130396cab0b9
|
File details
Details for the file cs_djutils-20251231-py2.py3-none-any.whl.
File metadata
- Download URL: cs_djutils-20251231-py2.py3-none-any.whl
- Upload date:
- Size: 9.0 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae9b964b0442bd64129992d706f3a2402a1f234bf186fc68ac21d22ca492db36
|
|
| MD5 |
1240e7bb716e1ed3e464daf89c35f267
|
|
| BLAKE2b-256 |
c8999fc72e967250a517b09cd7c1b84c8fbd57d2d52a81e6b7a09ba447490558
|