2011-04-10 9 views
11

Chcę zapisać wszystko, co może być użyte do statystyk, takie jak referrer, os, przeglądarka itp. Co jest dostępne i jaki jest najlepszy sposób jego przechowywania?Django zapisuje cały wniosek o statystyki, co jest dostępne?

Jest to ważne tylko dla 1 aplikacji (1 strona) w projekcie, a na innych stronach będzie używany standardowy produkt analityczny, na przykład google analytics.

Spojrzałem na śledzenie django, ale wygląda na to, że jest to przesada, ponieważ chcę go używać tylko w widoku 1. Idealną sytuacją byłoby przekazanie całego obiektu żądania do TaskQue i późniejsze przetworzenie. Zatem użytkownik jest najpierw przekierowywany, a przetwarzanie danych analitycznych odbywa się za kulisami.

Odpowiedz

12

Używamy prostego oprogramowania pośredniego. Poniżej znajduje się fragment. Możesz go zmodyfikować, aby korzystać bezpośrednio z widoku.

class WebRequest(models.Model): 
    time = models.DateTimeField(auto_now_add=True) 
    host = models.CharField(max_length=1000) 
    path = models.CharField(max_length=1000) 
    method = models.CharField(max_length=50) 
    uri = models.CharField(max_length=2000) 
    status_code = models.IntegerField() 
    user_agent = models.CharField(max_length=1000,blank=True,null=True) 
    remote_addr = models.IPAddressField() 
    remote_addr_fwd = models.IPAddressField(blank=True,null=True) 
    meta = models.TextField() 
    cookies = models.TextField(blank=True,null=True) 
    get = models.TextField(blank=True,null=True) 
    post = models.TextField(blank=True,null=True) 
    raw_post = models.TextField(blank=True,null=True) 
    is_secure = models.BooleanField() 
    is_ajax = models.BooleanField() 
    user = models.ForeignKey(User,blank=True,null=True) 

def dumps(value): 
    return json.dumps(value,default=lambda o:None) 

class WebRequestMiddleware(object): 
    def process_view(self, request, view_func, view_args, view_kwargs): 
     setattr(request,'hide_post',view_kwargs.pop('hide_post',False)) 


    def process_response(self, request, response): 

     if request.path.endswith('/favicon.ico'): 
      return response 

     if type(response) == HttpResponsePermanentRedirect and settings.APPEND_SLASH: 
      new_location = response.get('location',None) 
      content_length = response.get('content-length',None) 

      if new_location and content_length is '0': 
       new_parsed = urlparse(new_location) 

       old = (('http','https')[request.is_secure()], request.get_host(), '{0}/'.format(request.path), request.META['QUERY_STRING']) 
       new = (new_parsed.scheme, new_parsed.netloc, new_parsed.path, new_parsed.query) 

       if old == new: 
        #dont log - it's just adding a/
        return response 
     try: 
      self.save(request, response) 
     except Exception as e: 
      print >> sys.stderr, "Error saving request log", e 

     return response 

    def save(self, request, response): 
     if hasattr(request, 'user'): 
      user = request.user if type(request.user) == User else None 
     else: 
      user = None 

     meta = request.META.copy() 
     meta.pop('QUERY_STRING',None) 
     meta.pop('HTTP_COOKIE',None) 
     remote_addr_fwd = None 

     if 'HTTP_X_FORWARDED_FOR' in meta: 
      remote_addr_fwd = meta['HTTP_X_FORWARDED_FOR'].split(",")[0].strip() 
      if remote_addr_fwd == meta['HTTP_X_FORWARDED_FOR']: 
       meta.pop('HTTP_X_FORWARDED_FOR') 

     post = None 
     uri = request.build_absolute_uri() 
     if request.POST and uri != '/login/': 
      post = dumps(request.POST) 

     models.WebRequest(
      host = request.get_host(), 
      path = request.path, 
      method = request.method, 
      uri = request.build_absolute_uri(), 
      status_code = response.status_code, 
      user_agent = meta.pop('HTTP_USER_AGENT',None), 
      remote_addr = meta.pop('REMOTE_ADDR',None), 
      remote_addr_fwd = remote_addr_fwd, 
      meta = None if not meta else dumps(meta), 
      cookies = None if not request.COOKIES else dumps(request.COOKIES), 
      get = None if not request.GET else dumps(request.GET), 
      post = None if (not request.POST or getattr(request,'hide_post') == True) else dumps(request.POST), 
      raw_post = None if getattr(request,'hide_post') else request.raw_post_data, 
      is_secure = request.is_secure(), 
      is_ajax = request.is_ajax(), 
      user = user 
     ).save() 
+0

Podziękowania To jest niesamowite kod. Oszczędzi mi dużo pracy! Tylko jedno pytanie dotyczące modeli. Czy używasz MySQL? Czy stworzy to VARCHAR (1000)? Wystarczy spojrzeć na dokumentację tutaj: http://docs.djangoproject.com/en/dev/ref/databases/#notes-on-specific-fields –

+0

Używamy Oracle, więc TextField (jeśli to właśnie Ty " odnoszą się do) jest NLOB. –

+0

Miałem na myśli host = models.CharField (max_length = 1000). Poza tym dlaczego wyraźnie kopiujesz META? meta = request.META.copy() –

1

Po prostu ręcznie wyciągnij go z żądania.

Dokumenty opisują wiele informacji, które można pobrać z obiektu żądania.

Na przykład nagłówki są przechowywane w request.META GET params w request.GET itp
http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Jaki jest najlepszy sposób, aby go zapisać? Zależy od tego, co robisz. Zaloguj się, zapisz w DB, wyślij gdzieś indziej ... Mówisz dla statystyk, więc baza danych brzmi jak dobre miejsce na umieszczenie tego, ponieważ łatwo jest zapytać.

+0

Które bazy danych MySQL lub MongoDB jako dane będą ogromne? Lub wiele baz danych MySQL, z których jedna jest przeznaczona do przechowywania danych dotyczących wniosków? –

0

Rozszerzenie na odpowiedź Josh, można użyć JSONField dla danych post, jeśli używasz postgres jako backend. Pomoże to w bezpośredniej pracy z jsonem, a nie ręcznym ładowaniem.

czytaj więcej: https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#jsonfield

można zrobić coś takiego

from django.contrib.postgres.fields import JSONField 

class WebRequest(models.Model): 
    post = JSONField(default=dict) 
Powiązane problemy