基于类的视图总和,用于基于类的表单验证(无forms.py) [英] class based view sum used for class based form validation (without forms.py)

查看:59
本文介绍了基于类的视图总和,用于基于类的表单验证(无forms.py)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经研究了这一天了几天,并重新设计了我想如何在我的幻想体育网站上处理此功能:

I have been working on this one for a few days and have re-worked how i'd like to handle this functionality on my fantasy sports website:

Objective :限制幻想所有者名单上允许的玩家数量。

Objective: limit the number of players allowed on a fantasy owner's roster.

Django开箱即用的用户=所有者

Django out-of-the-box User = Owner

# 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上的类是表单的功能。

And here is the class on views.py which i suppose is how the form is functioning. There is no forms.py in this area of my project.

# 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字段从更新为用户。我想要做的是-当用户尝试将新玩家添加到他们的花名册时,系统会检查该用户已有多少玩家(也就是该用户在遍历该用户时被列为player_owner的次数)播放器模型的整个数据库),并且如果该播放器已经有最多15个播放器,则会吐出一个错误。否则,它允许添加消息。

So I have the functionality working for "adding" a player to your roster where it verifies you're signed in then --when submitted-- the Player.player_owner field updates from None to the User. What I'd like it to do is --when a User tries to add a new player to their roster, the system checks how many players the User already has (aka how many times that User is listed as the player_owner when running through the entire database of Player model) and spits out an error if the player already has the max of 15 players. Otherwise it allows the "adding" to go through.

如果您在播放器模型上注意到,我还有一个名为 player_unit_value 的字段,该字段通常停留在整数1处。我可以使用此字段在球队名册页面上的用户名册编号上产生总球员数。因此,在每个所有者的名册页面上,它显示了他们拥有的球员总数。这是我以前用来实现的views.py类(感谢@ruddra提供的代码):

If you notice on the Player model I also have a field called player_unit_value which is universally stuck at int 1. I was able to use this field to produce total players on a User's roster number on the team's roster page. So on each owner's roster page it shows the total number of players they have. Here is the views.py class that I used to pull that off (thanks to @ruddra for that code):

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}}

Then I could use the html tag {{ player_count }}

因此,这证明了该数字(计算 player_unit_value 对于在其player_owner字段中列出用户的每个玩家始终为1)可以计算并显示在前端。我想做的是在用户尝试添加玩家时访问该号码,并且-如果该号码大于14,则拒绝获取。我只是还没有弄清楚如何在 PlayerUpdateView (正在以表单形式)而不是 UserPlayerListView 。

So this proves that that number (counting the player_unit_value which is always 1 for every player who has the User listed in their player_owner field) can be calculated and displayed on the front end. What I want to do is access that number when a User is trying to add a player and --if that number is above 14-- deny the acquisition. I just havent figured out how to work that functionality on the PlayerUpdateView (which is working as a form) rather than the UserPlayerListView.

我在这里看到了很多关于如何进行自定义表单验证的讨论,我需要为该项目的这一区域提供一个实际的form.py文件。我有一个与我的用户区域关联的Forms.py文件,该文件处理用户个人资料表单(与用户名册页面不同)。我可以追溯地为已经工作的表单设置一个forms.py文件吗?我还试图创建自己的validators.py文件,并在player_owner字段上使用自定义验证器,但没有成功。

I've seen a lot of talk on here about how to have custom form validation like this I'd need to have an actual forms.py file for this area of the project. I have a forms.py file associated with my users area which handles the user profile form (not the same as the user roster page). Can I set up a forms.py file retroactively for a form thats already working? I also messed around with trying to create my own validators.py file and use custom validators on the player_owner field with no success.

编辑后的代码:

    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)


Forms.py


class AddPlayerForm(forms.ModelForm):
    class Meta:
        model = Player
        fields = []


注意:


出于某种原因,我不得不在在views.py上使用request的所有用法,以避免出现错误。另外,在尝试添加此表单验证之前,我可以使用 PlayerUpdateView类表单和单独的 PlayerDropView类表单在视图上通过这些基于类的表单来编辑Player模型。两者都在启动时分别完成了一项功能:将选定的玩家模型字段 player_owner从无切换到已登录的用户,反之亦然。因此,我能够将旧信息传递到表单中,然后将其发布为更新,直到我需要开始验证之前,我再也不必深入研究它。

note:

for some reason, I had to include "self" in front of all the uses of request on views.py in order to avoid an error. Also, Before I tried to add this form validation, I was able to edit the Player model via these class-based forms on the view using this 'PlayerUpdateView' class form and a separate 'PlayerDropView' class form. Both of those respectively accomplished one function when initiated: switch the selected Player model field 'player_owner' from None to the signed in User, or vice versa. So I was able to pass old info into a form and then post it as an update,I just never had to dig into it until i need to start validating.

所以就目前而言:代码确实将用户名册中的玩家限制为15个或更少,但是现在添加一个玩家时,将在后端创建一个玩家的空白实例,并将该用户分配为player_owner,而玩家的player_owner字段保持为None

So As it stands now: The code does restrict a User to 15 or less players on their roster, but now when a player is added, a blank instance of a player is created on the backend and assigned the User as the player_owner, while the player's player_owner field remains None.

@Josh提供了此解决方案。在答案中看到他的笔记:

@Josh provided this solution. See his notes in the answer:

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 红色轮廓不会显示在输出中。为什么?另外,我无法重定向到用户的特定花名册页面。为什么?

Question: For some reason when I try to use the else: message.error the red outline does not show up on output. Why? Also, I can't make my re-direct go to the User's specific roster page. Why?

    path('user_players/<str:username>/', UserPlayerListView.as_view(), name='user-players'),

    path('players/<id>/updating/', views.player_update, name="player-updating")


html on player.html


<a class="dropdown-item" href="{% url 'player-updating' player.id %}">Sign</a>


推荐答案

您可以在views.py或内部执行逻辑Forms.py。

You could do your logic in views.py or within forms.py.

以下内容应该可以使用,尽管尚未经过个人测试。

The below should work, though haven't tested it personally.

views.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!')

编辑:更新。

所以这就是我的做法做吧。我不是专业人士,所以我敢肯定有更好的方法,但这可以解决问题,而且不会太大。

So this is how I would do it. I'm not a pro at this, so I'm sure there's a better way, but this will do the trick and isn't too bulky.

如此大的前景:有一个页面所有玩家在该页面(或分页)上,然后为每个玩家提供一个运行一些逻辑的链接,该逻辑检查当前用户的花名册,并且如果年龄不超过14个,则将其添加到列表中。

So big picture: have a page with all the "Players" on it (or a paginated page), then for each player, have a link that runs some logic which checks the roster of the current user, and if 14 or fewer, adds that to the list.

urls.py

path('player_list', views.player_list, name="playerlist"),
path('player/<id>/update', views.player_update, name="playerupdate"),

views.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 %}

这篇关于基于类的视图总和,用于基于类的表单验证(无forms.py)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆