2013-03-13 25 views
11

Uygulamanızı prefetch_related ile hızlandırmaya çalışıyoruz. GenericForeignKey ilişkilerini izleyebilir ve __ ile daha derine gidebilir ancak maalesef ilgili modelde böyle bir alan yoksa başarısız olur. İşte Aynı DB sütuna ait birden çok alan

class ModelA(models.Model): 
    event_object = models.ForeignKey(SomeModelA) 

class ModelB(models.Model): 
    event = models.ForeignKey(SomeModelB) 

class ModelC(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey() 

Yani ModelC örneği ModelA veya ModelB ya işaret edebilir modeli yapının bazı örnektir. Ve ben hem A ve B modellerini önceden getirmek için böyle Sorgu Kümesi kullanabilirsiniz: ModelC.objects.all().prefetch_related('content_object') Maalesef ben de olay nesneyi seçmek gerekir (SomeModelA veya SomeModelB)

Ben

ModelC.objects.all().prefetch_related('content_object', 'content_object__event_object') 

İşe yarayacak çalıştırmayı denerseniz eğer ModelA işaret sadece ModelC örneklerini var, ama ModelBevent_object alanı var ve bunun yerine event yok çünkü DİĞER ÖN durumda, başarısız olur.

Bu modeller, kod genelinde birçok yerde kullanılır, böylece alanı yeniden adlandırmak iyi bir fikir değildir. Bu yüzden bir alan/sütun için bir takma ad oluşturmanın bir yolu olup olmadığını merak ediyorum.

böyle yapmaya çalıştığım:

class ModelB(models.Model): 
    event = models.ForeignKey(SomeModelB) 
    event_object = models.ForeignKey(SomeModelB, db_column='event_id', related_name='+') 

DB tablosundaki aynı sütuna işaret iki alan yapmak için. Ancak bu, save yöntemini kırdığı için çalışmıyor. Django, bir sütunun iki kez yerleştirildiği ve bir DatabaseError

Aldığı UPDATE SQL sorgusu oluşturur Bu takma ad oluşturmanın bir yolu var mı? Ya da belki bir istisna atmamak için prefetch_related yapmak için başka bir çözüm var mı?

Güncelleme: save yöntemde bu alanı dışlamak için kullanılabilecek bir update_fields parametre vardır. Ancak 1.5’te tanıtıldı ve 1.4 kullanıyoruz. Bu yüzden bir cevap aramaya devam ediyorum.

Güncelleştirme # 2: @ shx2 bana bir traceback vermemi istedi. 2 olası geri dönüş var. 1 - nitelik birinci nesne üzerinde eksik olduğunda:

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__ 
    data = list(self[:REPR_OUTPUT_SIZE + 1]) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__ 
    len(self) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__ 
    self._prefetch_related_objects() 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects 
    prefetch_related_objects(self._result_cache, self._prefetch_related_lookups) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1664, in prefetch_related_objects 
    (attr, first_obj.__class__.__name__, lookup)) 
AttributeError: Cannot find 'event_object' on ModelB object, 'content_object__event_object' is an invalid parameter to prefetch_related() 

Ve prefetch_related parametreler daha sonra ilk nesne için geçerli olup olmadığını ben 2 Traceback olsun

:

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__ 
    data = list(self[:REPR_OUTPUT_SIZE + 1]) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__ 
    len(self) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__ 
    self._prefetch_related_objects() 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects 
    prefetch_related_objects(self._result_cache, self._prefetch_related_lookups) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1680, in prefetch_related_objects 
    obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr) 
    File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1803, in prefetch_one_level 
    qs = getattr(obj, attname).all() 
AttributeError: 'ModelB' object has no attribute 'event_object' 
+0

'prefetch_related' hatasının izini ekleyebilirsiniz. – shx2

+0

Neden bir ModelC queryset'e ihtiyacınız var? Sadece 2 farklı sorgu yapabilir ve ayrı ayrı tedavi edemez misiniz? Benim sorumun biraz naif olduğunu biliyorum, ama bazen sorun şu ki bu zorluklarla yüz yüze geldiğimiz için – marianobianchi

+0

@marianobianchi no, django yöneticisinin bir kısmını optimize etmeye çalışıyoruz, bu yüzden tek bir sorgulamaya ihtiyacımız var. Ayrıca yukarıdaki modeller basitleştirilmiş, gerçek proje – Igor

cevap

2

Bir hata veya gözetimi benziyor django içinde. Geçici bir çözüm olarak, bir 2 aşamalı önceden getirilmesini yapan bir özel yöneticisi tanımlayan deneyebilirsiniz.

from django.db import models 
from django.db.models import Q 
from django.contrib.contenttypes.models import ContentType 

class PrefetchWorkaroundManager(models.Manager): 
    def get_queryset(self): 
     q = super(PrefetchWorkaroundManager, self).get_queryset() 
     content_typeA = ContentType.objects.get_for_model(ModelA) 
     content_typeB = ContentType.objects.get_for_model(ModelB) 
     return q.filter(content_type__pk = content_typeA.id).prefetch_related('content_object', 'content_object__event_object') | \ 
       q.filter(content_type__pk = content_typeB.id).prefetch_related('content_object', 'content_object__event') 

class ModelC(models.Model): 
    ... 

    objects_prefetched = PrefetchWorkaroundManager() 

ModelC.objects yerine ModelC.objects_prefetched erişmek gerekir gerçekleşmesi önceden getirilmesini isteyen her Arayan:

ModelC.objects_prefetched.filter(...) 

Muhtemelen olduğu gibi çalışmıyor bu yüzden, bunu test vermedi, kabul ediyorum. Ama bu yaklaşım ses olduğuna inanıyoruz.

+0

daha derin ilişkileri var Cevabı için teşekkürler, ama ne yazık ki işe yaramıyor. Querysets üzerinde '|' kullandığınızda, yeni bir queryset oluşturur. Ve queryset'in kendisi değerlendirildiğinde 'prefetch_related' değerlendirilir. Ayrıca, Django'da hata olup olmadığından emin değilim, ancak '' 'kullandığınızda, yalnızca ilk sorgudan prefetch aramaları kullanır – Igor

İlgili konular