Django Form not saving to database? - django

I am using CreateView to create entries on my frontend and then save to the database/backend. But each time i click save or submit the form redirect successfully as expected but will not save to the back end.
I have tried adding success_url to my views.py and also added get_absolute_url(self) to my models.py but still it hasn't worked.
Views.py
class Dashboard (LoginRequiredMixin, CreateView):
model = PostedJob
template_name ='accounts/dashboard.html'
fields = ['firstname', 'lastname', 'job_title', 'email', 'budget',
'country', 'state', 'address', 'job_category',
'description', 'photo']
success_message = "Redirect successfully created!"
login_url= 'login'
models.py
Type = (
('building inspection', 'Building Inspection'),
('agriculture', 'Agriculture'),
('construction', 'Construction'),
('maintenance & training', 'Maintenance & Training'),
('surveying & mapping', 'Surveying & Mapping'),
('events coverage', 'Events Coverage'),
)
class PostedJob(models.Model):
firstname=models.CharField(max_length=200)
lastname=models.CharField(max_length =150)
email=models.EmailField(max_length =150)
job_title= models.CharField(max_length =150)
budget=models.PositiveIntegerField()
country=models.CharField(max_length = 150)
state=models.CharField(max_length = 150)
address=models.CharField(max_length = 150)
job_category=models.CharField(choices=Type, default ='agriculture',
max_length=50 )
photo= models.ImageField(upload_to='/%Y/%m/%d/', blank=False,
null=False)
description=models.TextField(max_length = 1500)
post_date=models.DateTimeField(default = datetime.now, blank=True)
publish=models.BooleanField(default =False)
def __str__(self):
return self.job_title
def get_absolute_url(self):
return reverse('home')
urls.py
urlpatterns =[
path('accounts/dashboard', Dashboard.as_view(), name='dashboard'),
]
index.html
<form action="" method="post">
{% csrf_token %}
{{form.as_p}}
<div>
<input type="submit" id="submit" value="Submit" class="btn waves-
effect waves-grey green">
</div>
</form>
Also the form displays no error message. I will indeed be grateful for your help. Thanks.

The form shows no errors but using the following SQL queries in Python prompt
revealed the error :
from django.db import connection
cursor = connection.cursor()
error: django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are
not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call
settings.configure() before accessing settings.
** Updated**
However the environment variable does not really solve this. The problem is actually from the form itself. The form has an image field which is required by default. The form even though it redirect successfully on click, did not save to the database. The reason being that since all fields are required, the image will returning a blank field on every save or submit action causing the form to constantly not save on every submit action.
Solution: Simply add enctype="multipart/form-data to your form.
<form action="" method="POST" enctype="multipart/form-data">

Related

How to integrate a form into a Detail View?

I would like to do:
I am trying to create a form input on a detail view that will update a particular data column ('status') of the detailed model instance. Here is a picture of what I have in mind:
The selector would display the current status and the user could change it and update from the detail view without having to access the UpdateView.
my idea here would be to have this happen:
1. On submit, get the new user entered value.
2. get the model instance of the currently detailed class
3. assign the model instance attribute as the user entered value
4. save the model instance
I've tried: I don't know if this is the best way to do this but i've been trying to create an AJAX call, mostly by looking for examples online.
Results: Terminal shows Post on submit: "[19/Nov/2019 17:50:33] "POST /task/edit/4 HTTP/1.1" 200 41256". However, the data is not saved to the db. On refresh, the selector returns to previously saved status.
The console shows: "script is connected", and "Update Status" with no errors. On submit, the alert displays success message: "127.0.0.1:8000 says status updated".
Task_detail.html
<div class="deliv-box edit">
<form id="status-update-form" method='POST' action='{% url "task_edit" task.pk %}'>
{% csrf_token %}
{{task_form.status}}
<input id="status-update-btn" type="submit" value="Update Status" />
</form>
</div>
...
<script type="text/javascript">
var frm = $('#status-update-form');
frm.submit(function () {
console.log("script is connected")
console.log($('#status-update-btn').val())
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
$("#deliv-box edit").html(data);
alert("status updated");
},
error: function(data) {
alert("error");
}
});
return false;
});
</script>
forms.py
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = "__all__"
views.py
class TaskDetail(ModelFormMixin, DetailView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
def get_context_data(self, **kwargs):
context = super(TaskDetail, self).get_context_data(**kwargs)
context['task_form'] = self.get_form
return context
def update(request):
if request.method=='POST':
task_id = request.POST.get('id')
task = Task.objects.get(pk = task_id)
status_obj = request.POST.get('status')
task.status = status_obj
task.save()
return JsonResponse({'status':'updated...'})
else:
return JsonResponse({'status':'not updated'})
thank you.
A solution:
In the unlikely event that someone stumbles across this question and who is, like me, just trying to figure it out all by themselves, here is what I've learned about how this works: When a user wants to update a form, Django pre-populates the form with the existing data related to that instance. A user can then alter the data and re-submit the form.
Here, I was attempting to alter just one field of the exiting instance, but as I was only calling that one field, Django was assuming not, as I had hoped, that the other fields would remain the same, but that I intended the other fields to be submitted as blank. Where the fields are required one cannot return that field as blank. Therefore, Django was not able to validate the form and so the form did not get updated.
A solution that works is to call all the fields as hidden and show just the one you want to alter. This way Django can return the unaltered data and validate the form, and you get an update button on your detail view:
<form method="POST">
{% csrf_token %}
<h4> STATUS: </h4>
{% for field in form %}
{{ field.as_hidden }}
{% endfor %}
{{form.status}}
<button type="submit" class="btn btn-success">submit</button>
</form>
You are overriding the method update which does not exist, so it is never called.
You need to subclass UpdateView instead of the DetailView and the mixin.
class TaskUpdateView(UpdateView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
# you can use the line below instead of defining form_class to generate a model form automatically
# fields = ('status', )
def form_valid(self, form):
post = form.save(commit=False)
# do anything here before you commit the save
post.save()
# or instead of two lines above, just do post = form.save()
return JsonResponse({'status':'updated...'})
Here is how you would add readonly (disabled) fields to your form:
class TaskForm(forms.ModelForm):
# override the default form field definitions for readonly fields
other_field = forms.CharField(disabled=True)
another_field = forms.IntegerField(disabled=True)
class Meta:
model = Task
fields = ("status", "other_field", "another_field")
# you could also just do:
# fields = '__all__'

Understanding Django and Django FormView

I am trying to create a Django web app that accepts text in a form/textbox, processes it and redirects to a webpage showing the processed text . I have written a half-functioning app and find de-bugging quite challenging because I don't understand most of what I've done. I'm hoping you will help me understand a few concepts, Linking to resources, also appreciated.
Consider this simple model:
class ThanksModel(models.Model):
thanks_text = models.CharField(max_length=200)
Is the only way to set the text of thanks_text through the manage.py shell? This feels like a pain if I just have one piece of text that I want to display. If I want to display a webpage that just says 'hi', do I still need to create a model?
Consider the view and template below:
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html'
form_class = TestForm
success_url = '/thanks/'
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
I need to create another model, view and html template and update urls.py for '/thanks/' in order for the success_url to redirect correctly? (That's what I've done.) Do I need to use reverse() or reverse_lazy() the success_url in this situation?
Models are used when you are dealing with Objects and Data and DataBases that can contain a lot of information.
For Example A Person would be a model. their attributes would be age, name, nationality etc.
models.py
class Person(models.Model):
Name = models.CharField(max_length=50)
age = models.IntegerField()
nationality = models.CharField(max_length=50)
Thi deals with multiple bits of information for one object. (the object being the person)
A Thank you message would not need this? so scrap the model for the thank you message. just have views where you create the view using a templates and setting the view to a url.
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html' # self explantory
form_class = TestForm # grabs the test form object
success_url = reverse_lazy('vader:thanks') # this makes sure you can use the name of the url instead of the path
def ThanksView(request): # its simple so you don't even need a class base view. a function view will do just fine.
return render(request,"thanks.html")
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
thanks.html
<h1>Thank you for Submitting</h1>
<h2> Come Again </h2>
url.py
from django.urls import path
from djangoapp5 import views
urlpatterns = [
path('', TestView.as_view(), name='test_form'),
path('thanks/', views.ThanksView, name='vader:thanks'),
]
I haven't tested this but hopefully it helps and guide you in the right direction

Django: Unable to open a detail view by URL, which causes reverse argument errors in another view

Python 3.5.1
Django 1.10
Been tearing my hair out for hours on this, but have my Reverse Argument error pinned down to the actual problem.
When I try to open a form to edit a particular record in my model, it only opens a blank (unconnected) form. Using the same logic, I am able to delete a record, so I'm sure this is something stupid-simple. But I'm too many hours into this, so I would appreciate a lifeline.
From models.py
class CmsSpaces(models.Model):
sid = models.AutoField(db_column='SID', primary_key=True)
section = models.CharField(db_column='Section', max_length=5)
...Many more columns...
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('cms_spaces:space_edit', args = (self.sid), kwargs=None)
return reverse('cms_spaces:space_delete', args = (self.sid), kwargs=None)
return reverse('cms_spaces:space_new', args = None, kwargs = None)
class Meta:
managed = False
db_table = 'cms_spaces'
From views.py
def CmsSpaces_update(request, sid,
template_name='space_edit.html'):
space = get_object_or_404(CmsSpaces, sid=sid)
form = space_form(request.POST or None, instance=space)
if form.is_valid():
form.save()
return redirect('space_list')
return render(request, template_name, {'form':space_form})
def CmsSpaces_delete(request, sid,
template_name='space_delete.html'):
space = get_object_or_404(CmsSpaces, sid=sid)
if request.method=='POST':
space.delete()
return redirect('space_list')
return render(request, template_name, {'object':CmsSpaces})
From urls.py
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from cms_spaces import views
urlpatterns = [
url(r'^space_list/$', views.CmsSpaces_list, name='space_list'),
url(r'^space_new/$', views.CmsSpaces_create, name='space_new'),
url(r'^space_edit/(?P<sid>[\w-]+)/$', views.CmsSpaces_update, name='space_edit'),
url(r'^space_delete/(?P<sid>[\w-]+)/$', views.CmsSpaces_delete, name='space_delete'),
]
From space_edit.html. When I enter the url directly for .../space_delete/12345, it does proceed to delete the record with sid=12345.
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Add or Update Space" />
</form>
From space_list.html (which throws "Reverse for 'space_edit' with arguments '(10256,)' and keyword arguments '{}' not found. 0 pattern(s) tried: []") as an error. 10256 is in fact an sid for one of the records in the table. When I remove the links to space_edit and space_delete, it does render the list of records. Yes, there are many more lines of code that handle presentation, but this is the boiled down version, and it is "broken" even at this level.
<ul>
{% for CmsSpaces in space_list %}
<li>{{CmsSpaces.sid}} {{ CmsSpaces.section }} {{ CmsSpaces.space}} {{ CmsSpaces.lot }} {{ CmsSpaces.deednum}}
edit
delete
</li>
{% endfor %}
</ul>
All I want to do is be able to call and edit a record. If I can do that, I believe the list view will work, and then I'm well on my way to home free. The issue seems to be that even though it is correctly capturing the sid, it is failing to correctly pass it as an argument to the model. Help! Thanks.
EDIT
from django import forms
from django.forms import ModelForm
from masterdata.models import CmsSpaces
class space_form(ModelForm):
class Meta:
model = CmsSpaces
fields = [
'sid',
'section',
'space',
'lot',
'deednum',
'purchdate',
'notes',
'perpetualcare',
]
Okay... first off a big thanks to #knbk for getting me on track with the list issue.
Second, my initial diagnosis in the OP was wrong. The issue was in my CmsSpaces_update view. Boiled down, the view had the pieces to tie the form to the record, but no actual code to do so. slaps head
So because someone else may someday read this and wonder the same thing...
def CmsSpaces_update(request, sid,
template_name='templates/space_edit.html'):
space = get_object_or_404(CmsSpaces, sid=sid)
form = space_form(request.POST or None, instance=space)
if form.is_valid():
form.save()
return redirect('space_list')
ctx = {}
ctx['form'] = form
ctx['space'] = space
return render(request, template_name, ctx)

Form fields missing in Django, just button visable

New to Django and having problem seeing form fields displayed. What I see is just the submit button. If pressed, the form is finally presented, but with the format for a form that had bad data (typical 'this field is required' error for each box, red box, etc).
The form works fine after entering data and again pressing submit (stores entries in my db). I have a number of forms on the same page that have the same behavior.
Example of one form:
#model
class dbPara(models.Model): #parameters
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
username = models.CharField(max_length=10)
turns = models.FloatField(default=27)
units = models.FloatField(default=5)
rise = models.FloatField(default=2.9)
rescutL = models.FloatField(default=0.0833333333)
rescutH = models.FloatField(default=0.333333333)
LorR = models.CharField(max_length=1, default='R')
def __str__(self):
return self.timestamp, self.username, self.turns, self.units, self.rise, self.rescutL, self.rescutH, self.LorR
#form
class ParaForm(ModelForm):
class Meta:
model = dbPara
widgets = {'username': forms.HiddenInput()}
fields =['username', 'turns', 'units', 'rise', 'rescutL', 'rescutH', 'LorR']
#view
def importParameters(request):
if request.method == 'GET':
form = ParaForm()
else:
form = ParaForm(request.POST)
if form.is_valid():
entry=dbPara(username = request.POST.get('username'),
turns = request.POST.get('turns'),
units = request.POST.get('units'),
rise = request.POST.get('rise'),
rescutL = request.POST.get('rescutL'),
rescutH = request.POST.get('rescutH'),
LorR = request.POST.get('LorR')
)
entry.save()
return render(request, 'main.html',
{'ParaHTML' : form })
#url
urlpatterns = patterns('Inputs.views',
url(r'^importParameters/$', 'importParameters', name='urlParameters'),
)
#main.html
<div class='col-lg-3'>
<h4>Set Rosetta Parameters</h4>
<action="{% url "urlParameters" %}" method="post">{% csrf_token %}
{{ ParaHTML|crispy }}
<input type="hidden" name = "username" value = "{{ user.get_username }}">
<input type="submit" class="btn btn-primary" value="Set">
</form>
</div>
Appreciate any advice (better simple than 'most correct but complicated')
Could it be due to using default in the model? Would that not 'fill in the form' and result in 'POST' at the initial visit to the page, resulting in just the button? Thoughts?
One Suggesestion here ....
if Using request.POST.get('anything') simply then it Will raise error if particular string not find as in example('anything') string...
Because request.POST.get('anything') will return None if 'anything' is not in request.POST.
Additionally, .get allows you to provide an additional parameter of a default value which is returned if the key is not in the dictionary.
e.g: Corrected will be request.POST.get('anything', 'mydefaultvalue')

Django: I can't succeed displaying multiple checkboxes in my template

I read the following thread: Django Multiple Choice Field / Checkbox Select Multiple
But I somehow miss something important as I can't succeed in displaying the checkboxes in my template. However, the name of the field does appear in the template but that's all, after the field name, it's all white and blank.
Curiously, in the thread I read, the author didn't wrote a list of tuple. That's why I think the problem could lie in the models.py
Here is my models.py
from django.db import models
from user.models import User
class RegionChoices(models.Model):
REGION_CHOICES = (
('London', 'Londres'),
('Paris', 'Paris'),
('Berlin', 'Berlin'),
)
region = models.CharField(max_length=30, choices=REGION_CHOICES)
def __str__(self):
return self.region
class Offer(models.Model):
publisher = models.ForeignKey(User)
content = models.TextField()
region_choices = models.ManyToManyField(RegionChoices)
def __str__(self):
return self.publisher.username
forms.py
from django import forms
from django.contrib import admin
from django.conf import settings
from offers.models import Offer, RegionChoices
class SendOfferForm(forms.ModelForm):
region_choices = forms.ModelMultipleChoiceField(queryset=RegionChoices.objects.all(), widget=forms.CheckboxSelectMultiple)
class Meta:
model = Offer
exclude = ['publisher']
offer.html
<form action="{% url "send_offer" %}" method='POST' class='sendofferform'>
{{ form.errors }}
{{ form.non_field_errors }}
{% csrf_token %}
{{ offerform.as_p }}
</form>
views.py
if offerform.is_valid():
sent = True
offer = offerform.save(commit=False)
offer.publisher = User.objects.get(id=logged_user.id)
offer.save()
offerform.save_m2m()
else:
print(offerform.errors)
From your code sounds like you want to limit the choices of region your project can have. I think you should create an admin for RegionChoices first. In there you could create entrances of RegionChoices you like. Follow the django docs if you are not sure how to create an admin interface for a model https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
ps: You might want to do unique=True on region field in RegionChoices. Otherwise you might create duplicate entries of the same region by accident.
Okay, I realize I had to load data in the model RegionChoices.
I loaded the data in the admin part of my website and now, it works perfectly.