2016-09-20 9 views
0

그래서,고유 한 두 개의 키가있는 장고 모델에 대한 자동 증가 필드를 만드는 방법은 무엇입니까?

class Item(models.Model): 
    site = Site() 
    id_on_site = PositiveIntegerField() 

같은 모델은 지금은 ID를 생성하고, Item를 만드는 작업이 원이 아니라고,

next_id_on_site = Item.objects.filter(site=current_site).aggregate(current_id=Max("id_on_site"))['current_id']+1 

문제가 함께 인스턴스 Item(current_site, next_id_on_site)을 만들려 가지고 중복 ID를 만드는 경쟁 조건이 있으므로 .get(site=current_site, id_on_site=someid)MultipleObjectsReturned 예외를 발생시킵니다.

모델에서 unique_together을 사용하면 자동 증가 ID 생성에 도움이되지 않으며 DB 수준에서 전혀 구현되지 않은 것으로 보입니다.

+0

id_on_site는 자동 생성 ID입니까? –

답변

1

unique_together이 데이터베이스에 구현되어 있지만 고유 한 데이터베이스 색인이 생성되므로 마이그레이션을 실행하여 효과를 확인해야 할 수도 있습니다.

경우 당신이 원하는 모든id_on_site 사이트에있는 항목에 대한 몇 가지 고유 한 식별자하는 것은 고유성의 거의 확실한 보장이있는 UUIDField(default=uuid.uuid4), 같은 것을 사용하는 것이 더 쉬울 수도 있습니다. ID가 자동으로 증가하는 정수가 필요한 경우 조금 더 어렵습니다.

경쟁 조건을 피하기위한 한 가지 옵션은 가장 높은 행을 잠그는 것입니다 (id_on_site). 이것은 그들이 가장 높은 id_on_site을 얻으려고 노력하는 경우 차단하는 다른 트랜잭션을 야기한다

from django.db.transaction import atomic 

with atomic(): 
    next_id_on_site = (
     Item.objects 
     .filter(site=current_site) 
     .select_for_update(nowait=False) 
     .latest('id_on_site').id_on_site) 
    Item.objects.create(current_site, next_id_on_site) 

및 트랜잭션이 커밋되면, 당신은 단지 삽입 된 항목은 다음과 같습니다 (이것은 단지 certain database backends, 예를 들어 포스트 그레스에서 작동합니다) 다른 트랜잭션으로 리턴됩니다. 어떤 이유로 트랜잭션이 오래 지속되면 문제가 될 수 있습니다.

+0

나는이 숫자가 사이트의 사용자에게 보여주고 싶은 정수이기 때문에 증가하는 정수를 사용하고 싶다. 내가 원자와 노력,하지만 그것은 MySQL과 함께 작동하지 않는 것 같아요. 현재 잘못된 ID로 항목을 저장 한 다음 최대 ID를 집계하여''Item.objects.filter (id = newitem.id) .update (id_on_site = new_id)''를 실행하는 것입니다. .save()''하지만 여전히 집계와 업데이트간에 경쟁 조건이 발생합니다. docs는''select_for_update''가 postres와 같은 멋진 트랜잭션을 가지고 있지 않은 경우에도 mysql에서 작동해야합니다. 나는 그것을 시도 할 것이다. – allo

+0

원자는 두 데이터베이스 백엔드 모두에서 작동하지만 경쟁 조건은 해결되지 않습니다. 잠금 접근 방식이 작동하지 않으면 원시 SQL 쿼리를 작성하여 행을 업데이트하는 것이 좋습니다. Django의 ORM에서 표현하기 힘든 단순한 SQL 문이어야합니다. – RecursivelyIronic

+0

업데이트에 대해,'.filter (...). update (...)''라인은 단지 하나의''UPDATE ... WHERE ...''문을 생성합니다. – allo