質問編集履歴
3
文章の修正
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Django
|
1
|
+
Djangoで従テーブルのクエリによるページネーションを実装したい
|
test
CHANGED
@@ -8,9 +8,7 @@
|
|
8
8
|
・Articleモデルのリレーションフィールド(post_user)では、下記サイトを参考に、テンプレート側で逆参照を出来るように、related_nameオプションを設定しています
|
9
9
|
https://qiita.com/ragnar1904/items/1afaeb6601cc490fb70a#%E9%80%86%E5%8F%82%E7%85%A7%E3%81%AE%E5%A0%B4%E5%90%88
|
10
10
|
|
11
|
-
```py
|
12
|
-
|
11
|
+
```models.py
|
13
|
-
|
14
12
|
class CustomUser(AbstractUser):
|
15
13
|
username = models.CharField(
|
16
14
|
_("username"),
|
@@ -43,9 +41,7 @@
|
|
43
41
|
・ビューではListViewを継承し、クラス変数```model```にはCustomUserを指定し、クラス変数```paginate_by```の指定も行う
|
44
42
|
・get_queryset()のオーバーライドでは、マイページのユーザに紐づくArticleモデルのクエリーセットをテンプレートへ渡すようにする
|
45
43
|
|
46
|
-
```py
|
47
|
-
|
44
|
+
```views.py
|
48
|
-
|
49
45
|
class MyPageView(LoginRequiredMixin, generic.ListView):
|
50
46
|
template_name = 'mypage.html'
|
51
47
|
model = CustomUser
|
@@ -59,9 +55,7 @@
|
|
59
55
|
**テンプレート**
|
60
56
|
・テンプレートでは、主テーブルCustomUserのクエリを```{% for s in customuser_list %}```で取り出し、従テーブルArticleのクエリを```{% for article in s.name.all %}```で取り出す。
|
61
57
|
|
62
|
-
```html
|
58
|
+
```mypage.html
|
63
|
-
|
64
|
-
<!--mypage.html-->
|
65
59
|
{% for s in customuser_list %}
|
66
60
|
<section class="u-content-space">
|
67
61
|
<div class="container">
|
@@ -132,7 +126,7 @@
|
|
132
126
|
|
133
127
|
ブラウザの検証ツールを用いてhtmlを確認してみたところ、ページネーションに関するコードが記載されていなかった為、テンプレートの`{% if is_paginated %}`がFalseだと判定されたのだと理解しました。
|
134
128
|
|
135
|
-
|
129
|
+
原因はviewsでのページネーションに関わるメソッドのオーバーライドで一工夫する必要があるかと考えましたが、調べても同じような事例を見つけることができず、どうすれば良いのか頭を抱えています。
|
136
130
|
|
137
131
|
### 試したこと
|
138
132
|
・ブラウザのキャッシュを削除し再度読み込みを行なってもページネーションの表示がされることはありませんでした。
|
2
文章の簡易化
test
CHANGED
File without changes
|
test
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
### 実現したいこと
|
2
2
|
|
3
|
-
Djangoで
|
3
|
+
Djangoで日記アプリケーションを作成しています。マイページ上でプロフィールだけでなく、自分が投稿した記事の一覧を併せて表示させており、表示させる記事の数を最大6にして、それ以降はページネーションによって記事を分割表示しようとしています。
|
4
4
|
|
5
|
-
###
|
5
|
+
### 前提
|
6
|
+
**モデル**
|
7
|
+
・主モデルCustomUserに対して、従モデルArticleが一対多でリレーションシップ関係を取っています
|
6
|
-
|
8
|
+
・Articleモデルのリレーションフィールド(post_user)では、下記サイトを参考に、テンプレート側で逆参照を出来るように、related_nameオプションを設定しています
|
7
9
|
https://qiita.com/ragnar1904/items/1afaeb6601cc490fb70a#%E9%80%86%E5%8F%82%E7%85%A7%E3%81%AE%E5%A0%B4%E5%90%88
|
8
10
|
|
11
|
+
```py
|
9
|
-
|
12
|
+
#models.py
|
10
|
-
from django.db import models
|
11
|
-
from django.contrib.auth.models import AbstractUser
|
12
|
-
from django.utils.translation import gettext_lazy as _
|
13
13
|
|
14
14
|
class CustomUser(AbstractUser):
|
15
|
-
"""拡張ユーザーモデル"""
|
16
|
-
|
17
15
|
username = models.CharField(
|
18
16
|
_("username"),
|
19
17
|
max_length=30,
|
@@ -29,53 +27,28 @@
|
|
29
27
|
error_messages={
|
30
28
|
'unique': _("A user with that email address already exists."),
|
31
29
|
},)
|
32
|
-
|
30
|
+
|
33
|
-
ig_link = models.URLField(verbose_name='Instagram Link', null=True, blank=True)
|
34
|
-
tw_link = models.URLField(verbose_name='Twitter Link', null=True, blank=True)
|
35
|
-
bg_image = models.ImageField(verbose_name='Backgroung Image', null=True, blank=True, upload_to='bgimage/')
|
36
|
-
icon = models.ImageField(verbose_name='Icon Image', null=True, blank=True, upload_to='icon/')
|
37
|
-
profession = models.CharField(verbose_name='Profession', null=True, blank=True, max_length=20)
|
38
|
-
introduction = models.TextField(verbose_name='Introduction', null=True, blank=True, max_length=500)
|
39
|
-
|
40
31
|
class Meta:
|
41
32
|
verbose_name_plural = 'CustomUser'
|
42
|
-
```
|
43
33
|
|
44
|
-
```prototyping/article/models.py
|
45
|
-
from django.db import models
|
46
|
-
from accounts.models import CustomUser
|
47
|
-
from mdeditor.fields import MDTextField
|
48
34
|
|
49
35
|
class Article(models.Model):
|
50
|
-
|
51
|
-
"""記事タグ"""
|
52
|
-
tag_choices = (
|
53
|
-
('ELECTRONICS','ELECTRONICS'),
|
54
|
-
('INSTALLATION','INSTALLATION'),
|
55
|
-
('SERVICES','SERVICES'),
|
56
|
-
('CRAFT','CRAFT')
|
57
|
-
)
|
58
|
-
|
59
36
|
post_user = models.ForeignKey(CustomUser, verbose_name='Post User', on_delete=models.CASCADE, related_name='name',)
|
60
37
|
title = models.TextField(verbose_name='title', max_length=50,)
|
61
38
|
content = MDTextField()
|
62
|
-
photo = models.ImageField(verbose_name='photo', null=True, blank=True,)
|
63
|
-
thumbnail = models.ImageField(verbose_name='thumbnail', null=
|
39
|
+
thumbnail = models.ImageField(verbose_name='thumbnail', null=False, blank=False,)
|
64
|
-
tag = models.CharField(verbose_name='article tag', choices=tag_choices, max_length=30,)
|
65
|
-
created_at = models.DateField(verbose_name='created_at', auto_now_add=True,)
|
66
|
-
view_count = models.PositiveIntegerField(verbose_name='view count', default=0,)
|
67
40
|
```
|
68
41
|
|
42
|
+
**ビュー**
|
43
|
+
・ビューではListViewを継承し、クラス変数```model```にはCustomUserを指定し、クラス変数```paginate_by```の指定も行う
|
44
|
+
・get_queryset()のオーバーライドでは、マイページのユーザに紐づくArticleモデルのクエリーセットをテンプレートへ渡すようにする
|
69
45
|
|
46
|
+
```py
|
70
|
-
#
|
47
|
+
#views.py
|
71
|
-
ビューの作成はリストビューを継承したクラスで作成しており、get_querysetメソッドのオーバーライドでは、リクエストユーザ(=自身のマイページを閲覧しているユーザ)に紐づく子テーブルのレコードを抽出している。
|
72
48
|
|
73
|
-
```prototyping/article/views.py
|
74
49
|
class MyPageView(LoginRequiredMixin, generic.ListView):
|
75
50
|
template_name = 'mypage.html'
|
76
51
|
model = CustomUser
|
77
|
-
slug_field = 'username' #モデルのフィールド名
|
78
|
-
slug_url_kwarg = 'username' #urls.pyでのキーワード名
|
79
52
|
paginate_by = 6
|
80
53
|
|
81
54
|
def get_queryset(self):
|
@@ -83,64 +56,31 @@
|
|
83
56
|
return articles
|
84
57
|
```
|
85
58
|
|
59
|
+
**テンプレート**
|
86
|
-
|
60
|
+
・テンプレートでは、主テーブルCustomUserのクエリを```{% for s in customuser_list %}```で取り出し、従テーブルArticleのクエリを```{% for article in s.name.all %}```で取り出す。
|
61
|
+
|
87
|
-
```
|
62
|
+
```html
|
63
|
+
|
88
|
-
|
64
|
+
<!--mypage.html-->
|
89
65
|
{% for s in customuser_list %}
|
90
|
-
<section>
|
91
|
-
<div class="container">
|
92
|
-
<!-- Profile Block -->
|
93
|
-
<div class="row">
|
94
|
-
<div class="col-md-4 mx-auto">
|
95
|
-
<div class="u-pull-half text-center">
|
96
|
-
{% if s.icon %}
|
97
|
-
<img class="img-fluid u-avatar u-box-shadow-lg rounded-circle mb-3" width="200" height="auto" src="{{ s.icon.url }}" alt="Image Description">
|
98
|
-
{% else %}
|
99
|
-
<img class="img-fluid u-avatar u-box-shadow-lg rounded-circle mb-3" width="200" height="auto" src="{% static 'img/default_icon.png' %}" alt="Image Description">
|
100
|
-
{% endif %}
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
</div>
|
104
|
-
<!-- End Profile Block -->
|
105
|
-
|
106
|
-
<!-- About -->
|
107
|
-
<div class="row u-content-space-bottom">
|
108
|
-
<div class="col-lg-6 mb-5 mb-lg-5 pl-lg-5 mx-auto">
|
109
|
-
{% if s.introduction %}
|
110
|
-
<h4 class="mb-3">About me</h4>
|
111
|
-
<p>{{ s.introduction }}</p>
|
112
|
-
{% endif%}
|
113
|
-
</div>
|
114
|
-
</div>
|
115
|
-
<!-- End About -->
|
116
|
-
</div>
|
117
|
-
</section>
|
118
|
-
<!-- End About Section -->
|
119
|
-
|
120
|
-
<!-- Portfolio -->
|
121
66
|
<section class="u-content-space">
|
122
67
|
<div class="container">
|
123
68
|
<header class="text-center w-md-50 mx-auto mb-8">
|
124
|
-
<h2 class="h1">Prototyping Works</h2>
|
69
|
+
<h2 class="h1">Prototyping Works by {{ s.username }}</h2>
|
125
70
|
</header>
|
126
71
|
|
127
|
-
<!-- Work Content -->
|
128
72
|
<div class="js-shuffle u-portfolio row no-gutters mb-6">
|
129
|
-
|
130
73
|
{% for article in s.name.all %}
|
131
74
|
<figure class="col-sm-6 col-md-4 u-portfolio__item" data-groups='["its-illustration"]'>
|
132
75
|
<img class="u-portfolio__image_original" src="{{ article.thumbnail.url }}" alt="Image Description">
|
133
76
|
<figcaption class="u-portfolio__info">
|
134
77
|
<h6 class="mb-0">{{ article.title }}</h6>
|
135
|
-
<small class="d-block">Branding</small>
|
136
78
|
</figcaption>
|
137
|
-
<a class="js-popup-image u-portfolio__zoom" href="assets/img-temp/portfolio/img1.jpg">Zoom</a>
|
138
79
|
</figure>
|
139
80
|
{% endfor %}
|
140
|
-
<!-- End Work Content -->
|
141
81
|
|
142
82
|
<!--ページネーション処理-->
|
143
|
-
{% if
|
83
|
+
{% if is_paginated %}
|
144
84
|
<div class="row justify-content-between align-items-center mb-4">
|
145
85
|
<div class="col-lg">
|
146
86
|
<nav aria-label="Bootstrap Pagination Example">
|
@@ -183,21 +123,27 @@
|
|
183
123
|
|
184
124
|
</div>
|
185
125
|
</section>
|
186
|
-
<!-- End Portfolio -->
|
187
126
|
{% endfor %}
|
188
|
-
|
127
|
+
|
189
128
|
```
|
190
129
|
|
130
|
+
### 発生している問題
|
131
|
+
paginate_byで指定した値を上回る数の記事が表示され、さらにページネーションに関わる表示も一切ありませんでした。
|
191
132
|
|
192
|
-
### 発生している問題
|
193
|
-
|
133
|
+
ブラウザの検証ツールを用いてhtmlを確認してみたところ、ページネーションに関するコードが記載されていなかった為、テンプレートの`{% if is_paginated %}`がFalseだと判定されたのだと理解しました。
|
194
134
|
|
195
|
-
ブラウザの検証ツールを用いてhtmlを確認してみたところ、ページネーションに関するコードが記載されていなかった為、テンプレート56行目の`{% if s.name.is_paginated %}`がFalseだと判定されたのだと理解しました。
|
196
|
-
|
197
|
-
その為、原因は
|
135
|
+
その為、原因はviewsでのページネーションに関わるメソッドのオーバーライドで一工夫する必要があるかと考えましたが、調べても同じような事例を見つけることができず、どうすれば良いのか頭を抱えています。
|
198
136
|
|
199
137
|
### 試したこと
|
200
138
|
・ブラウザのキャッシュを削除し再度読み込みを行なってもページネーションの表示がされることはありませんでした。
|
139
|
+
・下記のページを参考にget_paginate_byメソッドをオーバーライドしましたが、ブラウザ上の表示は変わりませんでした。
|
140
|
+
https://teratail.com/questions/243787
|
141
|
+
|
142
|
+
```views.py
|
143
|
+
def get_paginate_by(self, queryset):
|
144
|
+
return self.request.GET.get('paginate_by', MyPageView.paginate_by)
|
145
|
+
```
|
146
|
+
|
201
147
|
|
202
148
|
### 補足情報(FW/ツールのバージョンなど)
|
203
149
|
開発環境は下記の通りです
|
@@ -207,3 +153,4 @@
|
|
207
153
|
・MacOS
|
208
154
|
・Chromeブラウザ
|
209
155
|
|
156
|
+
|
1
タグの変更
test
CHANGED
File without changes
|
test
CHANGED
File without changes
|