0

I am building a Django site to share code for Python games, but I'm running into trouble associating each game with a specific user. I'm trying to do this by using the user as the ForeignKey, which I think is the right approach, but I can't get the user to actually get inserted into the database without using some weird hack (like passing the user as a string into a hidden user field, which is totally insecure and causes other issues.)

My Game class looks like this:

class Game(models.Model):
    user = models.ForeignKey(User, blank=True)
    title = models.CharField(max_length=256)
    image = models.ImageField(upload_to='games')
    description = models.CharField(max_length=256)
    requirements = models.CharField(max_length=256)
    code = models.CharField(max_length=256000)

    def __unicode__(self):
        return self.title

The form for adding a game:

class GameForm(forms.ModelForm):

    image = forms.ImageField(required=False)
    code = forms.CharField(widget=PagedownWidget(show_preview=True))

    class Meta:
        model = Game
        fields = ('user','title','image','description','requirements','code')

User.game = property(lambda u: Game.objects.get_or_create(user=u)[0])

I create a custom version of this form in my addgame.html template:

<form action="/userprofile/addGame/" method="post">{% csrf_token %}
    {% for field in form.visible_fields %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}
            <br>
            {{ field }}
            <br><br>
        </div>
    {% endfor %}
    <input type="submit" value="Save">
</form>

My View looks like this:

@login_required
def add_game(request):
    user = request.user
    error_message = None

    if request.method == 'POST':
        form = GameForm(request.POST)
        if form.is_valid():
            form = form.save(commit=False)
            form.uploader = request.user
            form.save()
            return HttpResponseRedirect('/userprofile')
        else:
            error_message = "Invalid Input"
    else:
        form = GameForm()

    args = {}
    args.update(csrf(request))
    args['user'] = user
    args['form'] = form
    args['error_message'] = error_message

    return render_to_response('addgame.html', args)

However, I get the following error:

Cannot assign None: "Game.user" does not allow null values.

I realize that a User instance has not been passed into the form, thus I am getting a 'shouldn't be null' error, but I have no idea how to properly pass in the User instance to the form. I've looked at several questions on this exact issue, such as this, but I still haven't been able to get User successfully passed in to the form.

Community
  • 1
  • 1
123
  • 8,733
  • 14
  • 57
  • 99
  • 1
    That's normally done in the view. Can you add it to your question? – spectras Jan 03 '16 at 19:45
  • Have to go, but basic workflow: view instantiates the form, then view triggers form validation, then view sets additional fields on `form.instance`, then view saves the form. (as an alternative, view can save first, with commit=False, then set additional fields then save the model). – spectras Jan 03 '16 at 19:49
  • Your right, totally forgot to include that. Just added it in. – 123 Jan 03 '16 at 19:54
  • 1
    I can't understand the point of your monkeypatched `User.game` property. You have a FK from Game to User, so a User can have *multiple* games; if you want only one, use a OneToOneField. And both FK and OneToOneField already provide a reverse accessor to access Game from User. – Daniel Roseman Jan 03 '16 at 20:30
  • Yup, I'm pretty sure it's completely pointless :) ...I ran into a bug a while back that was only fixed by including that line, but it works fine without it now, so I've deleted it. – 123 Jan 03 '16 at 20:33

1 Answers1

2

Problem 1:

form.uploader = request.user

Should be:

form.user = request.user

I dont see uploader attribute in your Game model

Problem 2:

In the GameForm Meta class, the following line should not include a user field:

fields = ('title','image','description','requirements','code')

123
  • 8,733
  • 14
  • 57
  • 99
doniyor
  • 36,596
  • 57
  • 175
  • 260
  • I actually tried that before, but I still get the same error. Just double checked again, and changing it to `form.user` unfortunately doesn't fix the issue. – 123 Jan 03 '16 at 20:08
  • 1
    @TK-421 how do you want to save a new value to an attribute that never exists? – doniyor Jan 03 '16 at 20:09
  • Although that does make perfect sense..that line SHOULD say `form.user = request.user`, but apparently theres a deeper issue other than that. – 123 Jan 03 '16 at 20:10
  • @TK-421 there is no other deeper issue other than this! you were just not setting the `user` field and thats why the error came. – doniyor Jan 03 '16 at 20:11
  • Hmm, well I still get the same error after correcting that mistake. (I don't doubt that this was a problem in my code, it just unfortunately doesn't appear to have fixed the original issue.) – 123 Jan 03 '16 at 20:12
  • Found the other problem. Added an edit to your answer, let me know if that makes sense to you. – 123 Jan 03 '16 at 20:21
  • well, this makes sense only if you dont need the field `user` being set. :) @TK-421 – doniyor Jan 03 '16 at 20:23
  • It does seem a little strange that I needed to exclude that...I think it boils down to the fact that your not supposed to add a form field for a `foreignKey` in the model...I think it overrides the model field for user or something. Either way, the user field gets filled in the database properly now so I'm happy. Thanks for the help. – 123 Jan 03 '16 at 20:30