2011-08-29 5 views
2

장고 초보자. 임씨는 Uni에서 웹 프로그래밍 과정을 배정 받았다.장고 페이지 방문 카운터 동시성

from django.db import models 

# Create your models here. 

class HitCount(models.Model): 
    count = models.IntegerField() 

그리고 내가보기 파일에이 코드를 사용 :

<p>{{count}}</p> 

이 작동하는 것 같다 : 이것은 내 index.html 파일이

def index(request): 

    #try getting a hitcounter, if there is none, create one 
    try: 
     hc = HitCount.objects.get(pk=1) 
    except: 
     hc = HitCount(count=0) 
     hc.save() 
     pass 

    #get a queryset containing our counter 
    hc = HitCount.objects.filter(pk=1) 
    #increment its count and update it in db 
    hc.update(count=F('count')+1) 
    #ATM hc is a queryset, so hc.count will just return how many 
    #counters are in the queryset (1). So we have to get the 
    #actual counter object 
    hc = HitCount.objects.get(pk=1) 
    #and return its count 
    return render_to_response('hitcount/index.html', {'count': hc.count}) 

이다 나는 클래스 HitCount했다 그냥 괜찮아요,하지만 궁금해 :

  • 이것은 합리적인 방법인가요? 이러는거야? 증분 코드가 실제로 뷰 파일에 있어야합니까? 아니면 클래스의 메서드로 옮겨야합니까?
  • 이 동시성은 안전합니까? 아니면 어떤 종류의 잠금을 사용해야합니까? 과제의 일부는 카운터의 동시성을 안전하게하는 것입니다. 트랜잭션을 사용하는 SQLite를 사용하므로 문제가없는 것으로 생각했지만 뭔가 누락되었을 수 있습니다.
+1

거래가 자동으로 사용되지 않습니다.MySQL을 사용한다면 ORM의 멋진 점을 제거 할지라도 이것은 단일 질의로 수행 될 수 있습니다 : INSERT INTO hitcount (id, count) VALUES (1,1) ON DUPLICATE KEY UPDATE count = count +1 '이다. 이렇게하면 트랜잭션이 필요 없습니다. (오라클이나 SQL 서버에서는'MERGE INTO'를, PostgreS에서는 UDF를 사용할 수 있습니다.) –

+0

입력에 유쾌합니다. 조금 더 확장 해 주시겠습니까? 예 : 어떻게 거래를 강제로 사용합니까? 그리고 수동 쿼리를 사용하면 트랜잭션이 필요하지 않습니다. 그렇다면 두 개의 쿼리가 동시에 수행되어 오류가 발생할 위험이 있습니까? – fred

+1

Django가 트랜잭션을 처리하는 방법과 Django를 가질 수있는 방법에 대한 정보는 [here] (https://docs.djangoproject.com/en/dev/topics/db/transactions/#django-s-default-transaction-behavior)를 참조하십시오. 자동으로 트랜잭션을 사용합니다. 나의 대체 제안에 관해서는, 각 갱신은 단일 명령문에서 수행되고 데이터베이스 서버에 의해 원자 단위로 처리되므로 트랜잭션이 없습니다. –

답변

3

주제에서 벗어나지 만, 실제로는 HitCount 객체가 아직 존재하지 않는 경우를 제외하고는 코드를 실행하고 싶기 때문에 try/except에서 HitCount.DoesNotExist을 잡아야합니다.

히트 카운터를 사용하려면 Redis (또는 다른 키/발점)과 같은 것을 볼 수 있습니다.

Redis은 자동으로 값을 1 씩 증가시키는 INCR이라는 메서드를 제공합니다.이 메서드는 매우 빠르고 위와 같은 카운터를위한 훌륭한 솔루션입니다. 페이지와 관련된 키를 만드는 것만으로 +1 할 수 있습니다.

페이지 히트를 추적하려면 middleware 클래스를 사용하는 것이 더 적절할 수도 있습니다. 모든보기에 추가하는 것보다 훨씬 쉽습니다. 모든 페이지에이 개수를 표시해야하는 경우 context processor (more info)을 사용하여 페이지의 방문 횟수를 컨텍스트에 추가 할 수 있습니다. 이렇게하면 코드 반복이 줄어 듭니다.

편집

내가 처음에 이것이 유니 프로젝트 것을 놓친, 그래서 이것은 당신이 필요 엔지니어링을 통해 크게 될 수 있습니다. 그러나 프로덕션 환경에서 히트 카운터를 만드는 경우 이것이 내가 권장하는 것입니다. 미들웨어/컨텍스트 프로세서를 사용하여 DRY 방식으로 히트 카운트/검색을 수행 할 수 있습니다.

+0

훌륭한 답변과 훌륭한 정보입니다! Redis가이 특별한 경우에 약간의 잔인 함을 느낄 수도 있지만 필자는 코드의 일부를 미들웨어 클래스로 옮기는 방법에 대해 살펴볼 것입니다. 더 나은 디자인이라고 느낍니다. 당신이 내 질문에 틀림없이 대답하는 정보를 제게 제공했기 때문에이 질문을 받아 들인 대답으로 표시 할 것입니다. – fred

+0

감사합니다. 프레드, 프로젝트에 행운을 빕니다. –

0

각 히트에 대해 새 데이터베이스 행을 만들고 HitCount.objects.count()를 호출하여 개수를 가져올 수 있습니다.

+0

당신의 공헌에 감사드립니다 만, 틀림없이 더 간단하고 가벼워서 개체 수를 단순히 늘릴 수 있습니다. – fred

2

잠금은 다음과 같은 사용하여 파이썬에서 가능하다 :

lock = Lock() 
lock.acquire() 
try: 
    ... access shared resource 
finally: 
    lock.release() # release lock, no matter what 

이 방법은 그러나 다중 서버 환경에서 안전하지 있음을 유의하십시오.

각 히트를 관련 정보가있는 db의 행으로 추적 한 다음 특정 날짜 범위에서도 카운트/쿼리 할 수있는보다 확장 성있는 '로깅'솔루션을 만들 수도 있습니다.

+0

고마워, 나는 이것을 내 코드에 구현할 것이다! – fred