Search code examples
djangoformsmodels

Store the user who submitted the form into the same table?


I'm looking for the most advisable method for storing the name of the user responsible for the form submission so that I can easily organize the forms they have submitted by their username sort of like an "account setting" for each user.

I've searched but the solution is very fragmented and all posts about this refer to older versions as well as the best solution changing in every Django version. It probably doesn't help that I'm still learning the basics of Django.

Here is my views.py:

def add(request):
    title = 'Add Reddit Account'
    # ADD FORM
    form = AddRedditForm(request.POST or None)
    instance = form.save(commit=False)
    instance.user = request.user
    instance.save()
    if request.method == "POST":
        print(request.POST)

    context = {
        "form": form,
        "title": title,
        "user": instance.user
    }
    return render(request, "addreddit/add.html", context)

and my models.py:

from django.db import models

class Account(models.Model):
    user_name = models.CharField(max_length=20)
    password = models.CharField(max_length=18)
    secret = models.CharField(max_length=100)
    tag = models.CharField(max_length=20, blank=True)
    timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
    user = models.ForeignKey('auth.User', null=True)

    def __str__(self): #Python 3.3 is __str__
        return str(self.user)
        return self.user_name
        return self.password
        return self.secret
        return self.tag
        return self.timestamp

Lastly, forms.py in the event that it's relevant:

from django import forms
from .models import Account

class AddRedditForm(forms.ModelForm):
    class Meta:
        model = Account
        fields = ['user_name','password','secret','tag']
    user_name = forms.CharField(required=True)
    password = forms.CharField(widget=forms.PasswordInput,required=True)
    secret = forms.CharField(required=True)
    tag = forms.CharField(required=False)

This would seem to work very well except the only thing saved in the form is the user, not the other information.


advised edit:

from django.conf import settings
from django.core.mail import send_mail
from django.shortcuts import render, redirect
from .forms import AddRedditForm


# Create your views here.
def add(request):
    title = 'Add Reddit Account'
    # ADD FORM
    if request.method == "POST":
        form = AddRedditForm(request.POST or None)
        print(request.POST)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.user = request.user
            instance.save()
            return redirect('addreddit/add') 

    context = {
        "title": title,
        "user": request.user,  # not available if you haven't submitted the form
        "form": form
        }
return render(request, "addreddit/add.html", context)

Solution

  • You're doing a lot in that view to save the form data even when the request method is not POST. In that case, when you make a GET request, a form instance is being saved with only the .user field populated. You're also not validating the form, which is a useful Django built-in thing to do. Try this:

    def add(request):
        title = 'Add Reddit Account'
    
        if request.method == 'POST':
            form = AddRedditForm(request.POST)
            if form.is_valid():
                instance = form.save(commit=False)
                instance.user = request.user
                instance.save()
                return redirect('addreddit/add')  # or whatever named URL this is
        else:
            form = AddRedditForm()
    
        context = {
            "form": form,
            "title": title,
            "user": instance.user  # not available if you haven't submitted the form
        }
        return render(request, "addreddit/add.html", context)
    

    In a GET request, instance.user will give a name error. I presume it's just there for debugging. Otherwise, you can still access request.user.

    The other amendment I suggest is the redirect after POST, so that refreshing the page doesn't accidentally resubmit the form. Get this by importing:

    from django.shortcuts import redirect