Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lesson 17 - Delete Views and Advanced ModelForms

Lesson 17 - Delete Views and Advanced ModelForms

Dana Spiegel

December 18, 2012
Tweet

More Decks by Dana Spiegel

Other Decks in Technology

Transcript

  1. Providing Confirmation Messages • Django provides “messaging” application which can

    be used to display status messages to users based on their actions • Messages are set in the request, and are presented in a special message section of every page • Messages can have different “levels” of importance: • debug, info, success, warning, error • debug level doesn’t appear to users by default • Set MESSAGE_STORAGE in settings.py to use user session to hold messages • Ensure MIDDLEWARE_CLASSES contains MessageMiddleware: 3 'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.storage.session.SessionStorage'
  2. Providing Confirmation Messages • Ensure TEMPLATE_CONTEXT_PROCESSORS contains message: • Ensure

    INSTALLED_APPS has message application: • In view method, use messages.<LEVEL> to add a message that will be displayed the next time a template is rendered: • Messages are cleared whenever the message storage is iterated • In a template, this means whenever messages are included in the rendering of a page • Render messages in template by using messages template variable 4 'django.contrib.messages', 'django.contrib.messages.context_processors.messages' messages.debug(request, '5 SQL statements were executed.') messages.info(request, 'Three credits remain in your account.') messages.success(request, 'Profile details updated.') messages.warning(request, 'Your account expires in three days.') messages.error(request, 'Document deleted.')
  3. Example: Messages View 5 from django.contrib import messages ... def

    team_delete(request, team_id): try: team = models.Team.objects.get(pk=team_id) except models.Player.DoesNotExist: raise Http404 team.delete() messages.success(request, 'Team {0} deleted!'.format(team.name)) return redirect('team_list')
  4. Example: Messages Template 6 {% if messages %} {% for

    message in messages %} <div class="alert {% if message.tags %}alert- {{ message.tags }}{% endif %}"> <button type="button" class="close" data- dismiss="alert">×</button> {{ message }} </div> {% endfor %} {% endif %}
  5. Delete Views • Delete views enable the deletion of objects

    from the database • Implemented as standard views, but with no actual rendering • If deletion is successful, user is redirected to another view • Necessary, since object being deleted no longer exists! • Add delete view to urls 7 def team_delete(request, team_id): try: team = models.Team.objects.get(pk=team_id) except models.Player.DoesNotExist: raise Http404 team.delete() messages.success(request, 'Team {0} deleted!'.format(team.name)) return redirect('team_list') url(r'^team/(?P<team_id>\d+)/delete/$', 'softball.views.team_delete', name='team_delete'),
  6. Delete Views (cont’d.) • Django will “cascade” delete in some

    circumstances and not in others • Related objects will be removed • If related objects aren’t removed, be sure to delete them, otherwise orphaned objects will remain in the database • Can be controlled on ForeignKeys by using the on_delete argument when declaring the ForeignKey • Generally will behave like a database ON DELETE CASCADE query • Use CASCADE when you want an object to be deleted when the object specified by ForeignKey is deleted • Add on_delete=django.db.models.CASCADE to all of the ForeignKeys in models.py • Use PROTECT when you want to prevent deletion of ForeignKey object • More information can be found in Django docs: • https://docs.djangoproject.com/en/1.4/ref/models/fields/ #django.db.models.ForeignKey.on_delete 8
  7. Non-model Fields and ModelForms • ModelForms can be customized with

    additional fields that aren’t part of the Model • Works because ModelForms inherit from Django Forms • To add additional fields, configure them as in a normal Form • Use ModelChoiceField for GameForm since away_team and home_team are populated with Teams • Override clean() method to enable cleaning of additional fields 9 class GameForm(ModelForm): away_team = ModelChoiceField(label=u'Away Team', required=True, queryset=models.Team.objects.all(), help_text=u'Changing the team will clear the roster') home_team = ModelChoiceField(label=u'Home Team', required=True, queryset=models.Team.objects.all(), help_text=u'Changing the team will clear the roster')
  8. Example: Extra Fields in ModelForm 10 class GameForm(ModelForm): away_team =

    ModelChoiceField(label=u'Away Team', required=True, queryset=models.Team.objects.all(), help_text=u'Changing the team will clear the roster') home_team = ModelChoiceField(label=u'Home Team', required=True, queryset=models.Team.objects.all(), help_text=u'Changing the team will clear the roster') error_css_class = 'text-error' required_css_class = 'text-required' class Meta: model = models.Game fields = ('played_on', 'location', ) def clean(self): cleaned_data = self.cleaned_data if cleaned_data.get('home_team') == cleaned_data.get('away_team') and\ cleaned_data['home_team']: msg = u'Home team and Away team cannot be the same.' self._errors['home_team'] = self.error_class([msg]) self._errors['away_team'] = self.error_class([msg]) # These fields are no longer valid. Remove them from the # cleaned data. del cleaned_data['home_team'] del cleaned_data['away_team'] return cleaned_data
  9. Using Extra Fields in Views 11 • To use extra

    FormFields in a view, treat the form as both Form and ModelForm • is_valid() still works, validating input for both instance and additional fields • save() will return the instance without the extra fields (they are just part of the form, not the Model) • form.cleaned_data can be used to access the extra fields • Be sure to include initialization of the extra fields by providing an initial data dict to set the pre-filled values for the extra fields in addition to providing an instance! • For GameForm and game_create view, this technique allows using the Game Model for location and played_on date fields, but using manually managed home_team and away_team fields for creating/editing rosters automatically • Additional fields will appear automatically AFTER configured ModelFields when rendering the Form
  10. Example: game_create 12 def game_create(request): if request.method == 'POST': game_form

    = forms.GameForm(request.POST) if game_form.is_valid(): # home_team must be assigned a roster home_roster = models.Roster( team=game_form.cleaned_data['home_team']) home_roster.save() # away_team must be assigned a roster away_roster = models.Roster( team=game_form.cleaned_data['away_team']) away_roster.save() game = game_form.save(commit=False) game.home_roster = home_roster game.away_roster = away_roster game.save() messages.success(request, 'Game {0} created'.format(game)) return redirect('game_edit', game_id=game.id) else: game_form = forms.GameForm() return TemplateResponse(request, 'softball/game/create.html', { 'game_form': game_form, })
  11. Example: game_edit 13 def game_edit(request, game_id): try: game = models.Game.objects.get(pk=game_id)

    except models.Player.DoesNotExist: raise Http404 initial = { 'home_team': game.home_roster.team_id, 'away_team': game.away_roster.team_id, } if request.method == 'POST': game_form = forms.GameForm(request.POST, instance=game, initial=initial) if game_form.is_valid(): game = game_form.save() # if home_team or away_team were changed, clear the statistics if 'home_team' in game_form.changed_data: game.home_roster.team = game_form.cleaned_data['home_team'] game.home_roster.save() game.home_roster.player_statistics.all().delete() if 'away_team' in game_form.changed_data: game.away_roster.team = game_form.cleaned_data['away_team'] game.away_roster.save() game.away_roster.player_statistics.all().delete() if 'home_team' in game_form.changed_data or 'away_team' in game_form.changed_data: return redirect('game_edit', game_id=game.id) messages.success(request, 'Game {0} updated'.format(game)) return redirect('game_view', game_id=game.id) else: game_form = forms.GameForm(instance=game, initial=initial) return TemplateResponse(request, 'softball/game/edit.html', { 'game': game, 'game_form': game_form, })