add binding_filler to simplify some inserts

This commit is contained in:
voussoir 2016-12-14 14:36:58 -08:00
parent 1e7aff5cfd
commit 693fce0d34
2 changed files with 87 additions and 45 deletions

View file

@ -183,6 +183,25 @@ def _helper_filenamefilter(subject, terms):
basename = subject.lower() basename = subject.lower()
return all(term in basename for term in terms) return all(term in basename for term in terms)
def binding_filler(column_names, values, require_all=True):
'''
Manually aligning question marks and bindings is annoying.
Given the table's column names and a dictionary of {column: value},
return the question marks and the list of bindings in the right order.
'''
values = values.copy()
for column in column_names:
if column in values:
continue
if require_all:
raise ValueError('Missing column "%s"' % column)
else:
values.setdefault(column, None)
qmarks = '?' * len(column_names)
qmarks = ', '.join(qmarks)
bindings = [values[column] for column in column_names]
return (qmarks, bindings)
def getnow(timestamp=True): def getnow(timestamp=True):
''' '''
Return the current UTC timestamp or datetime object. Return the current UTC timestamp or datetime object.
@ -460,13 +479,16 @@ class PDBAlbumMixin:
if not isinstance(description, str): if not isinstance(description, str):
raise TypeError('Description must be string, not %s' % type(description)) raise TypeError('Description must be string, not %s' % type(description))
data = [None] * len(SQL_ALBUM_COLUMNS) data = {}
data[SQL_ALBUM['id']] = albumid data['id'] = albumid
data[SQL_ALBUM['title']] = title data['title'] = title
data[SQL_ALBUM['description']] = description data['description'] = description
data[SQL_ALBUM['associated_directory']] = associated_directory data['associated_directory'] = associated_directory
(qmarks, bindings) = binding_filler(SQL_ALBUM_COLUMNS, data)
query = 'INSERT INTO albums VALUES(%s)' % qmarks
self.cur.execute(query, bindings)
self.cur.execute('INSERT INTO albums VALUES(?, ?, ?, ?)', data)
album = Album(self, data) album = Album(self, data)
if photos: if photos:
for photo in photos: for photo in photos:
@ -569,23 +591,27 @@ class PDBPhotoMixin:
created = int(getnow()) created = int(getnow())
photoid = self.generate_id('photos') photoid = self.generate_id('photos')
data = [None] * len(SQL_PHOTO_COLUMNS) data = {}
data[SQL_PHOTO['id']] = photoid data['id'] = photoid
data[SQL_PHOTO['filepath']] = filename data['filepath'] = filename
data[SQL_PHOTO['override_filename']] = None data['override_filename'] = None
data[SQL_PHOTO['extension']] = extension data['extension'] = extension
data[SQL_PHOTO['created']] = created data['created'] = created
# These will be filled in just a moment data['tagged_at'] = None
data[SQL_PHOTO['bytes']] = None # These will be filled in during the metadata stage.
data[SQL_PHOTO['width']] = None data['bytes'] = None
data[SQL_PHOTO['height']] = None data['width'] = None
data[SQL_PHOTO['area']] = None data['height'] = None
data[SQL_PHOTO['ratio']] = None data['area'] = None
data[SQL_PHOTO['duration']] = None data['ratio'] = None
data[SQL_PHOTO['thumbnail']] = None data['duration'] = None
data['thumbnail'] = None
self.cur.execute('INSERT INTO photos VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', data) (qmarks, bindings) = binding_filler(SQL_PHOTO_COLUMNS, data)
query = 'INSERT INTO photos VALUES(%s)' % qmarks
self.cur.execute(query, bindings)
photo = Photo(self, data) photo = Photo(self, data)
if do_metadata: if do_metadata:
photo.reload_metadata(commit=False) photo.reload_metadata(commit=False)
if do_thumbnail: if do_thumbnail:
@ -598,6 +624,7 @@ class PDBPhotoMixin:
if commit: if commit:
log.debug('Commiting - new_photo') log.debug('Commiting - new_photo')
self.commit()
return photo return photo
def search( def search(
@ -1252,9 +1279,11 @@ class ObjectBase:
class GroupableMixin: class GroupableMixin:
def add(self, member, commit=True): def add(self, member, commit=True):
''' '''
Add a Tag object to this group. Add a child object to this group.
Child must be of the same type as the calling object.
If that object is already a member of another group, a exceptions.GroupExists is raised. If that object is already a member of another group, an
exceptions.GroupExists is raised.
''' '''
if not isinstance(member, type(self)): if not isinstance(member, type(self)):
raise TypeError('Member must be of type %s' % type(self)) raise TypeError('Member must be of type %s' % type(self))
@ -1290,7 +1319,12 @@ class GroupableMixin:
def delete(self, delete_children=False, commit=True): def delete(self, delete_children=False, commit=True):
''' '''
Delete a tag and its relationship with photos, synonyms, and tag groups. Delete this object's relationships to other groupables.
Any unique / specific deletion methods should be written within the
inheriting class.
For example, Tag.delete calls here to remove the group links, but then
does the rest of the tag deletion process on its own.
delete_children: delete_children:
If True, all children will be deleted. If True, all children will be deleted.
@ -1320,7 +1354,8 @@ class GroupableMixin:
def parent(self): def parent(self):
''' '''
Return the Tag object of which this is a member, or None. Return the group of which this is a member, or None.
Returned object will be of the same type as calling object.
''' '''
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [self.id]) self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [self.id])
fetch = self.photodb.cur.fetchone() fetch = self.photodb.cur.fetchone()
@ -1370,10 +1405,12 @@ class GroupableMixin:
class Album(ObjectBase, GroupableMixin): class Album(ObjectBase, GroupableMixin):
def __init__(self, photodb, row_tuple): def __init__(self, photodb, row_tuple):
self.photodb = photodb self.photodb = photodb
self.id = row_tuple[SQL_ALBUM['id']] if isinstance(row_tuple, (list, tuple)):
self.title = row_tuple[SQL_ALBUM['title']] row_tuple = {SQL_ALBUM_COLUMNS[index]: value for (index, value) in enumerate(row_tuple)}
self.id = row_tuple['id']
self.title = row_tuple['title']
self.description = row_tuple['description']
self.name = 'Album %s' % self.id self.name = 'Album %s' % self.id
self.description = row_tuple[SQL_ALBUM['description']]
self.group_getter = self.photodb.get_album self.group_getter = self.photodb.get_album
def __repr__(self): def __repr__(self):
@ -1476,22 +1513,25 @@ class Photo(ObjectBase):
''' '''
def __init__(self, photodb, row_tuple): def __init__(self, photodb, row_tuple):
self.photodb = photodb self.photodb = photodb
self.id = row_tuple[SQL_PHOTO['id']] if isinstance(row_tuple, (list, tuple)):
self.real_filepath = row_tuple[SQL_PHOTO['filepath']] row_tuple = {SQL_PHOTO_COLUMNS[index]: value for (index, value) in enumerate(row_tuple)}
self.id = row_tuple['id']
self.real_filepath = row_tuple['filepath']
self.real_filepath = normalize_filepath(self.real_filepath) self.real_filepath = normalize_filepath(self.real_filepath)
self.real_path = pathclass.Path(self.real_filepath) self.real_path = pathclass.Path(self.real_filepath)
self.filepath = row_tuple[SQL_PHOTO['override_filename']] or self.real_filepath self.filepath = row_tuple['override_filename'] or self.real_filepath
self.basename = row_tuple[SQL_PHOTO['override_filename']] or os.path.basename(self.real_filepath) self.basename = row_tuple['override_filename'] or os.path.basename(self.real_filepath)
self.extension = row_tuple[SQL_PHOTO['extension']] self.extension = row_tuple['extension']
self.width = row_tuple[SQL_PHOTO['width']] self.width = row_tuple['width']
self.height = row_tuple[SQL_PHOTO['height']] self.height = row_tuple['height']
self.ratio = row_tuple[SQL_PHOTO['ratio']] self.ratio = row_tuple['ratio']
self.area = row_tuple[SQL_PHOTO['area']] self.area = row_tuple['area']
self.bytes = row_tuple[SQL_PHOTO['bytes']] self.bytes = row_tuple['bytes']
self.duration = row_tuple[SQL_PHOTO['duration']] self.duration = row_tuple['duration']
self.created = row_tuple[SQL_PHOTO['created']] self.created = row_tuple['created']
self.thumbnail = row_tuple[SQL_PHOTO['thumbnail']] self.thumbnail = row_tuple['thumbnail']
self.tagged_at = row_tuple[SQL_PHOTO['tagged_at']] self.tagged_at = row_tuple['tagged_at']
def __reinit__(self): def __reinit__(self):
''' '''
@ -1820,8 +1860,10 @@ class Tag(ObjectBase, GroupableMixin):
''' '''
def __init__(self, photodb, row_tuple): def __init__(self, photodb, row_tuple):
self.photodb = photodb self.photodb = photodb
self.id = row_tuple[SQL_TAG['id']] if isinstance(row_tuple, (list, tuple)):
self.name = row_tuple[SQL_TAG['name']] row_tuple = {SQL_TAG_COLUMNS[index]: value for (index, value) in enumerate(row_tuple)}
self.id = row_tuple['id']
self.name = row_tuple['name']
self.group_getter = self.photodb.get_tag self.group_getter = self.photodb.get_tag
self._cached_qualified_name = None self._cached_qualified_name = None

View file

@ -28,7 +28,7 @@ p
<p>{{album["description"]}}</p> <p>{{album["description"]}}</p>
{% set parent=album["parent"] %} {% set parent=album["parent"] %}
{% if parent %} {% if parent %}
<h3>Parent: <a href="/album/{{parent["id"]}}">{{parent.title}}</a></h3> <h3>Parent: <a href="/album/{{parent["id"]}}">{{parent["id"] + " " + parent.title}}</a></h3>
{% else %} {% else %}
<h3>Parent: <a href="/albums">Albums</a></h3> <h3>Parent: <a href="/albums">Albums</a></h3>
{% endif %} {% endif %}