dkhaupt
dkhaupt

Reputation: 2348

Combining a Django model + modelform as a single unit

My friends and I play a sports picking style game via a clumsy spreadsheet, and I decided to learn about Django by implementing the game as a webapp. I've gone through the Django tutorial and I've been working on the basics of passing data between the database, views, and templates.

I'm trying to display information from one model alongside a different model form, then handle saving that form to the database based on the displayed model. Here's what I have for my models:

class Sheet(models.Model):
user = models.ForeignKey(User)
... other stuff

class Game(models.Model):
home_team = models.CharField(max_length=100, default='---')
away_team = models.CharField(max_length=100, default='---')
... other stuff

class Pick(models.Model):
sheet = models.ForeignKey(Sheet)
game = models.ForeignKey(Game)
... other stuff

As you can see, Picks have both a Sheet and a Game- so a users Sheet can have multiple Picks (due to the format of the game), and each Game can have multiple picks (since multiple users might pick any given game).

My intention is to display Game information with a PickForm, so that the user can make the pick based on the displayed information. Then on POST, the pick would be appropriately foreign keyed to the correct game. I'm experimenting right now, hence the static object ID below:

class GameDetail(DetailView):
 model = Game
 template_name = 'app/games.html'
 context_object_name = 'game_detail'

 def get_object(self):
    game = get_object_or_404(Game, id=5)
    return game

 def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['pickform'] = PickForm()
    return context

 def post(request):
    form = PickForm(request.POST)
    if form.is_valid():
        pick = Pick(sheet = form.cleaned_data['sheet'],
                    game = form.cleaned_data['game'],
                    amount = form.cleaned_data['amount'],
                    pick_type = form.cleaned_data['pick_type'],
                    pick_team = form.cleaned_data['pick_team']
                    )
        pick.save()
        return HttpResponseRedirect('/games/')

What I'm wondering is, should I accomplish this by creating a separate form class that combines the PickForm with the Game? Or does it make more sense to tie them together dynamically? One option I'm looking at for the latter is using the Form.initial capability with the following change to get_context_data:

context['pickform'] = PickForm(initial={'game':self.game})

This errors out when I try to load the page

AttributeError at /games
'GameDetail' object has no attribute 'game'

In get_context_data(), has get_object() not been run already? I thought that was first, followed by get_context_data().

I could have gone about this in the entirely wrong way, so I'll be very appreciative of any advice for this issue or on how I've structured the entire thing.

EDIT: I just realized self.game would likely only work if it was defined as a field at the top of GameDetail, so I tried this:

context['pickform'] = PickForm(initial={'game':kwargs['game']})

But that doesn't work either:

KeyError at /games
'game'

Upvotes: 0

Views: 67

Answers (1)

Anentropic
Anentropic

Reputation: 33833

context['pickform'] = PickForm(initial={'game':context['game_detail']})

https://docs.djangoproject.com/en/1.9/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_context_data

It returns a dictionary with these contents:

object: The object that this view is displaying (self.object).

In your form you have set context_object_name = 'game_detail'

Upvotes: 1

Related Questions