Django Forms:Post request is got but data is not saved - python

So I'm trying to build a Django site that collects Mod Applications to learn Django Forms. Except that I'm an idiot and I don't know what am I doing.
The thing that I'm trying to do is collect and save the Form data the current part and later try to show that data in the Django Admin the part I still haven't done and don't know how.
When I fill out the form I get [06/May/2017 19:38:29] "POST /modapp HTTP/1.1" 200 2354
This is my forms.py:
class Application(forms.ModelForm):
class Meta:
model = ModApplication
fields = ('discord', 'reddit', 'serverrank','finds','serverstay','active','timezone','reason','helped','help')
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
self.fields['discord'].widget.attrs['placeholder'] = 'UnknownDeveloper#2068'
self.fields['reddit'].widget.attrs['placeholder'] = '/u/UnknownDeveloper'
self.fields['serverrank'].widget.attrs['placeholder'] = 'GEOCACHING + RANK'
self.fields['serverstay'].label = "How long have you been on the server"
self.fields['active'].label = "How active have you been on the server"
self.fields['timezone'].widget.attrs['placeholder'] = 'CET'
self.fields['reason'].label = "Why do you want to become a mod?"
self.fields['helped'].label = "How have you helped the server so far?"
self.fields['help'].label = "How will you help the server if you'll become a mod"
models.py
class ModApplication(models.Model):
def __unicode__(self):
return "Discord User: " + self.discord + " aka " + self.reddit
reddit = models.CharField("Reddit Username", max_length=30)
discord = models.CharField("Discord Username", max_length=30)
serverrank = models.CharField("Server Rank", max_length=60)
finds = models.CharField("Finds", max_length=12)
serverstay = models.CharField("Stayed on the server for",max_length=200)
active = models.CharField("Is Actice on Discord for", max_length=500)
timezone = models.CharField("Timezone", max_length=20)
reason = models.TextField("He likes to become a mod because", max_length=5000)
helped = models.TextField("He helped by", max_length=5000)
help = models.TextField("He'll help by", max_length=5000)
views.py
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
user.discord = request.discord
user.reddit = request.reddit
user.serverrank = request.serverrank
user.finds = request.finds
user.serverstay = request.serverstay
user.active = request.active
user.timezone = request.timezone
user.reason = request.reason
user.helped = request.helped
user.help = request.help
user.save()
print(user)
messages.success(request, 'Your Mod Application has been successfully submitted!')
print(form)
return HttpResponse('Successful')
else:
form_class = Application
I searched a lot but I didn't find anything. I tried to print debug messages but they didn't print anything. I put the messages module but nothing happened. HTTPResponse just reloads back to the form. Help will be gladly accepted. Thanks for your time. If I am missing something please tell me and i'll edit my post

It's a suprise that this code runs at all, it should be producing attribute errors for these:
user.discord = request.discord
user.reddit = request.reddit
But the reason that it doesn't is because the execution path never reaches that point
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
Because of that return statement.
Your corrected code should look like
def formtofill(request):
form = Application()
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, 'Your Mod Application has been successfully submitted!')
return HttpResponseRedirect('/success_url')
else:
form_class = Application
return render(request, 'appmod.html', {'form': form,})

Dont save the form upfront. Save but put commit=false.
Also remove that return statement as in the answer above mine.
user = form.save(commit=False).
Then an instance is created, but its not written into the database. Now you can do the assignments.
user = form.save(commit=False).
#Now....
user.discord = request.POST['discord']
user.reddit = request.POST['reddit']
user.serverrank = request.POST['serverrank']
user.finds = request.POST['finds']
user.serverstay = request.POST['serverstay']
....................
user.save()
return HttpResponse('Successful')
Instead you were trying to access the data as an attribute of the request object itself. The form data are contained in request.POST, then you have to access it from there.
Also,
else:
form = Application()
You need to instantiate the form class.

Related

How to remove "this field is not required" in django?

I found posts with similar problem, but the solutions dont seem to work with me. Or maybe I am missing something.
I created a form in Django, but as a default it seems that every mandatory fields have this "this field is required" text above.
Ideally, I would like to have this only when someone tries to submit a form and a field is missing.
form.py
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
}
widgets = {
'user': forms.Select(attrs={'class':'form-control','required':'True'}),
'look_colour':forms.Select(attrs={'class':'form-control','required':'True'}),
}
view.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
return render(request,"main/ElderFlowerReview.html", {'form':form, 'submitted':submitted,'reviews':reviews, 'product':product})
models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
Any ideas
something wrong on case request.GET here:
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
You send the FormClass into the template context, and not the form instance.
Also see eror on the except case: If i have a GET, i should not render BoundedForm, here should be form.bounded = false (form is not bounded with any data). But you are always made the BoundedForm, with the request.POST data after error here:
reviews = ChampageRating.objects.get(pk=product_id)
My opinion is - you should try to read about Django-GCBV, it is better way to avoid complex errors, like in your question.
https://docs.djangoproject.com/en/4.0/topics/class-based-views/

Submit a form only once in Django

I am trying to make the user submit a form only once. I have a /dashboard page which is shown after submitting the /petform. But, I want the user to submit the form only once after logging in and other times it should redirect to the /dashboard directly (or show a message that "form already submitted").
models.py
class PetFormData(models.Model):
abstract = True
name = models.CharField(max_length=100)
age = models.IntegerField()
breed = models.CharField(max_length=100)
amount_spent = models.CharField(max_length=100, choices=AMOUNT_CHOICES)
pincode = models.CharField(max_length=15)
services_required = models.CharField(max_length=100, choices=SERVICE_CHOICES)
auth_user_email = models.ForeignKey(User, on_delete=models.CASCADE)
form_submitted = models.BooleanField(default=False)
views.py
#login_required
def showformdata(request):
form = PetForm(request.POST)
if request.method == 'POST':
if not PetFormData.form_submitted and user == PetFormData.auth_user_email:
PetFormData.form_submitted = True
print(PetFormData.form_submitted)
if form.is_valid():
user = request.user
nm = form.cleaned_data['name']
age = form.cleaned_data['age']
breed = form.cleaned_data['breed']
am_sp = form.cleaned_data['amount_spent']
pin = form.cleaned_data['pincode']
ser_req = ','.join(form.cleaned_data['services_required'])
model_pet_form = PetFormData(name=nm, age=age, breed=breed, amount_spent=am_sp, pincode=pin,
services_required=ser_req, auth_user_email=user)
model_pet_form.save()
print(session_data)
return redirect('/dashboard')
else:
print(PetFormData.form_submitted)
return HttpResponse('Form already submitted', content_type="text/plain")
else:
form = PetForm()
return render(request, 'petform.html', {'form': form})
Successfully submitting the form once presumably stores something in the database. A subsequent visit to that page can interrogate the database, discover it has already been done, and display the appropriate next page.
Something like this (I don't fully understand your problem)
if PetFormData.objects.filter( auth_user_email = request.user).exists() :
return redirect('/dashboard')
# OK, user hasn't submitted yet.

Passing logged in user to form

I am trying to pass logged in user to form that i would like to save.
forms.py
class SpotForm(ModelForm):
def __init__(self, *args, **kwargs):
super(SpotForm, self).__init__(*args, **kwargs)
self.fields['gross_weight'].widget = forms.NumberInput(attrs={'min':0})
self.fields['volume'].widget = forms.NumberInput(attrs={'min': 0})
class Meta:
model = Spot
fields = [
'gross_weight','volume','origin_country','origin_port',
'dest_country','dest_port','ship_week','requestor'
]
models.py
class Stakeholder(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
company_name = models.CharField(max_length=15)
mail = models.CharField(max_length=40)
def __str__(self):
return self.mail
class Spot(models.Model):
STATUSES = (
('Open','Open'),
('Closed','Closed')
)
gross_weight = models.FloatField(null=False,default=0,validators=[MinValueValidator(0)])
volume = models.FloatField(null=False,default=0,validators=[MinValueValidator(0)])
origin_country = models.CharField(
validators=[RegexValidator(regex='[A-Z]{2}', message='Country code is two letters')], max_length=2,null=True)
origin_port = models.CharField(
validators=[RegexValidator(regex='[A-Z]{3}', message='Port code is three letters')], max_length=3,null=True)
dest_country = models.CharField(
validators=[RegexValidator(regex='[A-Z]{2}', message='Country code is two letters')], max_length=2,null=True)
dest_port = models.CharField(
validators=[RegexValidator(regex='[A-Z]{3}', message='Port code is three letters')], max_length=3,null=True)
time_registered = models.DateField(default=timezone.now)
spot_status = models.CharField(max_length=6,default='Open', choices=STATUSES)
ship_week = models.CharField(max_length=2,null=True)
requestor = models.ForeignKey(Stakeholder,null = True,on_delete=models.CASCADE)
def __str__(self):
return self.origin_country + self.origin_port + '-' + self.dest_country +self.dest_port + '-' + self.ship_week
views.py
def register_spot(request):
my_user = Stakeholder.objects.get(user=request.user)
form = SpotForm()
if request.method =='POST':
print("print",request.POST)
form = SpotForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
print(form.errors)
context = {'form': form}
return render(request, 'spotrequesting/register_spot.html', context)
When i submit the form i am getting an error in command prompt stating "This field is required" for "requestor". After that - dropdown list for this field come up on screen and i can select out of two registered users i have. But even selecting something from this list and again submitting the form is giving me the same error.
Checking "my_user" variable - it is showing me that i am logged in.
Is there a way to pass to "requestor" field currently logged in user?
I was able to get the form saved only by deleting "requestor" from "fields" in SpotForm (which gave me "None" in the end for this field in database) but that's not the desired outcome.
Any suggestion would be highly appreciated.
You are not really passing the stakeholder instance to the requestor field in the form are you? So you will have to do:
form = SpotForm(requestor = my_user)

Grab an object in Django

This is probably very simple and basic but I'm struggling with grabbing a newly-created object in Django. It is for a basic library-style app. Over in models, I do this to create a Book object:
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
if not Author.objects.filter(first_name=first_name, last_name=last_name).exists():
author_obj = Author.objects.create(first_name=first_name, last_name=last_name)
else:
author_obj = Author.objects.get(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
Then in views, I call that method and wish to redirect to a page specifically for that newly-created object. I think you can see that I have most of the code down, but don't know what to put in place of the "????".
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
Book.objects.add_book(request.POST, request.session['uid'])
book_id = Book.objects.get(????).id
return redirect('/books/book/{}/'.format(book_id))
else:
context = {
'errors' : errors,
}
1st part use get_or_create for retrieve or create a model entry
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
author_obj, created = Author.objects.get_or_create(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
2nd part, return self.create return a Book entity :
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
book = Book.objects.add_book(request.POST, request.session['uid'])
return redirect('/books/book/{}/'.format(book.id))
else:
context = {
'errors' : errors,
}
There are some issues here. At the very least, look at Django Forms before you go much further. This is what a view that creates an object could look like:
def add_book(request):
if request.POST:
author, created = Author.objects.get_or_create(first_name=first_name,
last_name=last_name)
book = Book(title = request.POST['title'],
user_obj = request.GET['user'],
author = author,)
book.save()
return redirect('/books/book/{}/'.format(book.id))
else:
return render(request, 'book_form.html')
You really need to look into ModelForms to handle your POSTs. But start with looking at Forms.

django - load currently logged in user information in the form

django noob here.
The question i am going to ask has been asked several times, however, i couldn't find the answers which can help my case.
the query is:
I have a Form having a choice field which loads its choices information from the database. Basically, I have designed my models in such a way that, the choices displayed is individual to the users.
for example:
for user1, the choice field shows a,b,c,d.
where as for user 2, the choice field shows v,w,d.
The problem i am facing is referencing the logged in user and getting the username. then pass the username as the filter to the database.
I have come across numerous init functions trying to do this, somehow it is not helping my case.
forms.py
class class_model(forms.Form):
class_name = forms.ChoiceField(
required=False,
widget=forms.Select,
)
def __init__(self, user, *args, **kwargs):
self.user = user
super (class_model, self).__init__(*args, **kwargs)
current_user = self.user
name = current_user.username
k = User.objects.get(username=name)
y = UserProfile.objects.get(user=k)
schoolid = y.schoolid
primary_filter = Class1.objects.filter (school_id=schoolid)
ax = [("Choose Class", "Choose Class")] + list (primary_filter.objects.values_list ('class_name', 'class_name').distinct())
self.fields['class_name'].choices = ax
The error i receive: 'QueryDict' object has no attribute 'username'
Update:
views.py
#login_required(login_url="login/")
def create(request):
print(request.method)
if request.method == 'POST':
form2 = class_model(request.POST, request.user)
if form2.is_valid():
class_name = form2.cleaned_data['class_name']
return render(request, 'create_student.html', {'form2': form2}
else:
print(form.errors)
return render(request, 'create_student.html', {'form2': form2})
You've told the form to expect the user as the first positional parameter, so you need to pass it there.
form2 = class_model(request.user, data=request.POST)

Categories