Merge pull request #421 from mouse-reeve/reverse-set-many-to-many

Fixes celery tasks expanding data not setting many to many fields
This commit is contained in:
Mouse Reeve 2020-12-23 13:52:48 -08:00 committed by GitHub
commit f6f075fac6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 24 deletions

View file

@ -111,15 +111,10 @@ class ActivityObject:
continue continue
model_field = getattr(model, model_field_name) model_field = getattr(model, model_field_name)
try: # creating a Work, model_field is 'editions'
# this is for one to many # creating a User, model field is 'key_pair'
related_model = model_field.field.model related_model = model_field.field.model
related_field_name = model_field.field.name related_field_name = model_field.field.name
except AttributeError:
# it's a one to one or foreign key
related_model = model_field.related.related_model
related_field_name = model_field.related.related_name
values = [values]
for item in values: for item in values:
set_related_field.delay( set_related_field.delay(
@ -142,8 +137,8 @@ class ActivityObject:
@app.task @app.task
@transaction.atomic @transaction.atomic
def set_related_field( def set_related_field(
model_name, origin_model_name, model_name, origin_model_name, related_field_name,
related_field_name, related_remote_id, data): related_remote_id, data):
''' load reverse related fields (editions, attachments) without blocking ''' ''' load reverse related fields (editions, attachments) without blocking '''
model = apps.get_model('bookwyrm.%s' % model_name, require_ready=True) model = apps.get_model('bookwyrm.%s' % model_name, require_ready=True)
origin_model = apps.get_model( origin_model = apps.get_model(
@ -153,23 +148,36 @@ def set_related_field(
with transaction.atomic(): with transaction.atomic():
if isinstance(data, str): if isinstance(data, str):
item = resolve_remote_id(model, data, save=False) existing = model.find_existing_by_remote_id(data)
else: if existing:
# look for a match based on all the available data data = existing.to_activity()
item = model.find_existing(data) else:
if not item: data = get_data(data)
# create a new model instance activity = model.activity_serializer(**data)
item = model.activity_serializer(**data)
item = item.to_model(model, save=False)
# this must exist because it's the object that triggered this function # this must exist because it's the object that triggered this function
instance = origin_model.find_existing_by_remote_id(related_remote_id) instance = origin_model.find_existing_by_remote_id(related_remote_id)
if not instance: if not instance:
raise ValueError( raise ValueError(
'Invalid related remote id: %s' % related_remote_id) 'Invalid related remote id: %s' % related_remote_id)
# edition.parent_work = instance, for example # set the origin's remote id on the activity so it will be there when
setattr(item, related_field_name, instance) # the model instance is created
item.save() # edition.parentWork = instance, for example
model_field = getattr(model, related_field_name)
if hasattr(model_field, 'activitypub_field'):
setattr(
activity,
getattr(model_field, 'activitypub_field'),
instance.remote_id
)
item = activity.to_model(model)
# if the related field isn't serialized (attachments on Status), then
# we have to set it post-creation
if not hasattr(model_field, 'activitypub_field'):
setattr(item, related_field_name, instance)
item.save()
def resolve_remote_id(model, remote_id, refresh=False, save=True): def resolve_remote_id(model, remote_id, refresh=False, save=True):

View file

@ -59,9 +59,7 @@ class Book(BookDataModel):
subject_places = fields.ArrayField( subject_places = fields.ArrayField(
models.CharField(max_length=255), blank=True, null=True, default=list models.CharField(max_length=255), blank=True, null=True, default=list
) )
# TODO: include an annotation about the type of authorship (ie, translator)
authors = fields.ManyToManyField('Author') authors = fields.ManyToManyField('Author')
# preformatted authorship string for search and easier display
cover = fields.ImageField( cover = fields.ImageField(
upload_to='covers/', blank=True, null=True, alt_field='alt_text') upload_to='covers/', blank=True, null=True, alt_field='alt_text')
first_published_date = fields.DateTimeField(blank=True, null=True) first_published_date = fields.DateTimeField(blank=True, null=True)