chenzhaoyang
2025-12-17 063da0bf961e1d35e25dc107f883f7492f4c5a7c
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
import json
import logging
 
from django.core import serializers
from django.db import models
from django.db.models import JSONField
from django.utils.translation import gettext_lazy as _
 
logger = logging.getLogger(__name__)
 
 
class AsyncMigrationStatus(models.Model):
    meta = JSONField(
        'meta',
        null=True,
        default=dict,
        help_text='Meta is for any params for migrations, e.g.: project, filter or error message.',
    )
 
    project = models.ForeignKey(
        'projects.Project',
        related_name='asyncmigrationstatus',
        on_delete=models.CASCADE,
        null=True,
        help_text='Project ID for this migration',
    )
 
    name = models.TextField('migration_name', help_text='Migration name')
 
    STATUS_SCHEDULED = 'SCHEDULED'
    STATUS_STARTED = 'STARTED'
    STATUS_IN_PROGRESS = 'IN PROGRESS'
    STATUS_FINISHED = 'FINISHED'
    STATUS_ERROR = 'ERROR'
    STATUS_CHOICES = (
        (STATUS_SCHEDULED, 'Migration is scheduled but not yet started.'),
        (STATUS_STARTED, 'Migration is started or queued.'),
        (STATUS_IN_PROGRESS, 'Migration is in progress. Check meta for job_id or status.'),
        (STATUS_FINISHED, 'Migration completed successfully.'),
        (STATUS_ERROR, 'Migration completed with errors. Check meta for more info.'),
    )
    status = models.CharField(max_length=100, choices=STATUS_CHOICES, null=True, default=None)
 
    created_at = models.DateTimeField(_('created at'), auto_now_add=True, help_text='Creation time')
    updated_at = models.DateTimeField(_('updated at'), auto_now=True, help_text='Last updated time')
 
    def __str__(self):
        return f'(id={self.id}) ' + self.name + (' at project ' + str(self.project) if self.project else '')
 
 
class DeletedRow(models.Model):
    """
    Model to store deleted rows of other models.
    Useful for using as backup for deleted rows, in case we need to restore them.
    """
 
    model = models.CharField(max_length=1024)   # tasks.task, projects.project, etc.
    row_id = models.IntegerField(null=True)   # primary key of the deleted row. task.id, project.id, etc.
    data = JSONField(null=True, blank=True)   # serialized json of the deleted row.
    reason = models.TextField(null=True, blank=True)   # reason for deletion.
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
 
    # optional fields for searching purposes
    organization_id = models.IntegerField(null=True, blank=True)
    project_id = models.IntegerField(null=True, blank=True)
    user_id = models.IntegerField(null=True, blank=True)
 
    @classmethod
    def serialize_and_create(cls, model, **kwargs) -> 'DeletedRow':
        data = json.loads(serializers.serialize('json', [model]))[0]
        model = data['model']
        row_id = int(data['pk'])
        return cls.objects.create(model=model, row_id=row_id, data=data, **kwargs)
 
    @classmethod
    def bulk_serialize_and_create(cls, queryset, **kwargs) -> list['DeletedRow']:
        serialized_data = json.loads(serializers.serialize('json', queryset))
        bulk_objects = []
        for data in serialized_data:
            model = data['model']
            row_id = int(data['pk'])
            bulk_objects.append(cls(model=model, row_id=row_id, data=data, **kwargs))
        return cls.objects.bulk_create(bulk_objects)