前置き
Djangoチュートリアルを終えてちまちまと自分用にカスタマイズしているくらいの初心者です。その過程で自動テストを追加しようとチュートリアルを再度確認していると、以下のような記述が。
テストを追加することによって、同じように他の方法でアプリを改善できるでしょう。例えば、Choices を一つも持たない馬鹿げた Questions が公開可能になっています。このような Questions を排除するようビューでチェックできます。 Choices がない Question を作成し、それが公開されないことをテストし、同じようにして、Choices がある Question を作成し、それが公開 される ことをテストすることになるでしょう。
(引用元:さらなるテストについて考える)
自分は英単語と日本語を1:Mで対応させたモデルを使っているので、"対応する日本語を一つも持たない馬鹿げた英単語が公開可能になっている"状態です。
その手の表示を弾きたいだけなら、htmlファイル側でテンプレートタグを使い、適当なif処理でもさせればよいです。が、今回は公式のテストでも利用されているassertQuerysetEqualを使いたかった、というより他のテスト手法がわからなかったので、view側でQuerysetを送信する段階で弾くことにしました。
参考サイト様
コード
class EnglishWord(models.Model):
spell = models.CharField(max_length=30)
pub_date = models.DateTimeField('date published')
difficulty = models.IntegerField(default=0)
def __str__(self):
return self.spell
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published Recently?'
class JapaneseWord(models.Model):
english_word = models.ForeignKey(EnglishWord, on_delete=models.CASCADE)
japanese_mean = models.CharField(max_length=50)
difficulty = models.IntegerField(default=0)
def __str__(self):
return self.japanese_mean
from django.db.models import Count
class IndexView(generic.ListView):
template_name = 'wordapp/index.html'
context_object_name = 'latest_english_word_list'
def get_queryset(self):
return EnglishWord.objects.annotate(count=Count('japaneseword')).filter(count__gt=0)
annotateで臨時のカラムを設けて、そこにカウントした件数を格納し、格納した件数で条件を設定する、といった感じだと思います。あとは後ろにチュートリアルどおりにorder_byを付け加えるなりなんなりできそうです。
終わりに
多分SQLを含めたデータ処理に慣れている人にとっては当たり前の話なのでしょうが、3時間ほど詰まったので備忘録代わりに。もっと上手いやり方がありそうな気配がしますが、とりあえず希望通りに動いたのでヨシ。集合知に感謝。