-
Notifications
You must be signed in to change notification settings - Fork 4
/
relationship.py
192 lines (169 loc) · 7.41 KB
/
relationship.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
class CRIMRelationship(models.Model):
class Meta:
app_label = 'crim'
verbose_name = 'Relationship'
verbose_name_plural = 'Relationships'
observer = models.ForeignKey(
'CRIMPerson',
on_delete=models.SET_NULL,
to_field='person_id',
null=True,
db_index=True,
related_name='relationships',
)
model_observation = models.ForeignKey(
'CRIMObservation',
on_delete=models.CASCADE,
db_index=True,
related_name='observations_as_model',
)
derivative_observation = models.ForeignKey(
'CRIMObservation',
on_delete=models.CASCADE,
db_index=True,
related_name='observations_as_derivative',
)
# These next two fields are redundant, but make it easier
# to access all relationships associated with a piece using
# a reverse lookup. Removing these fields will make the
# piece/xxx/relationship template not work.
model_piece = models.ForeignKey(
'CRIMPiece',
on_delete=models.CASCADE,
to_field='piece_id',
db_index=True,
related_name='relationships_as_model',
)
derivative_piece = models.ForeignKey(
'CRIMPiece',
on_delete=models.CASCADE,
to_field='piece_id',
db_index=True,
related_name='relationships_as_derivative',
)
# These fields provide redundant, easily accessible, human-readable
# information about relationship type and musical type.
# They are updated upon saving.
relationship_type = models.CharField(max_length=64, blank=True)
musical_type = models.CharField(max_length=64, blank=True)
rt_q = models.BooleanField('quotation', default=False)
rt_q_x = models.BooleanField('exact', default=False)
rt_q_monnayage = models.BooleanField('monnayage', default=False)
rt_tm = models.BooleanField('mechanical transformation', default=False)
rt_tm_snd = models.BooleanField('sounding in different voice(s)', default=False)
rt_tm_minv = models.BooleanField('melodically inverted', default=False)
rt_tm_retrograde = models.BooleanField('retrograde', default=False)
rt_tm_ms = models.BooleanField('metrically shifted', default=False)
rt_tm_transposed = models.BooleanField('transposed', default=False)
rt_tm_invertible = models.BooleanField('double or invertible counterpoint', default=False)
rt_tnm = models.BooleanField('non-mechanical transformation', default=False)
rt_tnm_embellished = models.BooleanField('embellished', default=False)
rt_tnm_reduced = models.BooleanField('reduced', default=False)
rt_tnm_amplified = models.BooleanField('amplified', default=False)
rt_tnm_truncated = models.BooleanField('truncated', default=False)
rt_tnm_ncs = models.BooleanField('new counter-subject', default=False)
rt_tnm_ocs = models.BooleanField('old counter-subject shifted', default=False)
rt_tnm_ocst = models.BooleanField('old counter-subject transposed', default=False)
rt_tnm_nc = models.BooleanField('new combination', default=False)
rt_nm = models.BooleanField('new material', default=False)
rt_om = models.BooleanField('omission', default=False)
remarks = models.TextField('remarks (supports Markdown)', blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
curated = models.BooleanField('curated', default=False)
def id_in_brackets(self):
return '<R' + str(self.id) + '>'
id_in_brackets.short_description = 'ID'
id_in_brackets.admin_order_field = 'id'
def get_absolute_url(self):
return '/relationship/{0}/'.format(self.pk)
def __str__(self):
return '<R{0}> {1}, {2}'.format(
self.id,
self.model_observation.piece_id,
self.derivative_observation.piece_id
)
def save(self, *args, **kwargs):
# Add the model pieces fields based on the observations
self.model_piece = self.model_observation.piece
self.derivative_piece = self.derivative_observation.piece
# Set the parent relationship type field to true if any of the subtypes are
if self.rt_q_x or self.rt_q_monnayage:
self.rt_q = True
if (self.rt_tm_snd or self.rt_tm_minv or self.rt_tm_retrograde or
self.rt_tm_ms or self.rt_tm_transposed or self.rt_tm_invertible):
self.rt_tm = True
if (self.rt_tnm_embellished or self.rt_tnm_reduced or self.rt_tnm_amplified or
self.rt_tnm_truncated or self.rt_tnm_ncs or self.rt_tnm_ocs or
self.rt_tnm_ocst or self.rt_tnm_nc):
self.rt_tnm = True
# Fill out the human-readable relationship type field
if self.rt_q:
self.relationship_type = 'Quotation'
elif self.rt_tm:
self.relationship_type = 'Mechanical transformation'
elif self.rt_tnm:
self.relationship_type = 'Non-mechanical transformation'
elif self.rt_nm:
self.relationship_type = 'New material'
elif self.rt_om:
self.relationship_type = 'Omission'
# For the musical type field, check if both observations use the same
# musical type; otherwise, use whichever has a musical type if one of
# them doesn't (e.g. omission), or include them both.
if not self.model_observation.musical_type and not self.derivative_observation.musical_type:
pass
elif self.model_observation.musical_type:
self.musical_type = self.model_observation.musical_type
elif self.derivative_observation.musical_type:
self.musical_type = self.derivative_observation.musical_type
else:
self.musical_type = (
self.model_observation.musical_type +
', ' +
self.derivative_observation.musical_type
)
# Finalize changes
super().save()
#
# @receiver(post_save, sender=CRIMRelationship)
# def solr_index(sender, instance, created, **kwargs):
# print('Indexing in Solr')
# from django.conf import settings
# import solr
#
# solrconn = solr.SolrConnection(settings.SOLR_SERVER)
# record = solrconn.query("id:{0}".format(instance.id))
# if record:
# # the record already exists, so we'll remove it first.
# print("Deleting {}".format(record.results[0]['id']))
# solrconn.delete(record.results[0]['id'])
#
# # Don't index if this relationship needs review!
# if not instance.curated:
# return
# # The suffixes are for automatic creation of the schema using
# # the correct types -- see http://yonik.com/solr-tutorial/
# d = {
# 'type': 'crim_relationship',
# 'id': instance.id,
# 'observer_s': instance.observer.name,
#
# # Information about the relationship type
# ...
# }
# solrconn.add(**d)
# solrconn.commit()
@receiver(post_delete, sender=CRIMRelationship)
def solr_delete(sender, instance, **kwargs):
from django.conf import settings
import solr
solrconn = solr.SolrConnection(settings.SOLR_SERVER)
record = solrconn.query("id:{0}".format(instance.id))
if record:
# the record already exists, so we'll remove it first.
print("Deleting ".format(record.results[0]['id']))
solrconn.delete(record.results[0]['id'])