For Developers
This technical section is targeting software developers.
music_publisher
Django-Music-Publisher (DMP) is open source software for managing music metadata, registration/licencing of musical works and royalty processing.
music_publisher app is the only Django app in this project.
music_publisher.apps
Django app definition for music_publisher.
music_publisher.societies
Create society tuple and dict.
music_publisher.validators
CWR-compatibility field-level validation.
For formats that allow dashes and dots (ISWC, IPI Base), the actual format is from CWR 2.x specification: ISWC without and IPI Base with dashes.
- music_publisher.validators.check_ean_digit(ean)
EAN checksum validation.
- Parameters:
ean (str) – EAN
- Raises:
ValidationError –
- music_publisher.validators.check_iswc_digit(iswc, weight)
ISWC / IPI Base checksum validation.
- music_publisher.validators.check_ipi_digit(all_digits)
IPI Name checksum validation.
- Parameters:
all_digits (str) – IPI Name #
- Raises:
ValidationError –
- music_publisher.validators.check_isni_digit(all_digits)
ISNI checksum validation.
- Parameters:
all_digits (str) – ISNI
- Raises:
ValidationError –
- music_publisher.validators.check_dpid(dpid)
Calculate the checksum. A valid number should have a checksum of 1.
- class music_publisher.validators.CWRFieldValidator(*args, **kwargs)
Bases:
objectValidate fields for CWR compliance.
- deconstruct()
Return a 3-tuple of class import path, positional arguments, and keyword arguments.
- music_publisher.validators.validate_publisher_settings()
CWR-compliance validation for publisher settings.
- music_publisher.validators.validate_settings()
CWR-compliance validation for settings.
This is used to prevent deployment with invalid settings.
music_publisher.base
Contains base (abstract) classes used in models
- class music_publisher.base.NotesManager(*args, **kwargs)
Bases:
ManagerManager for objects inheriting from
NotesBase.Defers
NotesBase.notesfield.- get_queryset()
Defer
NotesBase.notesfield.
- class music_publisher.base.NotesBase(*args, **kwargs)
Bases:
ModelAbstract class for all classes that have notes.
- notes
Notes, free internal text field
- class music_publisher.base.DescriptionBase(*args, **kwargs)
Bases:
ModelAbstract class for all classes that have publicly visible descriptions.
- description
Public description
- class music_publisher.base.TitleBase(*args, **kwargs)
Bases:
ModelAbstract class for all classes that have a title.
- title
Title, used in work title, alternate title, etc.
- class music_publisher.base.PersonBase(*args, **kwargs)
Bases:
ModelBase class for all classes that contain people with first and last name.
This includes writers and artists. For bands, only the last name field is used.
- first_name
First Name
- last_name
Last Name
- class music_publisher.base.SocietyAffiliationBase(*args, **kwargs)
Bases:
ModelAbstract base for all objects with CMO affiliations
- pr_society
Performing Rights Society Code
- mr_society
Mechanical Rights Society Code
- sr_society
Sync. Rights Society Code
- class music_publisher.base.IPIBase(*args, **kwargs)
Bases:
ModelAbstract base for all objects containing IPI numbers.
- ipi_base
IPI Base Number
- ipi_name
IPI Name Number
- _can_be_controlled
used to determine if there is enough data for a writer to be controlled.
- clean_fields(*args, **kwargs)
Data cleanup, allowing various import formats to be converted into consistently formatted data.
- class music_publisher.base.IPIWithGeneralAgreementBase(*args, **kwargs)
Bases:
IPIBase,SocietyAffiliationBaseAbstract base for all objects with general agreements.
- saan
Society-assigned agreement number, in this context it is used for general agreements, for specific agreements use
models.WriterInWork.saan.
- generally_controlled
flags if a writer is generally controlled (in all works)
- publisher_fee
this field is used in calculating publishing fees
- clean()
Clean the data and validate.
- clean_fields(*args, **kwargs)
Data cleanup, allowing various import formats to be converted into consistently formatted data.
- class music_publisher.base.AccountNumberBase(*args, **kwargs)
Bases:
ModelAbstract base for all objects with an account number.
- account_number
account number, used for royalty processing
- clean_fields(*args, **kwargs)
Account Number cleanup
- class music_publisher.base.ArtistBase(*args, **kwargs)
Bases:
PersonBase,NotesBase,DescriptionBasePerforming artist base class.
- isni
International Standard Name Id
- clean_fields(*args, **kwargs)
ISNI cleanup
- class music_publisher.base.WriterBase(*args, **kwargs)
Bases:
PersonBase,IPIWithGeneralAgreementBase,NotesBase,DescriptionBase,AccountNumberBaseBase class for writers.
- class music_publisher.base.LabelBase(*args, **kwargs)
Bases:
NotesBase,DescriptionBaseMusic Label base class.
- name
Label Name
- class music_publisher.base.LibraryBase(*args, **kwargs)
Bases:
ModelMusic Library base class.
- name
Library Name
music_publisher.models
Concrete models.
They mostly inherit from classes in base.
- class music_publisher.models.Artist(*args, **kwargs)
Bases:
ArtistBasePerforming artist.
- get_dict()
Get the object in an internal dictionary format
- Returns:
internal dict format
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Label(*args, **kwargs)
Bases:
LabelBaseMusic Label.
- get_dict()
Get the object in an internal dictionary format
- Returns:
internal dict format
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Library(*args, **kwargs)
Bases:
LibraryBaseMusic Library.
- get_dict()
Get the object in an internal dictionary format
- Returns:
internal dict format
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Release(*args, **kwargs)
Bases:
ReleaseBaseMusic Release (album / other product)
- library
Foreign key to
models.Library
- release_label
Foreign key to
models.Label
- recordings
M2M to
models.Recordingthroughmodels.Track
- get_dict(with_tracks=False)
Get the object in an internal dictionary format
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.LibraryReleaseManager(*args, **kwargs)
Bases:
ManagerManager for a proxy class
models.LibraryRelease- get_queryset()
Return only library releases
- Returns:
Queryset with instances of
models.LibraryRelease- Return type:
- get_dict(qs)
Get the object in an internal dictionary format
- Parameters:
- Returns:
internal dict format
- Return type:
- class music_publisher.models.LibraryRelease(*args, **kwargs)
Bases:
ReleaseProxy class for Library Releases (AKA Library CDs)
- objects
Database Manager
- Type:
- clean()
Make sure that release title is required if one of the other “non-library” fields is present.
- Raises:
ValidationError – If not compliant.
- get_origin_dict()
Get the object in an internal dictionary format.
This is used for work origin, not release data.
- Returns:
internal dict format
- Return type:
- exception DoesNotExist
Bases:
DoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.CommercialReleaseManager(*args, **kwargs)
Bases:
ManagerManager for a proxy class
models.CommercialRelease- get_queryset()
Return only commercial releases
- Returns:
Queryset with instances of
models.CommercialRelease- Return type:
- get_dict(qs)
Get the object in an internal dictionary format
- Parameters:
- Returns:
internal dict format
- Return type:
- class music_publisher.models.CommercialRelease(*args, **kwargs)
Bases:
ReleaseProxy class for Commercial Releases
- objects
Database Manager
- Type:
- exception DoesNotExist
Bases:
DoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.PlaylistManager(*args, **kwargs)
Bases:
ManagerManager for a proxy class
models.Playlist- get_queryset()
Return only commercial releases
- Returns:
Queryset with instances of
models.CommercialRelease- Return type:
- get_dict(qs)
Get the object in an internal dictionary format
- Parameters:
- Returns:
internal dict format
- Return type:
- class music_publisher.models.Playlist(*args, **kwargs)
Bases:
ReleaseProxy class for Playlists
- objects
Database Manager
- Type:
- clean(*args, **kwargs)
Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
- exception DoesNotExist
Bases:
DoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Writer(*args, **kwargs)
Bases:
WriterBaseWriters.
- original_publishing_agreement
Foreign key to
models.OriginalPublishingAgreement
- clean(*args, **kwargs)
Check if writer who is controlled still has enough data.
- get_dict()
Create a data structure that can be serialized as JSON.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.WorkManager(*args, **kwargs)
Bases:
ManagerManager for class
models.Work- get_queryset()
Get an optimized queryset.
- Returns:
Queryset with instances of
models.Work- Return type:
- get_dict_items(qs)
Yield dictionary items for works from the queryset
- Parameters:
qs (django.db.models.query import QuerySet)
- Returns:
dictionary with works
- Return type:
- class music_publisher.models.Work(*args, **kwargs)
Bases:
TitleBaseConcrete class, with references to foreign objects.
- _work_id
permanent work id, either imported or fixed when exports are created
- iswc
ISWC
- original_title
title of the original work, implies modified work
- release_label
Foreign key to
models.LibraryRelease
- last_change
when the last change was made to this object or any of the child objects, basically used in filtering
- artists
Artists performing the work
- writers
Writers who created the work
- objects
Database Manager
- Type:
- is_modification()
Check if the work is a modification.
- Returns:
True if modification, False if original
- Return type:
- clean_fields(*args, **kwargs)
Deal with various ways ISWC is written.
- static get_publisher_dict()
Create data structure for the publisher.
- Returns:
JSON-serializable data structure
- Return type:
- get_dict(with_recordings=True)
Create a data structure that can be serialized as JSON.
Normalize the structure if required.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.AlternateTitle(*args, **kwargs)
Bases:
TitleBaseConcrete class for alternate titles.
- work
Foreign key to Work model
- suffix
implies that the title should be appended to the work title
- get_dict()
Create a data structure that can be serialized as JSON.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.ArtistInWork(*args, **kwargs)
Bases:
ModelArtist performing the work (live in CWR 3).
- artist
FK to Artist
- work
FK to Work
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.WriterInWork(*args, **kwargs)
Bases:
ModelWriters who created this work.
At least one writer in work must be controlled. Sum of relative shares must be (roughly) 100%. Capacity is limited to roles for original writers.
- work
FK to Work
- writer
FK to Writer
- saan
Society-assigned agreement number between the writer and the original publisher, please note that this field is for SPECIFIC agreements, for a general agreement, use
base.IPIBase.saan
- controlled
A complete mistery field
Initial split among writers, prior to publishing
- capacity
Role of the writer in this work
- publisher_fee
Percentage of royalties kept by publisher
- clean_fields(*args, **kwargs)
Turn SAAN into uppercase.
- Parameters:
*args – passing through
**kwargs – passing through
- Returns:
SAAN in uppercase
- Return type:
- clean()
Make sure that controlled writers have all the required data.
Also check that writers that are not controlled do not have data that can not apply to them.
- get_agreement_dict()
Get agreement dictionary for this writer in work.
- get_dict()
Create a data structure that can be serialized as JSON.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Recording(*args, **kwargs)
Bases:
ModelRecording.
- release_date
Recording Release Date
- duration
Recording Duration
- isrc
International Standard Recording Code
- record_label
Record Label
- clean_fields(*args, **kwargs)
ISRC cleaning, just removing dots and dashes.
- Parameters:
*args – may be used in upstream
**kwargs – may be used in upstream
- Returns:
return from
django.db.models.Model.clean_fields()
- property complete_recording_title
Return complete recording title.
- Returns:
str
- property complete_version_title
Return complete version title.
- Returns:
str
- property title
Generate title from various fields.
- property recording_id
Create Recording ID used in registrations
- Returns:
Internal Recording ID
- Return type:
- get_dict(with_releases=False, with_work=True)
Create a data structure that can be serialized as JSON.
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.Track(*args, **kwargs)
Bases:
ModelTrack, a recording on a release.
- recording
Recording
- release
Release
- cut_number
Cut Number
- get_dict()
Create a data structure that can be serialized as JSON.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.DeferCwrManager(*args, **kwargs)
Bases:
ManagerManager for CWR Exports and ACK Imports.
Defers
CWRExport.cwrandAckImport.cwrfields.- get_queryset()
Return a new QuerySet object. Subclasses can override this method to customize the behavior of the Manager.
- class music_publisher.models.CWRExport(*args, **kwargs)
Bases:
ModelExport in CWR format.
Common Works Registration format is a standard format for registration of musical works world-wide. Exports are available in CWR 2.1 revision 8 and CWR 3.0 (experimental).
- nwr_rev
choice field where user can select which version and type of CWR it is
- cwr
contents of CWR file
- year
2-digit year format
- num_in_year
CWR sequential number in a year
- works
included works
- description
internal note
- property version
Return CWR version.
- property filename3
Return proper CWR 3.x filename.
Format is: CWYYnnnnSUB_REP_VM - m - r.EXT
- Returns:
CWR file name
- Return type:
- get_record(key, record)
Create CWR record (row) from the key and dict.
- get_transaction_record(key, record)
Create CWR transaction record (row) from the key and dict.
This methods adds transaction and record sequences.
- yield_iswc_request_lines(works)
Yield lines for an ISR (ISWC request) in CWR 3.x
- yield_publisher_lines(publisher, controlled_relative_share)
Yield SPU/SPT lines.
- Parameters:
publisher (dict) – dictionary with publisher data
controlled_relative_share (Decimal) – sum of manuscript shares for controlled writers
- Yields:
str – CWR record (row/line)
- yield_registration_lines(works)
Yield lines for CWR registrations (WRK in 3.x, NWR and REV in 2.x)
- Parameters:
works (list) – list of work dicts
- Yields:
str – CWR record (row/line)
- get_party_lines(work)
Yield SPU, SPT, OPU, SWR, SWT, OPT and PWR lines
- Parameters:
work – musical work
- Yields:
str – CWR record (row/line)
- get_other_lines(work)
Yield ALT and subsequent lines
- Parameters:
work – musical work
- Yields:
str – CWR record (row/line)
- get_header()
Construct CWR HDR record.
- yield_lines(works)
Yield CWR transaction records (rows/lines) for works
- Parameters:
works (query) –
models.Workquery- Yields:
str – CWR record (row/line)
- static chunked(items, size)
Yield chunks from
itemswith at mostsizeitems.
- should_create_synchronously()
Return whether this export should be generated on save.
- create_cwr_files(publisher_code=None)
Create one or more CWR files from this export request.
Large requests are split into multiple CWRExport objects, each with at most
OPTION_CWR_WORKS_PER_FILEworks. If this export already fits into one file, it is generated directly and returned as the only item.
- create_cwr(publisher_code=None, generate=True)
Create CWR and save.
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.WorkAcknowledgement(*args, **kwargs)
Bases:
ModelAcknowledgement of work registration.
- date
Acknowledgement date
- remote_work_id
Remote work ID
- society_code
3-digit society code
- status
2-letter status code
- work
FK to Work
- get_dict()
Return dictionary with external work IDs.
- Returns:
JSON-serializable data structure
- Return type:
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.ACKImport(*args, **kwargs)
Bases:
ModelCWR acknowledgement file import.
- filename
Description
- society_code
3-digit society code, please note that
choicesis not set.- Type:
models.CharField
- society_name
Society name, used if society code is missing.
- Type:
models.CharField
- date
Acknowledgement date
- report
Basically a log
- cwr
contents of CWR file
- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- class music_publisher.models.DataImport(*args, **kwargs)
Bases:
ModelImporting basic work data from a CSV file.
This class just acts as log, the actual logic is in
data_import.- exception DoesNotExist
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- music_publisher.models.smart_str_conversion(value)
Convert to Title Case only if UPPER CASE.
- music_publisher.models.change_case(sender, instance, **kwargs)
Change case of CharFields from
music_publisher.
music_publisher.cwr_templates
Django old_templates for CWR generation.
- music_publisher.cwr_templates.TEMPLATES_22
Record old_templates for CWR 2.2, based on 2.1
- Type:
music_publisher.forms
Forms and formsets.
- class music_publisher.forms.LibraryReleaseForm(*args, **kwargs)
Bases:
ModelFormCustom form for
models.LibraryRelease.- property media
Return all media required to render the widgets on this form.
- class music_publisher.forms.PlaylistForm(*args, **kwargs)
Bases:
ModelFormCustom form for
models.LibraryRelease.- property media
Return all media required to render the widgets on this form.
- class music_publisher.forms.AlternateTitleFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)
Bases:
BaseInlineFormSetFormset for
AlternateTitleInline.- clean()
- Performs these checks:
if suffix is used, then validates the total length
- Returns:
None
- Raises:
ValidationError –
- class music_publisher.forms.WorkForm(*args, **kwargs)
Bases:
ModelFormCustom form for
models.Work.Calculate values for readonly field version_type.
- property media
Return all media required to render the widgets on this form.
- class music_publisher.forms.ACKImportForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)
Bases:
ModelFormForm used for CWR acknowledgement imports.
- acknowledgement_file
Field for file upload
- Type:
FileField
- clean()
Perform usual clean, then process the file, returning the content field as if it was the TextField.
- property media
Return all media required to render the widgets on this form.
- class music_publisher.forms.WriterInWorkFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)
Bases:
BaseInlineFormSetFormset for
WriterInWorkInline.- clean()
- Performs these checks:
at least one writer must be controlled, at least one writer music be Composer or Composer&Lyricist sum of relative shares must be ~100% for original works, only allowed capacities may be used for modified works, at least one writer must have an extended capacity
- Returns:
None
- Raises:
ValidationError –
- class music_publisher.forms.DataImportForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)
Bases:
ModelFormForm used for data imports.
- data_file
Field for file upload
- Type:
FileField
- clean()
This is the actual import process, if all goes well, the report is saved.
- Raises:
ValidationError –
- property media
Return all media required to render the widgets on this form.
music_publisher.admin
Main interface for music_publisher.
All views are here, except for royalty_calculation.
- class music_publisher.admin.ImageWidget(attrs=None)
Bases:
ClearableFileInput
- class music_publisher.admin.AudioPlayerWidget(attrs=None)
Bases:
ClearableFileInput
- class music_publisher.admin.MusicPublisherAdmin(model, admin_site)
Bases:
ModelAdminParent class to all admin classes.
- class music_publisher.admin.ArtistInWorkInline(parent_model, admin_site)
Bases:
TabularInlineInline interface for
models.ArtistInWork.- model
alias of
ArtistInWork
- class music_publisher.admin.RecordingInline(parent_model, admin_site)
Bases:
StackedInlineInline interface for
models.Recording, used inWorkAdmin.- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- class music_publisher.admin.ArtistAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Artist.- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- last_or_band(obj)
Placeholder for
models.Artist.last_name.
- actions = None
- save_model(request, obj, form, *args, **kwargs)
Save, then update
last_changeof the works whose CWR registration changes due to this change.
- get_queryset(request)
Optimized queryset for changelist view.
- work_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- recording_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- class music_publisher.admin.LabelAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Label.- actions = None
- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- get_queryset(request)
Optimized queryset for changelist view.
- commercialrelease_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- libraryrelease_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- recording_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- save_model(request, obj, form, *args, **kwargs)
Save, then update
last_changeof the corresponding works.
- class music_publisher.admin.LibraryAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Library.- actions = None
- get_queryset(request)
Optimized queryset for changelist view.
- libraryrelease_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- work_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- save_model(request, obj, form, *args, **kwargs)
Save, then update
last_changeof the corresponding works.
- class music_publisher.admin.TrackInline(parent_model, admin_site)
Bases:
TabularInlineInline interface for
models.Track, used inLibraryReleaseAdminandCommercialReleaseAdmin.
- class music_publisher.admin.PlaylistTrackInline(parent_model, admin_site)
Bases:
TrackInline
- class music_publisher.admin.ReleaseAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Release.- actions = None
- has_module_permission(request)
Return False
- has_add_permission(request)
Return False
- has_change_permission(request, obj=None)
Return False
- has_delete_permission(request, obj=None)
Return False
- class music_publisher.admin.LibraryReleaseAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.LibraryRelease.- form
alias of
LibraryReleaseForm
- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- get_inline_instances(request, obj=None)
Limit inlines in popups.
- save_model(request, obj, form, *args, **kwargs)
Save, then update
last_changeof the corresponding works.
- get_queryset(request)
Optimized queryset for changelist view.
- work_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- track_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- create_json(request, qs)
Batch action that downloads a JSON file containing library releases.
- Returns:
JSON file with selected works
- Return type:
JsonResponse
- get_actions(request)
Custom action disabling the default
delete_selected.
- class music_publisher.admin.PlaylistAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Playlist.- form
alias of
PlaylistForm
- get_inline_instances(request, obj=None)
Limit inlines in popups.
- get_queryset(request)
Optimized queryset for changelist view.
- track_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- class music_publisher.admin.CommercialReleaseAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.CommercialRelease.- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- get_inline_instances(request, obj=None)
Limit inlines in popups.
- get_queryset(request)
Optimized queryset for changelist view.
- track_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- create_json(request, qs)
Batch action that downloads a JSON file containing commercial releases.
- Returns:
JSON file with selected commercial releases
- Return type:
JsonResponse
- get_actions(request)
Custom action disabling the default
delete_selected.
- class music_publisher.admin.WriterAdmin(model, admin_site)
Bases:
MusicPublisherAdminInterface for
models.Writer.- get_fieldsets(request, obj=None)
Return the fieldsets.
Depending on settings, MR and PR affiliations may not be needed. See
WriterAdmin.get_society_list()
- actions = None
- static get_society_list()
List which society fields are required.
Mechanical and Sync affiliation is not required if writers don’t collect any of it, which is the most usual case.
- save_model(request, obj, form, *args, **kwargs)
Perform normal save_model, then update last_change of all connected works.
- get_queryset(request)
Optimized queryset for changelist view.
- work_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- class music_publisher.admin.AlternateTitleInline(parent_model, admin_site)
Bases:
TabularInlineInline interface for
models.AlternateTitle.- model
alias of
AlternateTitle
- formset
alias of
AlternateTitleFormSet
- complete_alt_title(obj)
Return the complete title, see
models.AlternateTitle.__str__()
- class music_publisher.admin.WriterInWorkInline(parent_model, admin_site)
Bases:
TabularInlineInline interface for
models.WriterInWork.- model
alias of
WriterInWork
- formset
alias of
WriterInWorkFormSet
- class music_publisher.admin.WorkAcknowledgementInline(parent_model, admin_site)
Bases:
TabularInlineInline interface for
models.WorkAcknowledgement, used inWorkAdmin.Note that normal users should only have a ‘view’ permission.
- model
alias of
WorkAcknowledgement
- class music_publisher.admin.WorkAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Work.This is by far the most important part of the interface.
- actions
batch actions used:
create_cwr(),create_json()- Type:
- inlines
inlines used in change view:
AlternateTitleInline,WriterInWorkInline,RecordingInline,ArtistInWorkInline,WorkAcknowledgementInline,- Type:
- writer_last_names(obj)
This is a standard way how writers are shown in other apps.
- percentage_controlled(obj)
Controlled percentage (sum of relative shares for controlled writers)
Please note that writers in work are already included in the queryset for other reasons, so no overhead except summing.
- work_id(obj)
Return
models.Work.work_id, make it sortable.
- cwr_export_count(obj)
Return the count of CWR exports with the link to the filtered changelist view for
CWRExportAdmin.
- recording_count(obj)
Return the count of CWR exports with the link to the filtered changelist view for
CWRExportAdmin.
- get_queryset(request)
Optimized queryset for changelist view.
- class InCWRListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter if work is included in any of CWR files.
- lookups(request, model_admin)
Simple Yes/No filter
- queryset(request, queryset)
Filter if in any of CWR files.
- class ACKSocietyListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter of societies from ACK files.
- lookups(request, model_admin)
Simple Yes/No filter
- queryset(request, queryset)
Filter on society sending ACKs.
- class ACKStatusListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter on ACK status.
- lookups(request, model_admin)
Simple Yes/No filter
- queryset(request, qs)
Filter on ACK status.
- class HasISWCListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter on the presence of ISWC.
- lookups(request, model_admin)
Simple Yes/No filter
- class HasRecordingListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter on the presence of recordings.
- lookups(request, model_admin)
Simple Yes/No filter
- queryset(request, queryset)
Filter on presence of
models.Recording.
- get_search_results(request, queryset, search_term)
Deal with the situation term is work ID.
- save_model(request, obj, form, *args, **kwargs)
Set last_change if the work form has changed.
- save_formset(request, form, formset, change)
Set last_change for the work if any of the inline forms has changed.
- create_cwr(request, qs)
Batch action that redirects to the add view for
CWRExportAdminwith selected works.
- create_json(request, qs)
Batch action that downloads a JSON file containing selected works.
- Returns:
JSON file with selected works
- Return type:
JsonResponse
- get_labels_for_csv(works, repeating_column_nr=0, simple=False)
Return the list of labels for the CSV file.
- get_rows_for_csv(works)
Return rows for the CSV file, including the header.
- create_csv(request, qs)
Batch action that downloads a CSV file containing selected works.
- Returns:
JSON file with selected works
- Return type:
JsonResponse
- get_actions(request)
Custom action disabling the default
delete_selected.
- get_inline_instances(request, obj=None)
Limit inlines in popups.
- class music_publisher.admin.RecordingAdmin(model, admin_site)
Bases:
MusicPublisherAdminAdmin interface for
models.Recording.- actions = None
- class HasISRCListFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter on the presence of ISRC.
- lookups(request, model_admin)
Simple Yes/No filter
- class HasAudioFilter(request, params, model, model_admin)
Bases:
SimpleListFilterCustom list filter on the presence of audio file.
- lookups(request, model_admin)
Simple Yes/No filter
- get_fieldsets(request, obj=None)
Hook for specifying fieldsets.
- get_queryset(request)
Optimized query regarding work name
- recording_id(obj)
Return
models.Recording.recording_id, make it sortable.
- title(obj)
Return the recording title, which is not the necessarily the title field.
- work_link(obj)
Link to the work the recording is based on.
- artist_link(obj)
Link to the recording artist.
- label_link(obj)
Link to the recording label.
- class music_publisher.admin.CWRExportAdmin(model, admin_site)
Bases:
ModelAdminAdmin interface for
models.CWRExport.- actions = None
- work_count(obj)
Return the work count from the database field, or count them. (dealing with legacy)
- get_preview(obj)
Get CWR preview.
If you are using highlighing, then override this method.
- view_link(obj)
Link to the CWR preview.
- download_link(obj)
Link for downloading or creating CWR file.
- get_queryset(request)
Optimized query with count of works in the export.
- get_readonly_fields(request, obj=None)
Read-only fields differ if CWR has been completed.
- get_fields(request, obj=None)
Shown fields differ if CWR has been completed.
- has_add_permission(request)
Return false if CWR delivery code is not present.
- has_delete_permission(request, obj=None)
If CWR has been created, it can no longer be deleted, as it may have been sent. This may change once the delivery is automated.
- has_change_permission(request, obj=None)
If object exists, it can only be edited in changelist.
- get_form(request, obj=None, **kwargs)
Set initial values for work IDs.
- add_view(request, form_url='', extra_context=None, work_ids=None)
Added work_ids as default for wizard from
WorkAdmin.create_cwr().
- change_view(request, object_id, form_url='', extra_context=None)
Normal change view with sub-views defined by GET parameters:
- Parameters:
preview – that returns the preview of CWR file,
download – that downloads the CWR file,
create_cwr – that creates the CWR file.
save_model()passes the main object, which is needed to fetch CWR from the external service, but only after related objects are saved.
- class music_publisher.admin.AdminWithReport(model, admin_site)
Bases:
ModelAdminThe parent class for all admin classes with a report field.
- print_report(obj)
Mark report as HTML-safe.
- class music_publisher.admin.ACKImportAdmin(model, admin_site)
Bases:
AdminWithReportAdmin interface for
models.ACKImport.- get_form(request, obj=None, **kwargs)
Returns a custom form for new objects, default one for changes.
- get_fields(request, obj=None)
Return different fields for add vs change.
- process(request, ack_import, file_content, import_iswcs=False)
Create appropriate WorkAcknowledgement objects, without duplicates.
Big part of this code should be moved to the model, left here because messaging is simpler.
- save_model(request, obj, form, change)
Custom save_model, it ignores changes, validates the form for new instances, if valid, it processes the file and, upon success, calls
super().save_model.
- has_add_permission(request)
Return false if CWR delivery code is not present.
- has_delete_permission(request, obj=None, *args, **kwargs)
Deleting ACK imports is a really bad idea.
- has_change_permission(request, obj=None)
Deleting this would make no sense, since the data is processed.
- get_preview(obj)
Get CWR preview.
If you are using highlighing, then override this method.
- view_link(obj)
Link to CWR ACK preview.
- change_view(request, object_id, form_url='', extra_context=None)
Normal change view with a sub-view defined by GET parameters:
- Parameters:
preview – that returns the preview of CWR file.
- class music_publisher.admin.DataImportAdmin(model, admin_site)
Bases:
AdminWithReportData import from CSV files.
Only the interface is here, the whole logic is in
data_import.- form
alias of
DataImportForm
- get_fields(request, obj=None)
Return different fields for add vs change.
- has_delete_permission(request, obj=None, *args, **kwargs)
Deleting data imports is a really bad idea.
- has_change_permission(request, obj=None)
Deleting this would make no sense, since the data is processed.
- get_form(request, obj=None, change=False, **kwargs)
Return a Form class for use in the admin add view. This is used by add_view and change_view.
- save_model(request, obj, form, change)
Custom save_model, it ignores changes, validates the form for new instances, if valid, it processes the file and, upon success, calls
super().save_model.
music_publisher.data_import
All the code related to importing data from external files.
Currently, only works (with writers, artists, library data and ISRCs) are imported. (ISRCs will be used for importing recording data the in future.)
music_publisher.royalty_calculation
This module is about processing royalty statements.
It processes files in the request-response cycle, not in background workers. Therefore, focus is on speed. Nothing is written to the database, and SELECTs are optimised and performed in one batch.
- music_publisher.royalty_calculation.get_id_sources()
Yield choices, fixed and societies.
- music_publisher.royalty_calculation.get_right_types()
Yield fixed options.
They will be extended with columns in JS and prior to validation.
- class music_publisher.royalty_calculation.RoyaltyCalculationForm(*args, **kwargs)
Bases:
FormThe form for royalty calculations.
- is_valid()
Append additional choices to various fields, prior to the actual validation.
- property media
Return all media required to render the widgets on this form.
- class music_publisher.royalty_calculation.RoyaltyCalculation(form)
Bases:
objectThe process of royalty calculation.
- property filename
Return the filename of the output file.
- property fieldnames
Return the list of field names in the output file.
- get_work_ids()
Find work unambiguous work identifiers.
- Returns:
set of work identifier from the file
- get_work_queryset(work_ids)
Return the appropriate queryset based on work ID source and ids.
- Returns:
queryset with
models.WriterInWorkobjects.query_idhas the matched field value.
- generate_works_dict(qs)
Generate the works cache.
- Returns:
dict (works) of lists (writerinwork) of dicts
- generate_writer_dict()
Generate the writers cache. :returns: dict (writer) of dicts
- get_works_and_writers()
Get work and writer data.
Extract all work IDs, then perform the queries and put them in dictionaries. When the actual file processing happens, no further queries are required.
- process_row(row)
Process one incoming row, yield multiple output rows.
- property out_file_path
This method creates the output file and outputs the temporary path.
Note that the process happens is several passes.
- class music_publisher.royalty_calculation.RoyaltyCalculationView(**kwargs)
Bases:
PermissionRequiredMixin,FormViewThe view for royalty calculations.
- form_class
alias of
RoyaltyCalculationForm
- render_to_response(context, **response_kwargs)
Prepare the context, required since we use admin template.
- dispatch(request, *args, **kwargs)
Royalty processing works only with TemporaryFileUploadHandler.
- form_valid(form)
This is where the magic happens.
music_publisher.tests
Tests for music_publisher.
The folder includes these files:
CW200001DMP_000.V21 - CWR 2.1 registration file
CW200002DMP_0000_V3-0-0.SUB - CWR 3.0 registration file
CW200003DMP_0000_V3-0-0.ISR - CWR3.0 ISWC request file
CW200001052_DMP.V21 - CWR 2.1 acknowledgement file
dataimport.csv - used for data imports
royaltystatement.csv - CSV royalty statement
royaltystatement_200k_rows.csv - CSV royalty statement with 200.000 rows, used for load testing.
Actual tests are in music_publisher.tests.tests.
music_publisher.tests.tests
Tests for music_publisher.
This software has almost full test coverage. The only exceptions are
instances of Exception being caught during data imports.
(User idiocy is boundless.)
Most of the tests are functional end-to-end tests. While they test that code works, they don’t always test that it works as expected.
Still, it must be noted that exports are tested against provided templates (made in a different software, not using the same code beyond Python standard library).
More precise tests would be better.
- music_publisher.tests.tests.get_data_from_response(response)
Helper for extracting data from HTTP response in a way that can be fed back into POST that works with Django Admin.
- class music_publisher.tests.tests.DataImportTest(methodName='runTest')
Bases:
TestCaseFunctional test for data import from CSV files.
- classmethod setUpClass()
Hook method for setting up class fixture before running tests in the class.
- test_log()
Test logging during import.
- test_unknown_key_exceptions()
Test exceptions not tested in functional tests.
- class music_publisher.tests.tests.AdminTest(methodName='runTest')
Bases:
TestCaseFunctional tests on the interface, and several related unit tests.
Note that tests build one atop another, simulating typical work flow.
- classmethod create_original_work()
Create original work, three writers, one controlled, with recording, alternate titles, included in a commercial release.
- classmethod create_modified_work()
Create modified work, original writer plus arranger, with recording, alternate titles.
- classmethod create_copublished_work()
Create work, two writers, one co-published
- classmethod create_duplicate_work()
Create work, two writers, one co-published, duplicate.
- classmethod create_writers()
Create four writers with different properties.
- classmethod create_cwr2_export()
Create a NWR and a REV CWR2 Export.
- classmethod create_cwr3_export()
Create a WRK and an ISR CWR3 Export.
- classmethod create_work_acknowledgements()
Create work acknowledgements.
- classmethod setUpClass()
Class setup.
Creating users. Creating instances of classes of less importance:
label,
library,
artist,
releases,
then calling the methods above.
- test_strings()
Test __str__ methods for created objects.
- test_unknown_user()
Several fast test to make sure that an unregistered user is blind.
- test_super_user()
Testing index for superuser covers all the cases.
- test_super_user_with_files()
Testing index for superuser covers all the cases.
- test_staff_user()
Test that a staff user can access some urls.
Please note that most of the work is in other tests.
- test_staff_user_with_files()
Testing index for superuser covers all the cases.
- test_cwr_previews()
Test that CWR preview works.
- test_cwr_downloads()
Test that the CWR file can be downloaded.
- test_json()
Test that JSON export works.
- test_cwr_nwr()
Test that small CWR export is generated synchronously.
- test_large_cwr_is_not_generated_synchronously()
CWR exports with 5,000 or more works are saved without CWR text.
- test_pending_cwr_export_shows_create_cwr_link()
Pending CWR exports show Create CWR instead of Download.
- test_create_cwr_link_generates_pending_export()
Create CWR link generates CWR for a pending export.
- test_large_cwr_is_split_into_multiple_exports()
Large CWR requests are split into files of up to 10,000 works.
- test_large_cwr_split_keeps_single_file_for_10000_works()
Exactly 10,000 works still produce one CWR file.
- test_csv()
Test that CSV export works.
- test_label_change()
Test that
models.Labelobjects can be edited.
- test_library_change()
Test that
models.Libraryobjects can be edited.
- test_library_change_2()
Test that
models.Libraryobjects can be edited.
- test_artist_change()
Test that
models.Artistobjects can be edited.
- test_commercialrelease_change()
Test that
models.CommercialReleasecan be edited.
- test_libraryrelease_change()
Test that
models.LibraryReleasecan be edited.
- test_audit_user()
Test that audit user can see, but not change things.
- test_generally_controlled_not_controlled()
Test that a controlled flag must be set for a writer who is generally controlled.
- test_missing_capacity()
Test that if controlled flag is set, the capacity must be set as well.
- test_controlled_but_no_writer()
Test that a line without a writer can not have controlled set.
- test_controlled_but_missing_data()
The requirements for a controlled writer are higher, make sure they are obeyed when setting a writer as controlled.
- test_writer_switch()
Just replace one writer with another, just to test last change
- test_not_controlled_extra_saan()
SAAN can not be set if a writer is not controlled.
- test_not_controlled_extra_fee()
Publisher fee can not be set if a writer is not controlled.
- test_bad_alt_title()
Test that alternate title can not have disallowed characters.
- test_unallowed_capacity()
Some capacieties are allowed only in modifications.
- test_extended_capacity()
At least one of the additional capacieties must be set for modifications.
- test_none_controlled()
At least one Writer in Work line must be set as controlled.
Sum of shares must be (roughly) 100%
- test_altitle_sufix_too_long()
A suffix plus the base title plus one space in between must be 60 characters or less.
- test_ack_import_and_work_filters()
Test acknowledgement import and then filters on the change view, as well as other related views.
These tests must be together, ack import is used in filters.
- test_data_import_and_royalty_calculations()
Test data import, ack import and royalty calculations.
This is the normal process, work data is entered, then the registration follows and then it can be processed in royalty statements.
This test also includes load testing, 200.000 rows must be imported in under 10-15 seconds, performed 4 times with different algos and ID types.
- test_bad_data_import()
Test bad data import.
- test_recording_filters()
Test Work changelist filters.
- test_search()
Test Work search.
- test_simple_save()
Test saving changed Work form.
- test_create_cwr_wizard()
Test if CWR creation action works as it should.
- test_create_cwr_wizard_no_publisher_code()
Publisher code is required for CWR generation, it must fail if attempted otherwise.
- class music_publisher.tests.tests.CWRTemplatesTest(methodName='runTest')
Bases:
SimpleTestCaseA test related to CWR Templates.
- test_templates()
Test CWR 2.1, 2.2 and 3.0 generation with empty values.
- class music_publisher.tests.tests.ValidatorsTest(methodName='runTest')
Bases:
TestCaseTest all validators.
Note that validators are also validating settings.
- class music_publisher.tests.tests.ModelsSimpleTest(methodName='runTest')
Bases:
TransactionTestCaseThese tests are modifying objects directly.
- test_work()
A complex test where a complete Work objects with all related objects is created.
- class music_publisher.tests.tests.OtherFunctionalTest(methodName='runTest')
Bases:
SimpleTestCaseThese tests are testing things not tested otherwise.