Django Models - Form saves but model is blank - python

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)

Related

Django form not saving - cannot identify problem with code

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)

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 can I populate a manytomanyfield , using view, without django pre-built forms?

I'm building a storage web system using django, I'm very newbie on the framework, so the problem is that, there is a business rule, which demands, two kinds of products, the inside products, and the finished ones. And the finished ones, always are composed by one or more inside products, I have the idea of using the manytomanyfields, but now, I don't really know how to extract this data , that should be a multiple choice, from the form and save in the database, does anyone has any tips or better ideas?
Models.py
class Produto(models.Model):
codigo = models.CharField(max_length=254, null=True)
produto_desc = models.CharField(max_length=200, null=False)
tipo = models.CharField(max_length=2)
qtd = models.IntegerField(null=True, default=0)
created = models.DateTimeField(default=timezone.now, editable=False)
last_updated = models.DateTimeField(default=timezone.now, editable=False)
#Relationship Fields
estrutura = models.ManyToManyField(
'storage.Produto',
related_name="produto"
)
def __str__(self):
return self.produto_desc
Views.py
def CadastroProd(request):
temp = 0
lista_produto = Produto.objects.order_by('id')[:20]
for i in lista_produto:
temp += 1
if request.method == 'POST':
form = NovoProduto(request.POST)
if form.is_valid():
obj = Produto()
obj.save(commit=False)
obj.codigo = form.cleaned_data['codigo']
obj.produto_desc = form.cleaned_data['produto_desc']
obj.tipo = form.cleaned_data['tipo']
# obj.estrutura = form.cleaned_data['estrutura']
obj.save()
return HttpResponseRedirect('/storage/produtos')
lista_produto = Produto.objects.order_by('id')[:20]
lista_pi = Produto.objects.filter(tipo='PI')
lista_pa = Produto.objects.filter(tipo='PA')
context = {'lista_produto': lista_produto,
'temp': temp,
'lista_pi': lista_pi, 'lista_pa': lista_pa,
}
return render(request, 'storage/cadproduto/cadproduto.html', context)
forms.py
class NovoProduto(forms.Form):
codigo = forms.CharField(label='codigo', max_length=254)
produto_desc = forms.CharField(label='produto_desc', max_length=100)
tipo = forms.CharField(label='tipo', max_length=2)
estrutura = forms.IntegerField()
index
<div class="row">
<div class="col-md-3 mb-3">
<label for="pi-ida">Composição de Produtos Internos</label>
<select name="estrutura" multiple id="id_estrutura" required>
{%for prod in lista_pi%}
<option value="{{prod.id}}">{{prod.produto_desc}}</option>
{% endfor %}
</select>
</div>
</div>
<hr class="mb-4">
<button class="btn btn-primary btn-lg btn-block" type="submit">Cadastrar</button>
I expected that I can get information of the product, adn of the products that compose it
You are using your own custom template so get the selected choices list using the getlist() method and use set() method to save the manytomany field like this
Also if form is valid you need to save the form
if request.method == 'POST':
form = NovoProduto(request.POST)
estrutura = request.POST.getlist('estrutura')
if form.is_valid():
obj=form.save(commit=False)
obj.codigo = form.cleaned_data['codigo']
obj.produto_desc = form.cleaned_data['produto_desc']
obj.tipo = form.cleaned_data['tipo']
# obj.estrutura = form.cleaned_data['estrutura']
obj.save()
obj.estrutura.set(estrutura)
return redirect....
In your Form subclass, use ModelMultipleChoiceField:
class NovoProduto(forms.Form):
codigo = forms.CharField(label='codigo', max_length=254)
produto_desc = forms.CharField(label='produto_desc', max_length=100)
tipo = forms.CharField(label='tipo', max_length=2)
estrutura = forms.ModelMultipleChoiceField(queryset=Produto.objects.order_by('id')[:20])
The M2M field seems to be a self reference (unless you have two Models called Produto), so you might want to exclude the current product from the list of select options.
You can modify the queryset of a ModelMultipleChoiceField in the form's constructor:
def __init__(*args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance and self.instance.id:
self.fields['estrutura'].queryset = Produto.objects.exclude(id=self.instance.id).order_by('id')[:20]

Django convert current model/raw HTML input to Form to save input data

I have a simple form where there is a username and a message. Upon clicking the submit button, I want the data for user and message to be stored separately into the database. I am currently receiving an IntegrityError on m.save()
"Exception Value: SimpleMessage_message.content may not be NULL"
and was told to instead use forms to accomplish this. However, I am confused as to how to use a form to pass in form data to the individual User and Message Models so that the input data is saved in the database.
Models
class User (models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class Message (models.Model):
content = models.TextField(max_length=140, null=True, blank=True)
user = models.ForeignKey(User)
time = models.DateTimeField()
def __unicode__(self):
return self.content
views.py
def index (request):
if request.method == 'POST':
u = User(name=request.POST.get('user'))
u.save()
m = Message(content=request.POST.get('text'), user = u)
m.save()
return render_to_response('index.html', {
'user': u,
'message': m,
}, RequestContext(request))
else:
u = User()
m = Message()
return render_to_response('index.html', {
'user': u,
'message': m,
}, RequestContext(request)
)
index.html
<form action="{% url 'index' %}" method = "post">
{% csrf_token %}
<input type="text" name="user" id="user" maxlength="20" placeholder = "Username">
<br>
<br>
<textarea rows="4" cols="35" id="text" name="text" maxlength="140" placeholder = "Message goes here"></textarea><br>
<input type="submit" value="Submit">
</form>
Try changing your model so that content can be null:
class Message (models.Model):
content = models.TextField(max_length=140, null=True, blank=True)
Or give a default value in the form:
m = Message(content=request.POST.get('text', ' '), user = u)

File upload form in Django

I'm trying to create a simple upload form for my project in Django 1.5 an Python 2.7.
This is my File class:
class File(models.Model):
middleschool = 'MS'
highschool = 'HS'
university = 'U'
blank = '-'
school_choices = ((middleschool, 'Middle School'), (highschool, 'High school'), (university, 'University'), (blank, 'Not defined'),)
name = models.CharField(max_length = 30, primary_key=True, blank=False, null=False)
description = models.CharField(max_length = 140, blank=False, null=False)
school = models.CharField(max_length = 30, choices = school_choices, default = blank)
subject = models.ForeignKey(Subject)
user = models.ForeignKey(User)
rating = models.DecimalField(max_digits=2, decimal_places=0, default = 0)
price = models.DecimalField(max_digits=2, decimal_places=1, default = 0, blank=True, null=True)
file = models.FileField(upload_to= "/file/")
this is the form:
class UploadFileForm(forms.Form):
middleschool = 'MS'
highschool = 'HS'
university = 'U'
blank = '-'
school_choices = ((middleschool, 'Middle School'), (highschool, 'High school'), (university, 'University'), (blank, 'Not defined'),)
name = forms.CharField(max_length = 30, required = True)
file = forms.FileField()
description = forms.CharField(max_length = 140, required = False, label='Breif description of the files content')
school = forms.ChoiceField(choices = school_choices, required=False, label='What level is the material that are you uploading?', initial = blank)
subject = forms.ModelChoiceField(queryset=Subject.objects.order_by('?'), required=False, label='What subject this file is about?')
price = forms.IntegerField(required=False)
this is the view:
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
new_file = File(file = request.FILE['file'])
cd = form.cleaned_data
new_file.name = cd['name']
new_file.description = cd['description']
new_file.school = cd['school']
new_file.subject = cd['subject']
new_file.price = cd['price']
new_file.rating = '0.0'
new_file.user = request.user
new_file.save()
form = Search()
return render(request, 'home.html', {'form': form, 'request': request})
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form, 'request': request})
and this is the relative HTML
{% if request.user.is_authenticated %}
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload">
<input type="reset" value="Reset">
</form>
{% else %}
<p>You must be logged to upload a file</p>
{% endif %}
My app path is: C:/Users/User/Desktop/site_is/app_is/ and I want hose files saved in the folder: C:/Users/User/Desktop/site_is/app_is/static/file/. In my Setting.py I set:
MEDIA_ROOT = 'C:/Users/User/Desktop/site_is/app_is/static/file/'
MEDIA_URL = '/file/'
STATIC_ROOT = 'C:/Users/User/Desktop/site_is/app_is/static/'
STATIC_URL = '/static/'
The problem is: when i select the file and hit the upload button the FileField empties itself and the form raise an error since that field is required.
I fear I'm doing something wrong with the media/static paths in the Setting.py because the view syntax it's the same as the one in the Django docmentation but I really don't know how to solve this problem.
You should specify enctype in form tag to allow file upload.
<form action="" method="post" enctype="multipart/form-data">

Categories