GÜNCELLEME: 24272Django GenericRelation ile çalışmak gerekiyordu prefetch_related mi
tüm ilgili neler var: Bu konuda Bir Açık Çok keyifli?
Django ekleyen GenericRelation sınıfına sahiptir ek API etkinleştirmek için jenerik bir ilişki “ters”.
Biz filtering
veya ordering
için bu reverse-generic-relation
kullanabilirsiniz çıkıyor, ama biz prefetch_related
içine kullanamaz.
Bunun bir hata mı, yoksa çalışması gerekmiyor mu, yoksa özellikte uygulanabilecek bir şey mi olduğunu merak ediyordum.
Size ne demek istediğimi örneklerle göstereyim.
İki ana modelimiz olduğunu varsayalım: Movies
ve Books
.
Movies
birDirector
Books
birAuthor
var olması Ve biz Movies
ve Books
bizim etiket atamak istediğiniz, ancak bunun yerine MovieTag
ve BookTag
modellerini kullanarak nedeniyle, tek kullanmak istiyorum sınıfı, GFK
- Movie
veya Book
.
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.tag
class Director(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class Movie(models.Model):
name = models.CharField(max_length=100)
director = models.ForeignKey(Director)
tags = GenericRelation(TaggedItem, related_query_name='movies')
def __unicode__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(Author)
tags = GenericRelation(TaggedItem, related_query_name='books')
def __unicode__(self):
return self.name
Ve bazı ilk veri:
>>> from tags.models import Book, Movie, Author, Director, TaggedItem
>>> a = Author.objects.create(name='E L James')
>>> b1 = Book.objects.create(name='Fifty Shades of Grey', author=a)
>>> b2 = Book.objects.create(name='Fifty Shades Darker', author=a)
>>> b3 = Book.objects.create(name='Fifty Shades Freed', author=a)
>>> d = Director.objects.create(name='James Gunn')
>>> m1 = Movie.objects.create(name='Guardians of the Galaxy', director=d)
>>> t1 = TaggedItem.objects.create(content_object=b1, tag='roman')
>>> t2 = TaggedItem.objects.create(content_object=b2, tag='roman')
>>> t3 = TaggedItem.objects.create(content_object=b3, tag='roman')
>>> t4 = TaggedItem.objects.create(content_object=m1, tag='action movie')
Yani
docs gösterisi olarak böyle şeyler yapabilirim İşte
modeli yapıdır. Bu
reverse generic relation
aracılığıyla
prefetch
TaggedItem
bazı
related data
çalışırsanız
>>> b1.tags.all()
[<TaggedItem: roman>]
>>> m1.tags.all()
[<TaggedItem: action movie>]
>>> TaggedItem.objects.filter(books__author__name='E L James')
[<TaggedItem: roman>, <TaggedItem: roman>, <TaggedItem: roman>]
>>> TaggedItem.objects.filter(movies__director__name='James Gunn')
[<TaggedItem: action movie>]
>>> Book.objects.all().prefetch_related('tags')
[<Book: Fifty Shades of Grey>, <Book: Fifty Shades Darker>, <Book: Fifty Shades Freed>]
>>> Book.objects.filter(tags__tag='roman')
[<Book: Fifty Shades of Grey>, <Book: Fifty Shades Darker>, <Book: Fifty Shades Freed>]
Ama, biz bir AttributeError almak için gidiyoruz.
>>> TaggedItem.objects.all().prefetch_related('books')
Traceback (most recent call last):
...
AttributeError: 'Book' object has no attribute 'object_id'
Ben sadece yerine burada books
ait content_object
kullanmayın neden Bazılarınız sorabilir miyim acaba? Nedeni, çünkü bu yalnızca aşağıdakileri yapmak istediğimizde çalışır: 1) querysets
'dan yalnızca bir düzey, farklı türde content_object
içeren.
>>> TaggedItem.objects.all().prefetch_related('content_object')
[<TaggedItem: roman>, <TaggedItem: roman>, <TaggedItem: roman>, <TaggedItem: action movie>]
2) prefetch
pek çok düzeyde fakat querysets
den content_object
yalnızca bir türünü içeren.ikimiz de 1 istiyorum) ve content_objects
farklı içeren queryset
2) (için prefetch
birçok seviyeleri ise
content_object
.
>>> TaggedItem.objects.all().prefetch_related('content_object__author')
Traceback (most recent call last):
...
AttributeError: 'Movie' object has no attribute 'author_id'
Django
content_objects
düşünüyor
Books
olup, bu nedenle
Author
.
Şimdiiçin istediğimiz durumu hayal edin.sadece books
author
, aynı zamanda onların director
ile movies
onların ile. İşte birkaç deneme.
saçma yolu:
>>> TaggedItem.objects.all().prefetch_related(
... 'content_object__author',
... 'content_object__director',
...)
Traceback (most recent call last):
...
AttributeError: 'Movie' object has no attribute 'author_id'
Belki özel ile Prefetch
nesne?
>>>
>>> TaggedItem.objects.all().prefetch_related(
... Prefetch('content_object', queryset=Book.objects.all().select_related('author')),
... Prefetch('content_object', queryset=Movie.objects.all().select_related('director')),
...)
Traceback (most recent call last):
...
ValueError: Custom queryset can't be used for this lookup.
bu sorunun bazı çözümler here gösterilmiştir. Ama kaçınmak istediğim veriler üzerinde çok fazla masaj var. Gerçekten reversed generic relations
gelen API gibi, böyle prefetchs
yapabilmek için çok güzel olurdu:
>>> TaggedItem.objects.all().prefetch_related(
... 'books__author',
... 'movies__director',
...)
Traceback (most recent call last):
...
AttributeError: 'Book' object has no attribute 'object_id'
Ya böyle
:>>> TaggedItem.objects.all().prefetch_related(
... Prefetch('books', queryset=Book.objects.all().select_related('author')),
... Prefetch('movies', queryset=Movie.objects.all().select_related('director')),
...)
Traceback (most recent call last):
...
AttributeError: 'Book' object has no attribute 'object_id'
Ama gördüğünüz gibi, biz uzağa o AttributeError olsun. Django 1.7.3
ve Python 2.7.6
kullanıyorum. Ve Django'nun bu hatayı neden attığını merak ediyorum? Neden Django, Book
modelinde object_id
modelini arıyor? Neden bu bir hata olabilir sence?
>>> TaggedItem.objects.all().prefetch_related('some_field')
Traceback (most recent call last):
...
AttributeError: Cannot find 'some_field' on TaggedItem object, 'some_field' is an invalid parameter to prefetch_related()
Ama burada durum farklı: biz olamaz şey çözmek için prefetch_related
sorduğunuzda Genellikle görürüz. Django aslında ilişkiyi çözmeye çalışır ve başarısız olur. Bu bildirilmesi gereken bir hata mı? Django'ya hiç bir şey bildirmedim, işte bu yüzden önce burada soruyorum. Hatayı izleyemiyorum ve bunun bir hata mı, yoksa uygulanabilecek bir özellik mi olduğuna kendim karar veremiyorum. Eğer Book
örneklerini almak ve ilgili etiketler Book.objects.prefetch_related('tags')
kullanmak ön getirmek istiyorsanız
Tamam Django Kaynak bakarak Söyleyebilirm kullanmak gerekir kitapları yazarları almak istiyorsanız bu bir hata, ama sadece ... desteklenmez 'select_related()' Bu bir 'ForeignKey' ilişki olduğu gibi. Bunu “prefetch_related” ile birlikte kullanmak için, şu anda [desteklenmeyen] özel bir queryset kullanmanız gerekir (https://github.com/django/django/blob/84b6c768301096849f5589d7612b129c5445abd3/django/contrib/contenttypes/fields.py# L170) Django tarafından jenerik ilişkiler için. –
Tamam, teşekkürler. Bu konuda [bir bilet açtım] (https://code.djangoproject.com/ticket/24272). Bu özellik ORM aracılığıyla yapacaktır birgün Umut:) – Todor