2

Я пытаюсь создать промежуточную модель с полем created, записывающим время следующего отношения.QuerySet промежуточных моделей order_by

модели выглядит следующим образом:

class Profile(models.Model): 
    user = models.OneToOneField(User, related_name='profile') 
    realname = models.CharField(max_length=20, verbose_name='真實姓名', blank=True) 
    nickname = models.CharField(max_length=20, verbose_name='暱稱/顯示名稱') 

## the intermediate model is connected through following field ## 
    followings = models.ManyToManyField('self', through='FollowShip', 
             related_name='followers', symmetrical=False, 
             through_fields=('profile_from', 'profile_to')) 

    total_followers = models.IntegerField(default=0) 

    def __str__(self): 
     return 'Profile of User:{}'.format(self.user.username) 


class FollowShip(models.Model): 
    profile_from = models.ForeignKey(Profile, related_name='follow_from_set') 
    profile_to = models.ForeignKey(Profile, related_name='follow_to_set') 
    created = models.DateField(auto_now_add=True, db_index=True) 

    def __str__(self): 
     return "{} follows {}".format(self.profile_from, self.profile_to) 

    class Meta: 
     unique_together = ('profile_from', 'profile_to') 

Он отлично работает. Однако, когда я попытался получить доступ к порядку QuerySet на created, поле FollowShip. Произошла ошибка.

В manage.py shell:

>>> user.profile.followings.order_by('followship__created') 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/query.py", line 232, in __repr__ 
    data = list(self[:REPR_OUTPUT_SIZE + 1]) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/query.py", line 256, in __iter__ 
    self._fetch_all() 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/query.py", line 1087, in _fetch_all 
    self._result_cache = list(self.iterator()) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/query.py", line 54, in __iter__ 
    results = compiler.execute_sql() 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 824, in execute_sql 
    sql, params = self.as_sql() 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 369, in as_sql 
    extra_select, order_by, group_by = self.pre_sql_setup() 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 47, in pre_sql_setup 
    order_by = self.get_order_by() 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 293, in get_order_by 
    field, self.query.get_meta(), default_order=asc)) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 553, in find_ordering_name 
    field, targets, alias, joins, path, opts = self._setup_joins(pieces, opts, alias) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 586, in _setup_joins 
    pieces, opts, alias) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1402, in setup_joins 
    names, opts, allow_many, fail_on_missing=True) 
    File "/Users/young/Desktop/env/strayvoice/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1327, in names_to_path 
    "Choices are: %s" % (name, ", ".join(available))) 
django.core.exceptions.FieldError: Cannot resolve keyword 'followship' into field. Choices are: follow_from_set, follow_to_set, followers, followings, id, nickname, realname, total_followers, user, user_id 

Похоже, что промежуточная модель не была установлена ​​правильно. Так что я не могу найти followship во время запроса. Однако я могу получить доступ к обеим сторонам хорошо. Примеры:

>>> user.profile.followings.all() 
`<QuerySet [<Profile: Profile of User:222222>, <Profile: Profile of User:333333>]>` 
>>> user.profile.followers.all() 
`<QuerySet [<Profile: Profile of User:222222>]>` 

Не имеют никаких намеков, что идут не так.

+0

То же сообщение об ошибке. Похоже, что отношение m2m относится к «я» с промежуточной моделью, действующей отличной от ориентации на другую модель. – JianWei

ответ

1

Использование p.follow_from_set.order_by('created').

user.profile.followings - описание профиля который следил за user.profile.
user.profile.followers - профиль, которые следят за user.profile.
Таким образом, как user.profile.followers, так и user.profile.followings вернут запрос Profile, их можно заказывать только по полям Profile, таким как имя пользователя, имя, псевдоним.

Если вы хотите, чтобы найти профиль, который был последующим use.profile и order_by created, вы можете использовать:

result = [] 
for profile_id in user.profile.follow_from_set.order_by('created').values('profile_to'): 
    result.append(Profile.objects.get(id=profile_id)) 

Если есть много следующий, может быть, вы можете оптимизировать SQL этим:

profile_ids = user.profile.follow_from_set.order_by('created').values('profile_to') 
profiles = Profile.objects.filter(id__in=profile_ids) 

FInally, измените порядок профилей с помощью параметра profile_ids.

result = [] 
result_dict = {} 
for profile in profiles: 
    result_dict[profile.id] = profile 
for id in profile_ids: 
    result.append(result_dict[id]) 
return result 

Возможно, есть много лучшего способа решить эту проблему. Может ли кто-нибудь сделать лучшее разрешение?

+0

См. Последнюю часть документа [django] (https://docs.djangoproject.com/en/1.10/topics/db/models/#intermediary-manytomany). Я предположил, что могу запросить, как '>>> Person.objects.filter ( ... group__name = 'The Beatles', ... membership__date_joined__gt = date (1961,1,1))' как говорится в документе. – JianWei

+0

Ваш путь работает. Но для этого я должен добавлять хиты в базу данных несколько раз, стоимость огромная. – JianWei

+0

Номер запроса. Profile.objects.filter (followers__nickname__contains = '') 'похоже на то, что вы рекомендовали. Здесь вы можете захотеть что-то вроде 'Profile.objects.filter (follower_from_set__created__lt = datetime.date (2016,1,1))' или 'Profile.objects.filter (followers__created__lt = datetime.date (2016,1,1))' (ни один из двух не работал) – ramwin