minor improvements + crash fix

sync_v2
Laurent 6 months ago
parent 1d8fb1b32a
commit e4beca4840
  1. 5
      sync/models/base.py
  2. 1
      sync/models/data_access.py
  3. 57
      sync/signals.py
  4. 7
      sync/utils.py
  5. 15
      sync/views.py

@ -51,7 +51,10 @@ class BaseModel(models.Model):
self.data_access_ids.append(str_id) self.data_access_ids.append(str_id)
def remove_data_access_relation(self, data_access): def remove_data_access_relation(self, data_access):
self.data_access_ids.remove(str(data_access.id)) try:
self.data_access_ids.remove(str(data_access.id))
except ValueError:
pass
def get_children_by_model(self): def get_children_by_model(self):
""" """

@ -79,6 +79,7 @@ class DataAccess(BaseModel):
try: try:
obj = model_class.objects.get(id=self.model_id) obj = model_class.objects.get(id=self.model_id)
related_instance = obj.related_instances() related_instance = obj.related_instances()
related_instance.append(obj)
for instance in related_instance: for instance in related_instance:
if isinstance(instance, BaseModel): if isinstance(instance, BaseModel):
instance.remove_data_access_relation(self) instance.remove_data_access_relation(self)

@ -17,28 +17,23 @@ User = get_user_model()
@receiver([pre_save, pre_delete]) @receiver([pre_save, pre_delete])
def presave_handler(sender, instance, **kwargs): def presave_handler(sender, instance, **kwargs):
synchronization_prepare(sender, instance, **kwargs)
def synchronization_prepare(sender, instance, **kwargs): # some other classes are excluded in settings_app.py: SYNC_APPS
if not isinstance(instance, (BaseModel, User)):
return
# print(f'*** synchronization_prepare for instance: {instance}')
signal = kwargs.get('signal') signal = kwargs.get('signal')
# avoid crash in manage.py createsuperuser + delete user in the admin # avoid crash in manage.py createsuperuser + delete user in the admin
if isinstance(instance, User) and (instance._state.db is None or signal == pre_delete): if isinstance(instance, User) and (instance._state.db is None or signal == pre_delete):
return return
# some other classes are excluded in settings_app.py: SYNC_APPS
if not isinstance(instance, BaseModel) and not isinstance(instance, User):
return
users = related_users(instance) users = related_users(instance)
# print(f'* impacted users = {users}') # print(f'* impacted users = {users}')
related_users_registry.register(instance.id, users) related_users_registry.register(instance.id, users)
# user_ids = [user.id for user in users] # user_ids = [user.id for user in users]
if signal == pre_save: if signal == pre_save:
detect_foreign_key_changes(sender, instance) detect_foreign_key_changes_for_shared_instances(sender, instance)
@receiver([post_save, post_delete]) @receiver([post_save, post_delete])
def synchronization_notifications(sender, instance, created=False, **kwargs): def synchronization_notifications(sender, instance, created=False, **kwargs):
@ -123,19 +118,35 @@ def save_model_log(users, model_operation, model_name, model_id, store_id):
# print(f'>> creating Model Log for: {model_operation} {model_name}') # print(f'>> creating Model Log for: {model_operation} {model_name}')
logs_to_create = [
ModelLog(
user=user,
operation=model_operation,
model_name=model_name,
model_id=model_id,
store_id=store_id,
device_id=device_id
)
for user in users
# if user.should_synchronize
]
with transaction.atomic(): with transaction.atomic():
for user in users: ModelLog.objects.bulk_create(logs_to_create)
# print(f' * {user.username}')
# with transaction.atomic():
# if user.should_synchronize: # for user in users:
model_log = ModelLog() # # print(f' * {user.username}')
model_log.user = user
model_log.operation = model_operation # # if user.should_synchronize:
model_log.model_name = model_name # model_log = ModelLog()
model_log.model_id = model_id # model_log.user = user
model_log.store_id = store_id # model_log.operation = model_operation
model_log.device_id = device_id # model_log.model_name = model_name
model_log.save() # model_log.model_id = model_id
# model_log.store_id = store_id
# model_log.device_id = device_id
# model_log.save()
# print(f'ML users = {len(users)}') # print(f'ML users = {len(users)}')
# existing_log = ModelLog.objects.filter(users__in=users, model_id=model_id, operation=model_operation).first() # existing_log = ModelLog.objects.filter(users__in=users, model_id=model_id, operation=model_operation).first()
@ -157,7 +168,7 @@ def save_model_log(users, model_operation, model_name, model_id, store_id):
# model_log.save() # model_log.save()
# model_log.users.set(users) # model_log.users.set(users)
def detect_foreign_key_changes(sender, instance): def detect_foreign_key_changes_for_shared_instances(sender, instance):
if not hasattr(instance, 'pk') or not instance.pk: if not hasattr(instance, 'pk') or not instance.pk:
return return
if not isinstance(instance, BaseModel): if not isinstance(instance, BaseModel):
@ -296,7 +307,7 @@ def related_users(instance):
# look in related DataAccess # look in related DataAccess
# data_access_list = instances_related_data_access(instance, related_instances) # data_access_list = instances_related_data_access(instance, related_instances)
print(f'instance = {instance.__class__.__name__}, data access count = {len(data_access_list)}') # print(f'instance = {instance.__class__.__name__}, data access count = {len(data_access_list)}')
for data_access in data_access_list: for data_access in data_access_list:
users.add(data_access.related_user) users.add(data_access.related_user)
users.update(data_access.shared_with.all()) users.update(data_access.shared_with.all())

@ -31,16 +31,13 @@ def get_serializer(instance, model_name):
def get_data(model_name, model_id): def get_data(model_name, model_id):
model = model_registry.get_model(model_name) model = model_registry.get_model(model_name)
# print(f'model_name = {model_name}')
# model = apps.get_model(app_label=app_label, model_name=model_name)
return model.objects.get(id=model_id) return model.objects.get(id=model_id)
def get_serialized_data(model_name, model_id): def get_serialized_data_by_id(model_name, model_id):
# print(f'model_name = {model_name}') # print(f'model_name = {model_name}')
model = model_registry.get_model(model_name) model = model_registry.get_model(model_name)
instance = model.objects.get(id=model_id) instance = model.objects.get(id=model_id)
serializer_class = build_serializer_class(model_name) serializer = get_serializer(instance, model_name)
serializer = serializer_class(instance)
return serializer.data return serializer.data
class HierarchyOrganizer: class HierarchyOrganizer:

@ -17,7 +17,7 @@ from collections import defaultdict
from urllib.parse import unquote from urllib.parse import unquote
from .serializers import DataAccessSerializer from .serializers import DataAccessSerializer
from .utils import get_serializer, build_serializer_class, get_data, get_serialized_data, HierarchyOrganizer from .utils import get_serializer, build_serializer_class, get_data, get_serialized_data_by_id, HierarchyOrganizer
from .models import ModelLog, BaseModel, SideStoreModel, DataAccess from .models import ModelLog, BaseModel, SideStoreModel, DataAccess
@ -212,13 +212,11 @@ class SynchronizationApi(APIView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
last_update_str = request.query_params.get('last_update') last_update_str = request.query_params.get('last_update')
device_id = request.query_params.get('device_id') if not last_update_str:
decoded_last_update = unquote(last_update_str) # Decodes %2B into +
if not decoded_last_update:
return Response({"error": "last_update parameter is required"}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": "last_update parameter is required"}, status=status.HTTP_400_BAD_REQUEST)
try: try:
decoded_last_update = unquote(last_update_str) # Decodes %2B into +
last_update = timezone.datetime.fromisoformat(decoded_last_update) last_update = timezone.datetime.fromisoformat(decoded_last_update)
except ValueError: except ValueError:
return Response({"error": f"Invalid date format for last_update: {decoded_last_update}"}, return Response({"error": f"Invalid date format for last_update: {decoded_last_update}"},
@ -226,6 +224,7 @@ class SynchronizationApi(APIView):
print(f'>>> GET last modifications since: {last_update_str} / converted = {last_update}') print(f'>>> GET last modifications since: {last_update_str} / converted = {last_update}')
device_id = request.query_params.get('device_id')
logs = self.query_model_logs(last_update, request.user, device_id) logs = self.query_model_logs(last_update, request.user, device_id)
print(f'>>> user = {request.user.username} > log count = {logs.count()}, device_id = {device_id}') print(f'>>> user = {request.user.username} > log count = {logs.count()}, device_id = {device_id}')
@ -262,7 +261,7 @@ class LogProcessingResult:
self.last_log_date = log.date self.last_log_date = log.date
try: try:
if log.operation in ['POST', 'PUT']: if log.operation in ['POST', 'PUT']:
data = get_serialized_data(log.model_name, log.model_id) data = get_serialized_data_by_id(log.model_name, log.model_id)
self.updates[log.model_name][log.model_id] = data self.updates[log.model_name][log.model_id] = data
elif log.operation == 'DELETE': elif log.operation == 'DELETE':
self.deletions[log.model_name].append(log.data_identifier_dict()) self.deletions[log.model_name].append(log.data_identifier_dict())
@ -292,7 +291,7 @@ class LogProcessingResult:
# elif log.operation == 'RELATIONSHIP_REMOVED': # elif log.operation == 'RELATIONSHIP_REMOVED':
# self.relationship_removals[log.model_name].append(log.data_identifier_dict()) # self.relationship_removals[log.model_name].append(log.data_identifier_dict())
elif log.operation == 'SHARED_RELATIONSHIP_SET': elif log.operation == 'SHARED_RELATIONSHIP_SET':
data = get_serialized_data(log.model_name, log.model_id) data = get_serialized_data_by_id(log.model_name, log.model_id)
self.shared_relationship_sets[log.model_name][log.model_id] = data self.shared_relationship_sets[log.model_name][log.model_id] = data
elif log.operation == 'SHARED_RELATIONSHIP_REMOVED': elif log.operation == 'SHARED_RELATIONSHIP_REMOVED':
self.shared_relationship_removals[log.model_name].append(log.data_identifier_dict()) self.shared_relationship_removals[log.model_name].append(log.data_identifier_dict())

Loading…
Cancel
Save