Django, проблемы при создании поля автоинкремента без первичного ключа - PullRequest
0 голосов
/ 07 марта 2020

Intro:

У меня есть несколько механизмов, сохраняющих данные в одном экземпляре базы данных (postgres), теперь для merchantA идентификатор в его списке ролей: 1,3,4,5,8, для merchantB: 2,6,7,8,10, чтобы каждый продавец мог получить свои собственные идентификаторы последовательного приращения, например, в списке ролей forntend торговца A должно быть:

     "merchant_id":1, 
     "role":{
             "id":1,"name":admin,
             "id":2,"name":dev,
             "id":3,"name":finance,
            }

роль продавца B Список:

     "merchant_id":2, 
     "role":{
             "id":1,"name":admin,
             "id":2,"name":dev,
             "id":3,"name":finance,
            }

Решение:

Я установил поле ref_id для модели ролей вместо того, чтобы использовать идентификатор поля базы данных по умолчанию, и использую таблицу для сохранения результата подсчета, когда объект роли

class Role(BaseModel):
    name = models.CharField(
        null=True,
        blank=True,
        max_length=50
    )
    ref_id = models.IntegerField(null=True, blank=True)
    merchant = models.ForeignKey(Merchant, on_delete=models.CASCADE)

    # use pre_save to save the count returned from AutoIDService
    @receiver(pre_save, sender=Role)
    def update_ref_id(sender, instance: Role, **kwargs):
        instance.ref_id = AutoIDService.next('Role', instance.merchant.id)


#IDTable used to save persist count
class IDTable(BaseModel):
    key = models.CharField(max_length=255, null=True, blank=True)
    ref_id = models.IntegerField(null=True, blank=True)

#do the count, return current 
class AutoIDService:
    @classmethod
    def next(cls, table_name, merchant_id):
        key = table_name + str(merchant_id)
        with transaction.atomic():
            id_table, created = IDTable.objects.select_for_update().get_or_create(key=key, defaults={'ref_id': 1})
            print('created', created)
            if not created:
                print('created false')
                id_table.ref_id += 1
                id_table.save()
        print('return value', id_table.ref_id)
        return id_table.ref_id


Задача

#This is the very first record in Role Table
m1 = Merchant.objects.first() 
r1 = Role(name='test1',merchant=m1,created_at=datetime.datetime.now())
r1.save()
#when I'm trying to save a role to database, I got this result:
#created True  
#value 1  
#created False  
#created false  
#return value 2

# second record for m1
r2 = Role(name='test2',merchant=m1,created_at=datetime.datetime.now())
r2.save()
#created False
#created false
#return value 3


#data in Role table is like
id   name   ref_id  merchant_id
1    test1    2        1
2    test2    3        1

Я не уверен, почему ref_id был посчитан дважды для первой записи, затем я попытался создать роль для другого продавца

r1 = Role(name='test1',merchant=m2,created_at=datetime.datetime.now())
r2 = Role(name='test2',merchant=m2,created_at=datetime.datetime.now())
r1.save()
#created True
#return value 1

r2.save()
#created False
#created false
#return value 2

#data in Role table:
id  name  ref_id  merchant_id
 3  test1   1       2
 4  test2   2       2

Вопрос

Что произошло в первой записи? и почему запись merchant2 верна? Wi sh кто-то может мне помочь с этим .. и кстати, это лучший способ решить эту проблему? Я также попытался UUID, HashID, но вывод не то, что я хочу.

...