from django.db import models
import cremquery as query
-class MediaCore(object):
+class ModelCore(models.Model):
+
+ @classmethod
+ def required_fields(cls):
+ required = []
+ for field in cls._meta.fields:
+ if (field != cls._meta.pk and field.default == models.fields.NOT_PROVIDED and
+ not field.null and not getattr(field, 'auto_now_add', False)):
+ required.append(field)
+ return required
+
+ def save(self, force_insert=False, force_update=False, using=None):
+ required = self.required_fields()
+ for field in required:
+ if not getattr(self, field.name):
+ raise RequiredFieldError(self, field)
+ super(ModelCore, self).save(force_insert, force_update, using)
+
+ class Meta:
+ abstract = True
+
+class MediaCore(ModelCore):
"Base class of all media objects"
def to_dict(self):
return False
is_well_formed_id = classmethod(is_well_formed_id)
+ class Meta:
+ abstract = True
+
class MetaCore:
app_label = 'telemeta'
-class MediaCollection(models.Model):
+class MediaCollection(MediaCore):
"Describe a collection of items"
PUBLIC_ACCESS_CHOICES = (('none', 'none'), ('metadata', 'metadata'), ('metadata', 'full'))
reference = models.CharField(unique=True, max_length=250,
null=True)
physical_format = models.ForeignKey('PhysicalFormat', related_name="collections",
- null=True)
- old_code = models.CharField(unique=True, max_length=250)
+ null=True, default=None)
+ old_code = models.CharField(unique=True, max_length=250, null=True)
code = models.CharField(unique=True, max_length=250)
title = models.CharField(max_length=250)
alt_title = models.CharField(max_length=250, default="")
recorded_to_year = models.IntegerField(default=0)
recording_context = models.ForeignKey('RecordingContext', related_name="collections",
null=True)
- approx_duration = models.TimeField(default=0)
+ approx_duration = models.TimeField(default='00:00')
doctype_code = models.IntegerField(default=0)
travail = models.CharField(max_length=250, default="")
state = models.TextField(default="")
def __unicode__(self):
return self.code
- def save(self, force_insert=False, force_update=False):
+ def save(self, force_insert=False, force_update=False, using=None):
raise MissingUserError("save() method disabled, use save_by_user()")
- def save_by_user(self, user, force_insert=False, force_update=False):
+ def save_by_user(self, user, force_insert=False, force_update=False, using=None):
"Save a collection and add a revision"
- super(MediaCollection, self).save(force_insert, force_update)
+ super(MediaCollection, self).save(force_insert, force_update, using)
Revision(element_type='collection', element_id=self.id, user=user).touch()
class Meta(MetaCore):
db_table = 'media_collections'
-class MediaItem(models.Model):
+class MediaItem(MediaCore):
"Describe an item"
PUBLIC_ACCESS_CHOICES = (('none', 'none'), ('metadata', 'metadata'), ('full', 'full'))
collection = models.ForeignKey('MediaCollection', related_name="items")
track = models.CharField(max_length=250, default="")
- old_code = models.CharField(unique=True, max_length=250)
+ old_code = models.CharField(unique=True, max_length=250, null=True)
code = models.CharField(unique=True, max_length=250, null=True)
- approx_duration = models.TimeField(default=0)
+ approx_duration = models.TimeField(default='00:00')
recorded_from_date = models.DateField(default=0)
recorded_to_date = models.DateField(default=0)
- location_name = models.ForeignKey('Location', related_name="items",
+ location = models.ForeignKey('Location', related_name="items",
db_column='location_name', null=True, default="")
location_comment = models.CharField(max_length=250, default="")
ethnic_group = models.ForeignKey('EthnicGroup', related_name="items",
super(MediaItem, self).save(force_insert, force_update)
Revision(element_type='item', element_id=self.id, user=user).touch()
-class MediaPart(models.Model):
+class MediaPart(MediaCore):
"Describe an item part"
item = models.ForeignKey('MediaItem', related_name="parts")
title = models.CharField(max_length=250)
def __unicode__(self):
return self.title
-class PhysicalFormat(models.Model):
+class PhysicalFormat(ModelCore):
"Collection physical format"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'physical_formats'
-class PublishingStatus(models.Model):
+class PublishingStatus(ModelCore):
"Collection publishing status"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'publishing_status'
-class AcquisitionMode(models.Model):
+class AcquisitionMode(ModelCore):
"Mode of acquisition of the collection"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'acquisition_modes'
-class MetadataAuthor(models.Model):
+class MetadataAuthor(ModelCore):
"Collection metadata author"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'metadata_authors'
-class MetadataWriter(models.Model):
+class MetadataWriter(ModelCore):
"Collection metadata writer"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'metadata_writers'
-class LegalRight(models.Model):
+class LegalRight(ModelCore):
"Collection legal rights"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'legal_rights'
-class RecordingContext(models.Model):
+class RecordingContext(ModelCore):
"Collection recording context"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'recording_contexts'
-class AdConversion(models.Model):
+class AdConversion(ModelCore):
"Collection digital to analog conversion status"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'ad_conversions'
-class VernacularStyle(models.Model):
+class VernacularStyle(ModelCore):
"Item vernacular style"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'vernacular_styles'
-class GenericStyle(models.Model):
+class GenericStyle(ModelCore):
"Item generic style"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'generic_styles'
-class Instrument(models.Model):
+class Instrument(ModelCore):
"Instrument used in the item"
name = models.CharField(max_length=250)
class Meta(MetaCore):
db_table = 'instruments'
-class InstrumentAlias(models.Model):
+class InstrumentAlias(ModelCore):
"Instrument other name"
name = models.CharField(max_length=250)
class Meta(MetaCore):
db_table = 'instrument_aliases'
-class InstrumentRelation(models.Model):
+class InstrumentRelation(ModelCore):
"Instrument family"
instrument = models.ForeignKey('Instrument', related_name="parent_relation")
parent_instrument = models.ForeignKey('Instrument', related_name="child_relation")
db_table = 'instrument_relations'
unique_together = (('instrument', 'parent_instrument'),)
-class InstrumentAliasRelation(models.Model):
+class InstrumentAliasRelation(ModelCore):
"Instrument family other name"
alias = models.ForeignKey('InstrumentAlias', related_name="other_name")
instrument = models.ForeignKey('InstrumentAlias', related_name="relation")
db_table = 'instrument_alias_relations'
unique_together = (('alias', 'instrument'),)
-class MediaItemPerformance(models.Model):
+class MediaItemPerformance(ModelCore):
"Item performance"
media_item = models.ForeignKey('MediaItem', related_name="performances")
instrument = models.ForeignKey('Instrument', related_name="performances",
class Meta(MetaCore):
db_table = 'media_item_performances'
-class User(models.Model):
+class User(ModelCore):
"Telemeta user"
LEVEL_CHOICES = (('user', 'user'), ('maintainer', 'maintainer'), ('admin', 'admin'))
class Meta(MetaCore):
db_table = 'users'
-class Playlist(models.Model):
+class Playlist(ModelCore):
"Item or collection playlist"
owner_username = models.ForeignKey('User', related_name="playlists", db_column="owner_username")
name = models.CharField(max_length=250)
class Meta(MetaCore):
db_table = 'playlists'
-class PlaylistResource(models.Model):
+class PlaylistResource(ModelCore):
"Playlist components"
RESOURCE_TYPE_CHOICES = (('item', 'item'), ('collection', 'collection'))
class Meta(MetaCore):
db_table = 'playlist_resources'
-class Location(models.Model):
+class Location(ModelCore):
"Item location"
TYPE_CHOICES = (('country', 'country'), ('continent', 'continent'), ('other', 'other'))
def __unicode__(self):
return self.name
-class LocationType(models.Model):
+class LocationType(ModelCore):
"Location type of an item location"
id = models.CharField(max_length=64, primary_key=True)
name = models.CharField(max_length=150)
class Meta(MetaCore):
db_table = 'location_types'
-class LocationAlias(models.Model):
+class LocationAlias(ModelCore):
"Location other name"
location_name = models.ForeignKey('Location', related_name="aliases",
db_column="location_name", max_length=150)
db_table = 'location_aliases'
unique_together = (('location_name', 'alias'),)
-class LocationRelation(models.Model):
+class LocationRelation(ModelCore):
"Location family"
location_name = models.ForeignKey('Location', related_name="parent_relations",
db_column="location_name", max_length=150)
class Meta(MetaCore):
db_table = 'location_relations'
-class ContextKeyword(models.Model):
+class ContextKeyword(ModelCore):
"Keyword"
value = models.CharField(max_length=250)
class Meta(MetaCore):
db_table = 'context_keywords'
-class MediaItemKeyword(models.Model):
+class MediaItemKeyword(ModelCore):
"Item keyword"
item = models.ForeignKey('MediaItem')
keyword = models.ForeignKey('ContextKeyword')
db_table = 'media_item_keywords'
unique_together = (('item', 'keyword'),)
-class Publisher(models.Model):
+class Publisher(ModelCore):
"Collection publisher"
value = models.CharField(max_length=250, unique=True)
class Meta(MetaCore):
db_table = 'publishers'
-class PublisherCollection(models.Model):
+class PublisherCollection(ModelCore):
"Collection which belongs to publisher"
publisher = models.ForeignKey('Publisher', related_name="publisher_collections")
value = models.CharField(max_length=250)
class Meta(MetaCore):
db_table = 'publisher_collections'
-class Revision(models.Model):
+class Revision(ModelCore):
"Revision made by user"
ELEMENT_TYPE_CHOICES = (('collection', 'collection'), ('item', 'item'), ('part', 'part'))
CHANGE_TYPE_CHOICES = (('import', 'import'), ('create', 'create'), ('update', 'update'), ('delete','delete'))
class Meta(MetaCore):
db_table = 'revisions'
-class EthnicGroup(models.Model):
+class EthnicGroup(ModelCore):
"Item ethnic group"
name = models.CharField(max_length=250)
def __unicode__(self):
return self.name
-class EthnicGroupAlias(models.Model):
+class EthnicGroupAlias(ModelCore):
"Item ethnic group other name"
ethnic_group = models.ForeignKey('EthnicGroup', related_name="aliases")
name = models.CharField(max_length=250)
class MissingUserError(Exception):
pass
+
+class RequiredFieldError(Exception):
+ def __init__(self, model, field):
+ self.model = model
+ self.field = field
+ super(Exception, self).__init__('%s.%s is required' % (model._meta.object_name, field.name))
# David LIPSZYC <davidlipszyc@gmail.com>
import unittest
-from telemeta.models import MediaCollection, MediaItem, Location, EthnicGroup, LocationType, User, Revision
+from telemeta.models import MediaCollection, MediaItem, Location, EthnicGroup, LocationType, User, Revision, RequiredFieldError
from datetime import datetime, timedelta
class CollectionItemTestCase(unittest.TestCase):
"Create a test database based on objects created in Django"
User.objects.all().delete()
- self.david = User.objects.create(username="david", level="user", first_name="david", last_name="aaa", phone="0156565656",
- email="david@a.com")
- self.olivier = User.objects.create(username="olivier", level="admin", first_name="olivier", last_name="bbb",
- phone="0155555555", email="olivier@a.com")
+ self.david = User.objects.create(username="david", level="user")
+ self.olivier = User.objects.create(username="olivier", level="admin")
LocationType.objects.all().delete()
- self.country = LocationType.objects.create(id="country", name="country")
- self.continent = LocationType.objects.create(id="continent", name="continent")
- self.city = LocationType.objects.create(id="city", name="city")
+ self.country = LocationType.objects.create(id="country", name="Country")
+ self.continent = LocationType.objects.create(id="continent", name="Continent")
+ self.city = LocationType.objects.create(id="city", name="City")
Location.objects.all().delete()
- self.paris = Location.objects.create(name="Paris", type="other", complete_type=self.city, is_authoritative=0)
- self.france = Location.objects.create(name="France", type="country", complete_type=self.country, is_authoritative=0)
- self.europe = Location.objects.create(name="Europe", type="continent", complete_type=self.continent, is_authoritative=0)
- self.belgique = Location.objects.create(name="Belgique", type="country", complete_type=self.country, is_authoritative=0)
+ self.paris = Location.objects.create(name="Paris", type="other", complete_type=self.city)
+ self.france = Location.objects.create(name="France", type="country", complete_type=self.country)
+ self.europe = Location.objects.create(name="Europe", type="continent", complete_type=self.continent)
+ self.belgique = Location.objects.create(name="Belgique", type="country", complete_type=self.country)
EthnicGroup.objects.all().delete()
self.a = EthnicGroup.objects.create(name="a")
self.d = EthnicGroup.objects.create(name="d")
MediaCollection.objects.all().delete()
- self.persepolis = MediaCollection(id=1, reference="A1", physical_format_id=1111, old_code="10", code="100", title="persepolis", alt_title="bjr", creator="Abraham LINCOLN",
- booklet_author="Maria BALTHAZAR",
- booklet_description="compilation de mots français",
- collector="Friedrich HEINZ", collector_is_creator=0, publisher_id=1442,
- year_published=2009, publisher_collection_id=1234,
- publisher_serial="123456", external_references="Larousse",
- acquisition_mode_id=1, comment="chants", metadata_author_id=1,
- metadata_writer_id=1, legal_rights_id=1, alt_ids="89",
- recorded_from_year=1970, recorded_to_year=1980, recording_context_id=1,
- approx_duration="5:00:00", doctype_code=1357, travail="travail",
- state="etat", cnrs_contributor="Jean PETIT", items_done="fiches",
- a_informer_07_03="a informer", ad_conversion_id=9, public_access="full")
+ self.persepolis = MediaCollection(id=1, code="100", reference="A1", title="persepolis",
+ creator="Abraham LINCOLN", collector="Friedrich HEINZ", year_published=2009,
+ recorded_from_year=1970, recorded_to_year=1980)
self.persepolis.save_by_user(self.david)
- self.volonte = MediaCollection(id=2, reference="A2", physical_format_id=222, old_code="20", code="200",
- title="Volonté de puissance", alt_title="ar", creator="Friedrich NIETZSCHE",
- booklet_author="George POMPIDOU", booklet_description="notice numero 2",
- collector="Jean AMORA", collector_is_creator=0, publisher_id=2884,
- year_published=1999, publisher_collection_id=2345,
- publisher_serial="234567", external_references="dico",
- acquisition_mode_id=2, comment="commentaire 2", metadata_author_id=2,
- metadata_writer_id=2, legal_rights_id=2, alt_ids="78",
- recorded_from_year=1960, recorded_to_year=2000, recording_context_id=2,
- approx_duration="1:00:00", doctype_code=2468, travail="travail 2",
- state="etat 2", cnrs_contributor="Richard LIONHEART", items_done="fiches 2",
- a_informer_07_03="a informer 2", ad_conversion_id=8,
- public_access="metadata")
+ self.volonte = MediaCollection(id=2, reference="A2", code="200", title="Volonté de puissance",
+ creator="Friedrich NIETZSCHE", collector="Jean AMORA", year_published=1999,
+ recorded_from_year=1960, recorded_to_year=2000)
self.volonte.save_by_user(self.olivier)
- self.nicolas = MediaCollection(id=3, reference="A3", physical_format_id=333, old_code="30", code="300",
- title="petit nicolas", alt_title="slt", creator="Georgette McKenic",
- booklet_author="Francesca DICORTO", booklet_description="notice 3",
- collector="Paul MAILLE", collector_is_creator=0, publisher_id=3773,
- year_published=1999, publisher_collection_id=7890, publisher_serial="8764",
- external_references="ref externes", acquisition_mode_id=3,
- comment="commentaire 3", metadata_author_id=3, metadata_writer_id=3,
- legal_rights_id=3, alt_ids="56", recorded_from_year=1967,
- recorded_to_year=1968, recording_context_id=3, approx_duration="0:00:00",
- doctype_code=5790, travail="travail 3", state="etat 3",
- cnrs_contributor="Gerard MICKAEL", items_done="fiches 3",
- a_informer_07_03="a informer 3", ad_conversion_id=8, public_access="none")
+ self.nicolas = MediaCollection(id=3, reference="A3", code="300", title="petit nicolas",
+ creator="Georgette McKenic", collector="Paul MAILLE", year_published=1999,
+ recorded_from_year=1967, recorded_to_year=1968)
self.nicolas.save_by_user(self.olivier)
MediaItem.objects.all().delete()
- self.item_1 = MediaItem(id=1, collection=self.persepolis, track="1111", old_code="101", code="1010",
- approx_duration="00:01:00", recorded_from_date="1971-01-12",
- recorded_to_date="1971-02-24", location_name=self.paris,
- location_comment="capital de la France", ethnic_group=self.a,
- title="item 1", alt_title="I1", author="Mickael SHEPHERD",
- context_comment="contexte ethno 1", external_references="ext ref 1",
- moda_execut="moda exec 1",copied_from_item_id=99,
- collector="Charles PREMIER", cultural_area="Ile de France", generic_style_id=1,
- collector_selection="collec sel 1", creator_reference="ref du deposant 1",
- comment="comment 1", filename="item 1.item", public_access="full")
+ self.item_1 = MediaItem(id=1, collection=self.persepolis, code="1010",
+ recorded_from_date="1971-01-12", recorded_to_date="1971-02-24", location=self.paris,
+ ethnic_group=self.a, title="item 1", author="Mickael SHEPHERD", collector="Charles PREMIER",
+ comment="comment 1")
self.item_1.save_by_user(self.david)
- self.item_2 = MediaItem(id=2, collection=self.volonte, track="2222", old_code="202", code="2020",
- approx_duration="00:02:00", recorded_from_date="1981-01-12",
- recorded_to_date="1991-02-24", location_name=self.france,
- location_comment="loc comment 2", ethnic_group=self.a, title="item 2",
- alt_title="I2", author="Rick ROLL", context_comment="contexte ethno 2",
- external_references="ext ref 2", moda_execut="moda exec 2",
- copied_from_item_id=98, collector="Gerard LENORMAND",
- cultural_area="Nord de la France", generic_style_id=1,
- collector_selection="collec sel 2", creator_reference="ref du deposant 2",
- comment="comment 2", filename="item 2.item", public_access="metadata")
+ self.item_2 = MediaItem(id=2, collection=self.volonte, code="2020",
+ recorded_from_date="1981-01-12", recorded_to_date="1991-02-24", location=self.france,
+ ethnic_group=self.a, title="item 2", author="Rick ROLL", comment="comment 2")
self.item_2.save_by_user(self.david)
- self.item_3 = MediaItem(id=3, collection=self.nicolas, track="3333", old_code="303", code="3030",
- approx_duration="00:03:00", recorded_from_date="1968-01-12",
- recorded_to_date="1968-02-24", location_name=self.belgique,
- location_comment="en Europe", ethnic_group=self.b, title="item 3",
- alt_title="I3", author="John SMITH", context_comment="contexte ethno 3",
- external_references="ext ref 3", moda_execut="moda exec 3", copied_from_item_id=97,
- collector="Paul CARLOS", cultural_area="Europe occidentale", generic_style_id=1,
- collector_selection="collec sel 3", creator_reference="ref du deposant 3",
- comment="comment 3", filename="item 3.item", public_access="none")
+ self.item_3 = MediaItem(id=3, collection=self.nicolas, code="3030",
+ recorded_from_date="1968-01-12", recorded_to_date="1968-02-24", location=self.belgique,
+ ethnic_group=self.b, title="item 3", author="John SMITH", collector="Paul CARLOS",
+ comment="comment 3", )
self.item_3.save_by_user(self.olivier)
- self.item_4 = MediaItem(id=4, collection=self.persepolis, track="4444", old_code="404", code="4040",
- approx_duration="00:04:00", recorded_from_date="1972-01-12",
- recorded_to_date="1972-02-24", location_name=self.europe,
- location_comment="loc comm 4", ethnic_group=self.a, title="item 4",
- alt_title="I4", author="Keanu REAVES", context_comment="contexte ethno 4",
- external_references="ext ref 4", moda_execut="moda exec 4", copied_from_item_id=96,
- collector="Christina BARCELONA", cultural_area="aire culturelle 4",
- generic_style_id=1, collector_selection="collec sel 4",
- creator_reference="ref du deposant 4", comment="comment 4", filename="item 4.item",
- public_access="none")
+ self.item_4 = MediaItem(id=4, collection=self.persepolis, code="4040",
+ recorded_from_date="1972-01-12", recorded_to_date="1972-02-24", location=self.europe,
+ ethnic_group=self.a, title="item 4", alt_title="I4", author="Keanu REAVES",
+ collector="Christina BARCELONA", comment="comment 4")
self.item_4.save_by_user(self.olivier)
- self.item_5 = MediaItem(id=5, collection=self.volonte, track="5555", old_code="505", code="5050",
- approx_duration="00:05:00", recorded_from_date="1978-01-12",
- recorded_to_date="1978-02-24", location_name=self.belgique,
- location_comment="loc comm 5", ethnic_group=self.a, title="item 5",
- alt_title="I5", author="Simon PAUL", context_comment="contexte ethno 5",
- external_references="ext ref 5", moda_execut="moda exec 5", copied_from_item_id=95,
- collector="Javier BARDEM", cultural_area="aire culturelle 5", generic_style_id=1,
- collector_selection="collec sel 5", creator_reference="ref du deposant 5",
- comment="comment 5", filename="item 5.item", public_access="metadata")
+ self.item_5 = MediaItem(id=5, collection=self.volonte,code="5050",
+ approx_duration="00:05:00", recorded_from_date="1978-01-12", recorded_to_date="1978-02-24",
+ location=self.belgique, ethnic_group=self.a, title="item 5", alt_title="I5",
+ author="Simon PAUL", collector="Javier BARDEM",
+ comment="comment 5")
self.item_5.save_by_user(self.olivier)
- self.item_6 = MediaItem(id=6, collection=self.persepolis, track="10000", old_code="1111111",
- code="6060", approx_duration="10:03:00", recorded_from_date="1968-01-12",
- recorded_to_date="1968-02-11", location_name=self.france,
- location_comment="loc comment 10000", ethnic_group=self.b,
- title="item 6", alt_title="I10000", author="Paul ANDERSON",
- context_comment="contexte ethno 10000", external_references="ext ref 10000",
- moda_execut="moda exec 10000", copied_from_item_id=11111, collector="Jim CARLSON",
- cultural_area="cul area 10000", generic_style_id=1,
- collector_selection="collec sel 10000", creator_reference="ref du deposant 10000",
- comment="comment 10000", filename="item 10000.item", public_access="none")
+ self.item_6 = MediaItem(id=6, collection=self.persepolis, code="6060",
+ recorded_from_date="1968-01-12", recorded_to_date="1968-02-11", location=self.france,
+ ethnic_group=self.b, title="item 6", author="Paul ANDERSON",
+ collector="Jim CARLSON", comment="comment 10000")
self.item_6.save_by_user(self.david)
def testWithoutCollection(self):
"Test without_collection property of MediaItem class"
self.assertEquals(self.items.without_collection().count(), 0)
+
+ def testCodeRequired(self):
+ c = MediaCollection()
+ try:
+ c.save_by_user(self.olivier)
+ except RequiredFieldError, e:
+ self.assertEquals(e.field.name, 'code')
+ else:
+ self.fail("No exception raised")
+