Django CreateView self.object返回无

时间:2018-08-30 14:29:43

标签: python django django-forms

我在Django中有一个CreateView,并且尝试使用按以下方式创建的对象。

def get_success_url(self, *args, **kwargs):
    team  = self.get_team()
    match = self.object
    if match.home.team == team: lineup = match.home
    else: lineup = match.away

    return redirect ('matches:update-lineup', kwargs={'pk' : lineup.id})

我只是得到一个错误,说self.object是None。我认为这意味着该对象尚未保存,那么我该如何实现get_success_url直到对象被保存然后再使用呢?

编辑 添加了回溯

Traceback:

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/contrib/auth/mixins.py" in dispatch
  56.         return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
  88.         return handler(request, *args, **kwargs)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  217.         return super(BaseCreateView, self).post(request, *args, **kwargs)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  183.             return self.form_valid(form)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/edit.py" in form_valid
  163.         return super(ModelFormMixin, self).form_valid(form)

File "/home/henry/Documents/Sites/Development/statmetrix/env/lib/python3.6/site-packages/django/views/generic/edit.py" in form_valid
  79.         return HttpResponseRedirect(self.get_success_url())

File "/home/henry/Documents/Sites/Development/statmetrix/matches/views.py" in get_success_url
  506.         if match.home.team == team: lineup = match.home

Exception Type: AttributeError at /matches/1/create-match/
Exception Value: 'NoneType' object has no attribute 'home'

编辑2 已添加整个视图

class CreateMatchView(LoginRequiredMixin, CreateView):
    model = Match
    form_class = forms.CreateMatchForm
    template_name = 'matches/add_match/step1.html'

    def get_team(self, *args, **kwargs):
        return Team.objects.get(id=self.kwargs['team_id'])

    def get_form_kwargs(self, *args, **kwargs):
        kws = super(CreateMatchView, self).get_form_kwargs(*args, **kwargs)
        kws['team'] = self.get_team()
        return kws

    def get_context_data(self, *args, **kwargs):
        ctx = super(CreateMatchView, self).get_context_data(*args, **kwargs)
        ctx['associations'] = Association.objects.all().order_by('country')
        ctx['team'] = self.get_team()
        return ctx

    def get_success_url(self, *args, **kwargs):
        team  = self.get_team()
        match = self.object
        if match.home.team == team: lineup = match.home
        else: lineup = match.away

        return redirect ('matches:update-lineup', kwargs={'pk' : lineup.id})

编辑3 添加了CreateMatchForm

class CreateMatchForm(forms.ModelForm):
    side = forms.IntegerField()
    opposition = forms.ModelChoiceField(queryset=Team.objects.all())
    team = forms.ModelChoiceField(queryset=Team.objects.all())
    str_time = forms.CharField()
    str_date = forms.CharField()

    class Meta:
        model = Match
        fields = ['str_time','str_date','venue','season','competition','side','opposition','team']

    def __init__(self, *args, **kwargs):
        team = kwargs.pop('team')
        super(CreateMatchForm, self).__init__(*args, **kwargs)
        self.fields['opposition'].queryset = Team.objects.filter(association=team.association)
        self.fields['season'].initial = team.current_season
        self.fields['season'].widget = forms.HiddenInput()
        self.fields['competition'].queryset = Competition.objects.filter(association=team.association)
        self.fields['team'].initial = team
        self.fields['team'].widget = forms.HiddenInput()

    def save(self, *args, **kwargs):
        team = self.cleaned_data['team']
        #We have to then add Lineups so we just take a copy of the most recent, if it exists, or create one if not
        if self.cleaned_data['side'] == 1:
            home_team = team
            away_team = self.cleaned_data['opposition']
        else :
            away_team = team
            home_team = self.cleaned_data['opposition']

        home_lineup = Lineup.objects.filter(team=home_team).first()
        if home_lineup is None:
            #We have no previous lineup to base this lineup on so we select first 11 players from Roster
            roster = Roster.objects.filter(team=home_team, season=team.current_season).first()
            if roster is None:
                #We have no roster and need to create one
                create_standard_roster(home_team, team.current_season)
                roster = Roster.objects.filter(team=home_team, season=team.current_season).first()
            home_lineup = Lineup (team=home_team)
            home_lineup.save()
            for player in roster.players.all()[:10]:
                home_lineup.starters.add(player)
            for player in roster.players.all()[11:]:
                home_lineup.substitutes.add(player)
        else:
            home_lineup.pk = None
            home_lineup.save()

        away_lineup = Lineup.objects.filter(team=away_team).first()
        if away_lineup is None:
            #We have no previous lineup to base this lineup on so we select first 11 players from Roster
            roster = Roster.objects.filter(team=away_team, season=team.current_season).first()
            if roster is None:
                #We have no roster and need to create one
                create_standard_roster(self.away_team, team.current_season)
                roster = Roster.objects.filter(team=away_team, season=team.current_season).first()
            away_lineup = Lineup (team=self.away_team)
            away_lineup.save()
            for player in roster.players.all()[:10]:
                away_lineup.starters.add(player)
            for player in roster.players.all()[11:]:
                away_lineup.substitutes.add(player)
        else :
            away_lineup.pk = None
            away_lineup.save()

        match = Match (
            time = datetime.datetime.strptime(self.cleaned_data['str_date']+'T'+self.cleaned_data['str_time'], '%d %b %YT%H:%M'),
            venue = self.cleaned_data['venue'],
            season = self.cleaned_data['season'],
            competition = self.cleaned_data['competition'],
            home = home_lineup,
            away = away_lineup
        )
        match.save()

1 个答案:

答案 0 :(得分:2)

Form(如您的CreateMatchForm)必须返回在调用.save()函数时构造/更新的对象。

因此,您应该将表格重写为:

class CreateMatchForm(forms.ModelForm):

    # ...

    def save(self, *args, **kwargs):
        # ...
        match.save()
        return match

# ...仍应包含原始代码,但是引用较长的代码片段不会提高可读性,因此我在答案中将其省略了)

如果忽略此返回,则函数将返回None(这是Python处理不显式返回任何内容的函数的方式)。

因此,通过“破坏”该合同,self.object被赋予None而不是创建的Match,因此match.home毫无意义。