Django form not saving - cannot identify problem with code - python

Trying to save the below form, but it's not saving.
The traceback doesn't identify any problem, and print(form.errors) doesnt not return any issue.
I have the exact same code working for another page. So I am not sure what I am missing here. There has to be a typo, I cannot find it.
You will notice that I have an autocomplete function in my template. I initially thought autocomplete was not returning data in all the fields, so also tried to input data manually but not luck either.
Also tried with and without is_ajax but same result.
models.py:
class Venue(models.Model):
name = models.CharField(verbose_name="Name",max_length=100, null=True, blank=True)
address = models.CharField(verbose_name="Address",max_length=100, null=True, blank=True)
town = models.CharField(verbose_name="Town",max_length=100, null=True, blank=True)
county = models.CharField(verbose_name="County",max_length=100, null=True, blank=True)
post_code = models.CharField(verbose_name="Post Code",max_length=8, null=True, blank=True)
country_1 = models.CharField(verbose_name="Country1",max_length=100, null=True, blank=True)
country_2 = models.CharField(verbose_name="Country2",max_length=100, null=True, blank=True)
longitude = models.CharField(verbose_name="Longitude",max_length=50, null=True, blank=True)
latitude = models.CharField(verbose_name="Latitude",max_length=50, null=True, blank=True)
phone = models.CharField(max_length=120)
web = models.URLField('Website Address')
email_address = models.EmailField('Venue Email Address')
def __str__(self):
return str(self.name) if self.name else ''
forms.py:
class VenueForm(ModelForm):
name = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"name"}))
address = forms.CharField(max_length=100, widget = forms.TextInput(attrs={'id':"address"}))
town = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"town"}))
county = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"county"}))
post_code = forms.CharField(max_length=8, required=True, widget = forms.TextInput(attrs={'id':"post_code"}))
country_1 = forms.CharField(max_length=40, required=True, widget = forms.TextInput(attrs={'id':"country_1"}))
country_2 = forms.CharField(max_length=40, required=True, widget = forms.TextInput(attrs={'id':"country_2"}))
longitude = forms.CharField(max_length=50, required=False, widget = forms.TextInput(attrs={'id':"longitude"}))
latitude = forms.CharField(max_length=50, required=False, widget = forms.TextInput(attrs={'id':"latitude"}))
phone = forms.CharField(max_length=120,required=False)
web = forms.URLField(max_length=120,required=False)
email_address = forms.CharField(max_length=120, required=False)
class Meta:
model = Venue
fields = ['name', 'address', 'town', 'county', 'post_code','country_1','country_2','longitude','latitude','web', 'phone', 'email_address']
views.py:
def google_api_test(request):
submitted = False
form = VenueForm()
if is_ajax(request) and request.method =="POST":
form = VenueForm(data = request.POST)
if form.is_valid():
form.save()
messages.success(request,("Success!"))
return redirect('home')
else :
print(form.errors)
context = {
'form' : form,
'submitted' : submitted,
'google_api_key' : settings.GOOGLE_API_KEY,
'base_country' : settings.BASE_COUNTRY,
}
return render(request,"main/google_api_test.html", context)
html file:
<div class = "form-group">
<input id="autocomplete" style ="width: 500px "placeholder="Enter your address">
<form id="venueform" method="POST" action="">
{% csrf_token %}
{{ form|as_crispy_errors }}
<td class="label">Name (Name)</td>
{{form.name| as_crispy_field}}
</br>
<td class="label">Street Number + Street Name (Address)</td>
{{form.address| as_crispy_field}}
</br>
<td class="label">Town (town)</td>
{{form.town | as_crispy_field}}
</br>
<td class="label">Country(country_1)</td>
{{form.country_1| as_crispy_field}}
</br>
<td class="label">Post Code (post_code)</td>
{{form.post_code| as_crispy_field}}
</br>
<td class="label">Country(country_2)</td>
{{form.country_2| as_crispy_field}}
</br>
<td class="label">Country(longitude)</td>
{{form.longitude| as_crispy_field}}
</br>
<td class="label">Country(latitude)</td>
{{form.latitude| as_crispy_field}}
</br>
<td class="label">phone(phone)</td>
{{form.phone| as_crispy_field}}
</br>
<td class="label">web(web)</td>
{{form.web| as_crispy_field}}
</br>
<td class="label">email_address(email_address)</td>
{{form.email_address| as_crispy_field}}
</br>
<button type="submit" value="Submit" id="profile-btn">Validate</button>
</form>
</div>

Firstly, I'd recommend you to check whether the form even goes to the POST method of google_api_view or not since you mentioned form.errors prints nothing.
Remove the empty action="" from the html form, since Django always takes current page route or url, so it is unnecessary.
Also suggest not to use is_ajax(request) only for one time to check(I think it's depreciated).
So, try this view:
def google_api_test(request):
submitted = False
form="" # for the error - local variable 'form' referenced before assignment if occurs.
if request.method == 'POST':
print("POST method") # check it prints it or not.
form = VenueForm(request.POST)
if form.is_valid():
form.save()
messages.success(request,"Success!")
return redirect('home')
else:
print(form.errors)
else: # GET request
form = VenueForm()
context = {
'form' : form,
'submitted' : submitted,
'google_api_key' : settings.GOOGLE_API_KEY,
'base_country' : settings.BASE_COUNTRY,
}
return render(request,"main/google_api_test.html", context)
Also share Ajax and jQuery code.

county is missing in your template. It's weird that your print(form.errors) did not show up in your terminal - it should have

def google_api_test(request):
submitted = False
if is_ajax(request) and request.method == 'POST':
print(request.POST) # Check--Are you getting form data
form = VenueForm(data = request.POST)
if form.is_valid():
form.save()
messages.success(request,("Success!"))
return redirect('home')
else :
print(form.errors)
else:
form = VenueForm() #Changes in here.
context = {
'form' : form,
'submitted' : submitted,
'google_api_key' : settings.GOOGLE_API_KEY,
'base_country' : settings.BASE_COUNTRY,
}
return render(request,"main/google_api_test.html", context)

Related

Django Models - Form saves but model is blank

Not sure my title is fully representing my problem.
I thought I would put a screenshot of the problem (admin panel), so it's clearer for everyone
It looks like the form is savings, but nothing goes inside.
Here is the models code:
class Venue(models.Model):
name = models.CharField(verbose_name="Name",max_length=100, null=True, blank=True)
address = models.CharField(verbose_name="Address",max_length=100, null=True, blank=True)
town = models.CharField(verbose_name="Town",max_length=100, null=True, blank=True)
county = models.CharField(verbose_name="County",max_length=100, null=True, blank=True)
post_code = models.CharField(verbose_name="Post Code",max_length=8, null=True, blank=True)
country = models.CharField(verbose_name="Country",max_length=100, null=True, blank=True)
longitude = models.CharField(verbose_name="Longitude",max_length=50, null=True, blank=True)
latitude = models.CharField(verbose_name="Latitude",max_length=50, null=True, blank=True)
city = models.CharField(max_length=120)
def __str__(self):
return str(self.name) if self.name else ''
Obviously, I am aware I have asked to return '' if self.name wasnt there. The reason why I did it, is because initially, the models was visible on the admin panel under "-" but was throwing an error message when clicking on it.
Considering I am working with a form, here is the form code:
class VenueForm(forms.ModelForm):
name = forms.CharField(max_length=100, required=True, widget = forms.HiddenInput())
address = forms.CharField(max_length=100, required=True, widget = forms.HiddenInput())
town = forms.CharField(max_length=100, required=True, widget = forms.HiddenInput())
county = forms.CharField(max_length=100, required=True, widget = forms.HiddenInput())
post_code = forms.CharField(max_length=8, required=True, widget = forms.HiddenInput())
country = forms.CharField(max_length=40, required=True, widget = forms.HiddenInput())
longitude = forms.CharField(max_length=50, required=True, widget = forms.HiddenInput())
latitude = forms.CharField(max_length=50, required=True, widget = forms.HiddenInput())
phone = forms.CharField(max_length=120)
web = forms.URLField(max_length=120)
email_address = forms.CharField(max_length=120)
class Meta:
model = Venue
fields = ['name', 'address', 'town', 'county', 'post_code','country','post_code','latitude','city', 'web', 'phone', 'email_address']
the views
def add_venue(request):
submitted = False
form = VenueForm()
if is_ajax(request) and request.method =="POST":
form = VenueForm(data = request.POST)
if form.is_valid():
form.save()
messages.success(request,("Success!"))
return HttpResponseRedirect('/add_venue?submitted=True')
context = {
'form' : form,
'submitted' : submitted,
'google_api_key' : settings.GOOGLE_API_KEY,
'base_country' : settings.BASE_COUNTRY,
}
return render(request,"main/add_venue.html",context)
and finally the html file
<div class="form-group">
<input type="text" placeholder="*Begin typing address" id="id-google-address" name="google_address">
<form id="venueform" method="POST" action="{% url 'add_venue'%}">
{% csrf_token %}
<label for="name" class="hidden-el" hidden>Name</label>
{{form.name}}
<label for="address" class="hidden-el" hidden>Address</label>
{{form.address}}
<label for="town" class="hidden-el" hidden>Town/City</label>
{{form.town}}
<label for="county" class="hidden-el" hidden>County</label>
{{form.county}}
<label for="post_code" class="hidden-el" hidden>Postal Code</label>
{{form.post_code}}
<label for="country" class="hidden-el" hidden>Country</label>
{{form.country}}
<label for="longitude" class="hidden-el" hidden>Longitude</label>
{{form.longitude}}
<label for="latitude" class="hidden-el" hidden>Latitude</label>
{{form.latitude}}
<h4>Phone</h4>
<label for="phone" class="hidden-el" hidden>Phone</label>
{{form.phone}}
<h4>WebSite</h4>
<label for="web" class="hidden-el" hidden>Website</label>
{{form.web}}
<h4>Email Address</h4>
<label for="email_address" class="hidden-el" hidden>Email Address</label>
{{form.email_address}}
<button type = "submit" class="btn btn-secondary">Add Venue</button>
</form>
</div>
{% endblock %}
{% block extend_footer %}
<script type="text/javascript">
var google_api_key = "{{google_api_key|safe}}";
var base_country = "{{base_country|safe}}";
</script>
<script src="{% static 'google_places.js' %}"></script>
{% endblock %}
def add_venue(request):
submitted = False
form = VenueForm()
venue = Venue.objects.create() # <- This line is the issue.
You are creating an empty venue, and not going anything with the variable.
Then, you are saving the form
data = form.save(commit = False)
data.name = form.cleaned_data['name']
data.address = form.cleaned_data['address']
data.town = form.cleaned_data['town']
data.county = form.cleaned_data['county']
data.post_code = form.cleaned_data['post_code']
data.country = form.cleaned_data['country']
data.longitude = form.cleaned_data['longitude']
data.latitude = form.cleaned_data['latitude']
data.city = form.cleaned_data['city']
data.phone = form.cleaned_data['phone']
data.web = form.cleaned_data['web']
data.email_address = form.cleaned_data['email_address']
data.save()
Without having validated the form first.
You need to call form.is_valid() before any of this.
Then, you are validating the form, and saving the form again.
You are trying a single object, 3 times. 2 of which are executed wrong.
Then, you are not instantiating your form in the
else:
form = VenueForm
if 'submitted' in request.GET:
submitted = True
And on top of that, you should return the form POSTed, so you can send back the form.errors().
else:
form = VenueForm()
if 'submitted' in request.GET:
submitted = True
If this is a ModelForm, all that is needed is:
def add_venue(request):
submitted = False
form = VenueForm()
if is_ajax(request) and request.method =="POST":
form = VenueForm(data = request.POST)
if form.is_valid():
form.save()
messages.success(request,("Success!"))
return HttpResponseRedirect('/add_venue?submitted=True')
context = {
'form' : form,
'submitted' : submitted,
'google_api_key' : settings.GOOGLE_API_KEY,
'base_country' : settings.BASE_COUNTRY,
}
return render(request,"main/add_venue.html",context)

django dynamic forms setting max_length property

I am creating a 'Forms Management' system for my application.
I am creating a forms dynamically using a custom form 'factory' method.
Form data is in a json file.
I can create a forms.CharField and set the label, required, initial and help_text properties.
When I try to set the max_length property I do not get any error message, but the resulting HTML does not contain the max_length attribute.
In static (class) forms defined as
class SearchAccountForm(forms.Form):
provider_code = forms.CharField(
label='Provider:',
max_length=100,
required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
The resulting HTML contains the max_length attribute.
<label for="id_provider_code">Provider:</label>
</th><td><input type="text" name="provider_code" class="form-control" maxlength="100" required id="id_provider_code">
So what's up with max_length??
Json file
{
"form1": [
{
"fld_name": "customer_name",
"fld_type": "CharField",
"fld_label": "Cust Name",
"fld_required": "False",
"fld_maxLength": 5,
"initial": "Dr John"
},
{
"fld_name": "customer_number",
"fld_type": "CharField",
"fld_label": "Cust #",
"fld_required": "True",
"fld_maxLength": 15,
"help_text": "Enter account number"
},
{
"fld_name": "customer_type",
"fld_type": "CharField",
"fld_label": "Customer Type",
"fld_required": "False"
}
]
}
and the forms.py factory method
from django import forms
import json
def dynfrm():
f = open('blog/frmJson/frm1.json')
data = json.load(f)
fields = {}
for i in data['form1']: ## form1 = form name in json file
print(i)
## add to fields list
if i['fld_type'] == 'CharField':
fields[i["fld_name"]] = forms.CharField()
if 'fld_label' in i:
fields[i["fld_name"]].label = i["fld_label"]
if 'fld_required' in i:
if i["fld_required"] == 'False':
fields[i["fld_name"]].required = False
else:
fields[i["fld_name"]].required = True
if 'initial' in i: fields[i["fld_name"]].initial = i["initial"]
if 'help_text' in i: fields[i["fld_name"]].help_text = i["help_text"]
## next line not working
if 'fld_maxLength' in i: fields[i["fld_name"]].max_length = i["fld_maxLength"]
fields[i["fld_name"]].widget = forms.TextInput()
return type('DynForm', # form name is irrelevant
(forms.BaseForm,),
{'base_fields': fields})
my view
def vdynfrm(request):
if request.method == 'POST':
form = dynfrm(request.POST)
if form.is_valid():
pass
## all good
else:
form = dynfrm()
##return render(request, "blog/dfrm.html",{'form': form})
return render(request, "blog/searchAccount.html",{'form': form})
and the resulting HTML
<div class="form-group">
<form action="/searchAccount/" method="post">
<table>
<tr>
<th><label for="id_customer_name">Cust Name:</label></th>
<td><input type="text" name="customer_name" value="Dr John" id="id_customer_name">/td>
</tr>
<tr>
<th><label for="id_customer_number">Cust #:</label></th>
<td><input type="text" name="customer_number" required id="id_customer_number"><br>
<span class="helptext">Enter account number</span></td>
</tr>
<tr>
<th><label for="id_customer_type">Customer Type:</label></th>
<td><input type="text" name="customer_type" id="id_customer_type"></td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
</div>
The max_length property only works when you send the context correctly to your template file.
your forms.py
class SearchAccountForm(forms.Form):
provider_code = forms.CharField(
label='Provider:',
max_length=100,
required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
With function based view:
def home(request):
if request.method == 'POST':
form = SearchAccountForm(request.POST)
if form.is_valid():
provider_c= form.cleaned_data['provider_code']
print('Provider Code :',provider_c)
return HttpResponseRedirect('/thanks/')
else:
form = SearchAccountForm()
return render(request, 'home/index.html', {'form': form})
def thanks(req):
return render(req, 'home/thanks.html')
If you forget to give else condition for get request method, so you will not receive django's inbuild error messages as well as max_length etc.
With Class based view it can be handled easily:
from django.views.generic.edit import FormView
class Home(FormView):
template_name = 'home/index.html'
form_class = SearchAccountForm
success_url = '/thanks/'
def form_valid(self, form):
print(form)
print('Provider Code : ', form.cleaned_data['provider_code'])
return super().form_valid(form)
def thanks(req):
return render(req, 'home/thanks.html')
From both the examples above max_length property is working properly because its get request got handled.
Check your views.py, it may help.

How to can I upload a form on django

I am trying to make a matchmaking project on python django such as snapchat's hoop, but first I am trying to do the easiest part(what I know) which is just making the user create a profile to find a mate and then show that created profile to the other users, currently I am not using any matchmaking based on questions, I need to first show the created user to other users. The error comes when I pass the variables to the html via for loops, and now the mates.html file doesnt show anything. Please if you need more explanation let me know in the comments.
models.py (Profile model show the profile of the user which is created by default wen the user is created and Mates model shows the profile that the user has to create which provide an image and a description)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=400, default=1, null=True)
class Mates(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
users_requests = models.ManyToManyField(User, related_name="users_requests")
req_bio = models.CharField(max_length=400)
req_image = models.ImageField(upload_to='requestmates_pics', null=True, blank=True, default=False)
views.py
def matesmain(request):
contents = Mates.objects.all()
args123 = {
'contents': contents,
}
return render(request, 'mates.html', args123)
def mates(request):
if request.method == 'POST':
form_mates = MatesForm(request.POST, request.FILES)
if form_mates.is_valid():
instance = form_mates.save(commit=False)
instance.user = request.user
instance.save()
return redirect('mates-main')
print('succesfully uploded')
else:
form_mates = MatesForm()
print('didnt upload')
return render(request, 'mates.html', {'form_mates': form_mates})
forms.py
class MatesForm(forms.ModelForm):
class Meta:
model = Mates
fields = ('req_bio', 'req_image',)
urls.py
urlpatterns = [
path('mates', views.mates, name='mates'),
path('mates-main', views.matesmain, name='mates-main'),
]
mates.html
<div class="mates">
<div class="mates-container">
{% for content in contents %}
<div class="mates-item">{{ content.user }}
</div>
{% endfor %}
<div class="mates-item">content(picture)
<form action="{% url 'mates' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form_mates.as_p }}
</form>
</div>
</div>
</div>
If you are displaying the form with the second function (mates), then you aren't sending any context for your fields to iterate over. Try like so:
def mates(request):
if request.method == 'POST':
form_mates = MatesForm(request.POST, request.FILES)
if form_mates.is_valid():
instance = form_mates.save(commit=False)
instance.user = request.user
instance.save()
return redirect('mates-main')
print('succesfully uploded')
else:
form_mates = MatesForm()
print('didnt upload')
context = {
'form_mates': form_mates,
'contents': Mates.objects.all()
}
return render(request, 'mates.html', context)
and in your other view (matesmain):
contents = Mates.objects.all()
args123 = {
'contents': contents,
'form_mates': MatesForm()
}
return render(request, 'mates.html', args123)
I'm not sure I understand, however, why you have two separate views for this.

Django Forms - DateInput not populating from instance

I'm trying to set up an edit form for a Django model which includes a DateField. I've set this field as a forms.DateInput in forms.py. This works fine for creating a new instance of the model, but when I try to populate the form with an existing instance the DateInput field remains blank even though all of the other fields are populated correctly.
If I revert to the default TextField input then the data is recalled correctly. I've also tried to set a format in the DateInput widget.
models.py
class Rider(models.Model):
first_name = models.CharField(max_length=40)
surname = models.CharField(max_length=40)
MALE = 'M'
FEMALE = 'F'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
]
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
dob = models.DateField("Date of Birth", auto_now = False, auto_now_add = False)
club = models.CharField(max_length=50,blank=True, null=True)
bc_number = models.IntegerField("British Cycling Membership Number", blank=True, null=True)
linked_account = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
views.py
def rider_edit(request, pk):
rider = get_object_or_404(Rider, pk=pk)
if request.method == "POST":
form = RiderForm(request.POST, prefix='rider', instance=rider)
if form.is_valid():
rider = form.save(commit=False)
rider.linked_account = request.user
rider.save()
return redirect('rider_list')
else:
form = RiderForm(prefix='rider', instance=rider)
return render(request, 'riders/rider_new.html', {'riderform': form})
form.py
from django import forms
from .models import Rider, MedicalInfo
class RiderForm(forms.ModelForm):
class Meta:
model = Rider
fields = ('first_name', 'surname', 'gender', 'dob', 'club', 'bc_number')
widgets= {
'dob': forms.DateInput(attrs={'type': 'date'}, format='%d/%m/%Y')
}
rider_new.html
<h2>New Rider</h2>
<form method="POST" class="post-form">
{% csrf_token %}
{{ riderform.as_p }}
<button type="submit" class="save btn btn-default">Add Rider</button>
</form>
The dob field is the only field that doesn't populate correctly from the database, it should show a date in the format dd/mm/YYYY e.g. "10/09/2010". It's actually showing the default "dd/mm/YYYY".
I found a solution to the problem, the date from the database was being returned in "%d/%m/%Y" format but the input on the form was of the "date" type which expects an input in the format "%Y-%m-%d", by changing:
widgets= {
'dob': forms.DateInput(format=('%d/%m/%Y'), attrs={'class':'form-control', 'placeholder':'Select Date','type': 'date'})
}
to:
widgets= {
'dob': forms.DateInput(format=('%Y-%m-%d'), attrs={'class':'form-control', 'placeholder':'Select Date','type': 'date'})
}
Therefore, the generated HTML form changed from:
<input type="date" name="rider-dob" value="10/09/2010" class="form-control" placeholder="Select Date" required="" id="id_rider-dob">
to:
<input type="date" name="rider-dob" value="2010-09-10" class="form-control" placeholder="Select Date" required="" id="id_rider-dob">

How to Initialize a django form with values from a model

I am making a shopping website, I am trying to initialize my products update form with the product information but I cant get the information from the model into the form.
models function
def get_product_details(product_id):
product_details = Products.objects.filter(name=rproduct_id).select_related('name', 'description','price','qty')
return product_details
form.py
class UpdateProductForm(forms.Form):
name = forms.CharField(
max_length=200,
required=True,
label="* name:",
widget=TextInput(attrs={'class' : 'span6 small-margin-top small-margin-bottom'}),
)
description = forms.CharField(
max_length=200,
required=True,
label="* description:",
widget=TextInput(attrs={'class' : 'span6 small-margin-top small-margin-bottom'}),
)
price = forms.IntegerField(
label="* price:",
widget=TextInput(attrs={'class' : 'span6 small-margin-top small-margin-bottom'}),
)
qty = forms.IntegerField(
label="* Qty:",
widget=TextInput(attrs={'class' : 'span6 small-margin-top small-margin-bottom'}),
)
view.py
def update_risk(request,product_id):
product_details = get_product_details(product_id)
name = form.cleaned_data['name']
description = form.cleaned_data['description']
price = form.cleaned_data['price']
qty = form.cleaned_data['qty']
form = UpdateProductForm(product_details)
return render(
request,
template_name = 'products/forms/update_product_form.html',
dictionary = {
'form':form,
'instr_text':instr_text
}
)
update form
<form method="POST" action="{% url 'products:update'%}">
{% csrf_token %}
{{ form.name }}
{{ form.description }}
{{ form.price }}
{{ form.qty }}
</form>
You could use ModelForms, which are designed not only to match the fields of the model, but also can easily be initialized with the data from a model.
See here for a general description: https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/
Specifically, if the form is a ModelForm, you can do this:
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)

Categories