目標
目標是根據模型中的另一個欄位,按視圖中三個不同日期欄位之一有條件地對 QuerySet 進行排序。由于 Class Meta 無法完成條件排序,因此我正在探索在視圖中實作此目標。
以下是相關摘錄models.py:
READING_PROGRESS = [
('---', '---'),
('1) On Reading List', '1) On Reading List'),
('2) Reading In Progress', '2) Reading In Progress'),
('3) Completed Reading', '3) Completed Reading'),
]
class ReadingProgress(models.Model):
record = models.ForeignKey(
LibraryRecord,
related_name='record_in_reading_progress',
on_delete=models.CASCADE,
null=True,
blank=True,
verbose_name='Library record'
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
blank=True
)
reading_progress = models.CharField(
max_length=30,
choices=READING_PROGRESS,
default='---'
)
date_added = models.DateField(
auto_now=False,
auto_now_add=False,
null=True,
blank=True,
)
date_started = models.DateField(
auto_now=False,
auto_now_add=False,
null=True,
blank=True,
)
date_completed = models.DateField(
auto_now=False,
auto_now_add=False,
null=True,
blank=True,
)
class Meta:
ordering = [
'reading_progress',
]
verbose_name_plural = 'Reading Progress'
unique_together = ('record', 'user',)
# Record metadata
date_created = models.DateTimeField(
auto_now_add=True
)
def __str__(self):
return f'{self.record.title} - {self.reading_progress}'
模型中的相關欄位是:
reading_progressdate_addeddate_starteddate_completed
每個日期欄位對應一個狀態值。我希望能夠按欄位在視圖中 order_by 查詢集reading_progress:
- 當
reading_progress== '1) On Reading List' 然后按date_added - 當
reading_progress== '2) Reading In Progress' 然后按date_started - 當
reading_progress== '3) 完成閱讀' 然后按date_completed
到目前為止的研究
我做了一些研究,發現了一個看起來很有用的 QuerySet API,名為annotate(). 這看起來是要走的路(Django docs)。
但是,我的實作不起作用。這是我目前擁有的views.py:
reading_progress = ReadingProgress.objects.filter(user__username=self.request.user)\
.annotate(
date_to_display=Case(
When(reading_progress='1) On Reading List', then=F('date_added')),
When(reading_progress='2) Reading In Progress', then=F('date_started')),
When(reading_progress='3) Completed Reading', then=F('date_completed')),
output_field=DateField(),
)
).order_by(
'date_to_display'
)
Django 檔案似乎暗示:
- 我可以過濾
- 然后在過濾后的 QuerySet 上進行注釋
- 通過額外的研究,我得出結論,我可以將其用作在API
F()中實作查詢的一種方式annotate()
但是,我的實作并不完全奏效。這是報告 NameError 的 Traceback:
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/usr/local/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.10/site-packages/django/views/generic/base.py", line 84, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/views/generic/base.py", line 119, in dispatch
return handler(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/views/generic/list.py", line 174, in get
context = self.get_context_data()
File "/app/web/library/views.py", line 1280, in get_context_data
reading_progress = ReadingProgress.objects.filter(user__username=self.request.user).annotate(date_to_display=Case(When(reading_progress='1) On Reading List', then=F('date_added')),When(reading_progress='2) Reading In Progress', then=F('date_started')),When(reading_progress='3) Completed Reading', then=F('date_completed')),output_field=DateField(),)).order_by('date_to_display')
Exception Type: NameError at /reading_list/
Exception Value: name 'Case' is not defined
我覺得我很接近,但目前正在撓頭。我見過的示例片段使用了,Case但由于某種原因,我收到一個錯誤,說我沒有定義Case。這讓我相信,也許我正在以錯誤的方式處理這個問題。
歡迎任何見解或建議。
答案
從接受的答案中,views.py可以使用以下內容。我也洗掉output_field了所有三個被注釋的欄位都是相同的資料型別:
from django.db.models import Case, F, Q, Value, When
reading_progress = ReadingProgress.objects.filter(user__username=self.request.user)\
.annotate(
date_to_display=Case(
When(reading_progress='1) On Reading List', then=F('date_added')),
When(reading_progress='2) Reading In Progress', then=F('date_started')),
When(reading_progress='3) Completed Reading', then=F('date_completed')),
)
).order_by(
'reading_progress',
'date_to_display',
)
uj5u.com熱心網友回復:
您必須在其中匯入相關部分views.py
from django.db.models import Case, F, Q, Value, When
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/492967.html
