python - 基于类的视图总和用于基于类的表单验证(没有 forms.py)
问题描述
我已经为此工作了几天,并在我的幻想体育网站上重新设计了我希望如何处理此功能:
目标:限制幻想所有者名单上允许的玩家数量。
Django 开箱即用的用户 = 所有者
# models.py
class Player(models.Model):
player_full = models.CharField(max_length=50)
player_owner = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
image = models.ImageField(default='default_player.jpg', upload_to='player_pics')
player_unit_value = models.PositiveSmallIntegerField(default=1, validators=[MinValueValidator(1),
MaxValueValidator(1),])
这是views.py上的课程,我想这是表单的运作方式。我的项目的这个区域没有forms.py。
# views.py
class PlayersUpdateView(LoginRequiredMixin, UpdateView, Player):
model = Player
fields = []
template_name = 'blog/player_form.html' # <app>/<model>_<viewtype>.html
context_object_name = 'players'
# this def makes sure only the post author can edit the post
def test_func(self, **kwargs):
# this makes sure it is the exact post we are updating
player = self.get_object()
if self.request.user == player.player_owner:
return True
return False
def form_valid(self, form):
form.instance.player_owner = self.request.user
return super().form_valid(form)
因此,我有一个功能可以将玩家“添加”到您的花名册中,它会验证您是否已登录,然后 -- 当提交时 -- Player.player_owner 字段从None
用户更新。我想做的是——当用户尝试将新玩家添加到他们的名单中时,系统会检查用户已经拥有多少玩家(也就是在运行时该用户被列为 player_owner 的次数) Player 模型的整个数据库),如果玩家已经拥有最多 15 名玩家,则会吐出一个错误。否则,它允许“添加”通过。
如果您在 Player 模型上注意到我还有一个名为的字段player_unit_value
,它普遍停留在 int 1。我能够使用该字段在团队的花名册页面上的用户花名册编号上生成总球员。因此,在每个所有者的名单页面上,它会显示他们拥有的球员总数。这是我用来完成它的 views.py 类(感谢@ruddra 的代码):
class UserPlayerListView(ListView):
model = Player
template_name = 'blog/user_players.html' # <app>/<model>_<viewtype>.html
context_object_name = 'players'
paginate_by = 20
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Player.objects.filter(player_owner=user).order_by('-player_sal_19_20')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
player_list = list(context['players']) # evaluates the query
context['sum_of_sal_19_20'] = sum([x.player_sal_19_20 for x in player_list]) # pythonic sum calculation
context['player_count'] = sum([x.player_unit_value for x in player_list])
context['players'] = player_list
return context
然后我可以使用 html 标签 {{ player_count }}
所以这证明了这个数字(player_unit_value
对于每个在他们的 player_owner 字段中列出 User 的玩家来说始终为 1)可以计算并显示在前端。我想要做的是在用户尝试添加玩家时访问该号码,并且 - 如果该号码高于 14 - 拒绝收购。我只是还没弄清楚如何在PlayerUpdateView
(作为表单工作)而不是UserPlayerListView
.
我在这里看到了很多关于如何进行自定义表单验证的讨论,我需要为项目的这个区域提供一个实际的 forms.py 文件。我有一个与我的用户区域关联的 forms.py 文件,它处理用户配置文件表单(与用户名册页面不同)。我可以为已经工作的表单追溯设置 forms.py 文件吗?我还尝试创建自己的 validators.py 文件并在 player_owner 字段上使用自定义验证器,但没有成功。
编辑代码:
视图.py
def form_valid(self, form):
if self.request.method == 'POST':
form = AddPlayerForm(self.request.POST)
if form.is_valid():
form.save(commit=False)
current_user = self.request.user
if Player.objects.filter(player_owner=current_user).count() > 14:
messages.info(self.request, f'Your roster is full! Player not added.')
return redirect('profile')
else:
form.instance.player_owner = self.request.user
return super().form_valid(form)
表格.py
class AddPlayerForm(forms.ModelForm):
class Meta:
model = Player
fields = []
笔记:
出于某种原因,为了避免错误,我不得不在 view.py 上所有 request 的使用前包含“self”。此外,在我尝试添加此表单验证之前,我能够使用此“PlayerUpdateView”类表单和单独的“PlayerDropView”类表单在视图上通过这些基于类的表单编辑播放器模型。两者在启动时分别完成一个功能:将选定的 Player 模型字段“player_owner”从 None 切换到已登录的 User,反之亦然。因此,我能够将旧信息传递到表单中,然后将其作为更新发布,在需要开始验证之前,我无需深入研究它。
所以就目前而言:代码确实将用户限制为 15 名或更少的球员,但现在当添加球员时,会在后端创建一个球员的空白实例并将用户分配为 player_owner,而玩家的 player_owner 字段保持为无。
最终编辑:
@Josh 提供了这个解决方案。请参阅他在答案中的注释:
视图.py
def player_update(request, id,):
player = Player.objects.get(id=id)
current_user = request.user
if Player.objects.filter(player_owner=current_user).count() <= 14:
player.player_owner = current_user
player.save()
messages.success(request, f'Player added!')
return redirect('blog-players')
else:
messages.warning(request, f'Your roster is full! Player not added.')
return redirect('blog-players')
def players(request):
context = {
'players': Player.objects.all(),
}
return render(request, 'blog/players.html', context)
问题:由于某种原因,当我尝试使用else: message.error
红色轮廓时,输出中没有出现。为什么?此外,我无法让我的重定向转到用户的特定花名册页面。为什么?
网址.py
path('user_players/<str:username>/', UserPlayerListView.as_view(), name='user-players'),
path('players/<id>/updating/', views.player_update, name="player-updating")
player.html 上的 html
<a class="dropdown-item" href="{% url 'player-updating' player.id %}">Sign</a>
解决方案
您可以在 views.py 或 forms.py 中执行您的逻辑。
下面应该可以工作,虽然没有亲自测试过。
视图.py
if request.method == 'POST':
form = forms.AddPlayer(request.POST)
if form.is_valid():
instance = form.save(commit=False)
current_user = request.user
if Player.objects.filter(user_id=current_user).count() > 14:
# do something here, such as return error or redirect to another page
else:
instance.save()
或形式: forms.py
class AddPlayerForm(forms.ModelForm):
class Meta:
model = Player
fields = ['name', 'number']
def clean(self):
current_user = request.user
if Player.objects.filter(user_id=current_user).count() <= 14:
pass
else:
raise ValidationError('Your team is full!')
编辑:更新。
所以我会这样做。我不是这方面的专家,所以我确信有更好的方法,但这会奏效并且不会太笨重。
如此大的画面:有一个包含所有“玩家”的页面(或分页页面),然后对于每个玩家,有一个链接运行一些逻辑来检查当前用户的名单,如果 14 或更少,添加到列表中。
网址.py
path('player_list', views.player_list, name="playerlist"),
path('player/<id>/update', views.player_update, name="playerupdate"),
视图.py
def player_list(request)
player_list = Player.objects.all()
return render(request, 'player_list.html', {'player_list': player_list}
def player_update(request, id):
player = Player.objects.get(id=id)
current_user = request.user
if Player.objects.filter(user_id=current_user).count() <= 14:
player.player_owner = current_user
player.save()
return redirect('roster')
else:
return redirect('error')
player_list.html
{% for player in player_list %}
{{player.name}} -- <a href="/player/{{player.id}}/update"> Click here to claim this player!</a>
{% endfor %}
推荐阅读
- php - (PHP) MySQL 到 Excel 导出生成不同单元格格式的文件
- javascript - 在 JS 对象内设置多个属性
- css - 浏览器缩放时自动调整单选按钮大小
- java - 日历错误的Outlook时间
- sql - 如何将 Sql 行数据传递给 Vue 文件(Laravel 项目)
- ios - 如何从 PDF 矢量资产中获取调整大小的图像?
- python - 为什么我没有在日期时间列表上使用 numpy.searchsorted over bisect.bisect_left 获得更好的性能?
- javascript - 你如何设置一个对象出现在屏幕上的随机概率javascript(用于游戏)
- javascript - JS 插件无法识别动态添加的元素
- firebase - 如何使用云函数中的 response.sendFile 从云存储发送文件?