Django ModelForm not rendering in the template - python

I've looked at several answers here and I can't get this to work. I'm trying to create a model form that will save the user's profile after he has signed up on the website. The problem is that when I try to render the form I get a blank page and no errors. Any help will be much appreciated.
models.py
class Perfil(models.Model):
user = models.OneToOneField(User)
Sexo = models.CharField(max_length=100)
Direccion = models.CharField(max_length=100)
CP = models.CharField(max_length=100)
Ciudad = models.CharField(max_length=100)
Estado = models.CharField(max_length=100)
Pais = models.CharField(max_length=100)
Telefono = models.CharField(max_length=100)
Celular = models.CharField(max_length=100)
PaisPasaporte = models.CharField(max_length=100)
NumeroPasaporte = models.CharField(max_length=100)
VigenciaPasaporte = models.DateField(max_length=100)
ContactoEmergencia = models.CharField(max_length=100)
TelefonoEmergencia = models.CharField(max_length=100)
CorreoEmergencia = models.CharField(max_length=100)
Alergias = models.CharField(max_length=500)
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Perfil
views.py
#verified_email_required()
def profile(request):
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
perfil = form.save(commit=False)
perfil.user = request.user
perfil.save()
return HttpResponseRedirect("/profile/")
else:
return render(request, "explore/profile.html", {"form": form})
return render(request, "explore/profile.html")
and finally my html
<form class="profile" id="profile_form" method="post" action="" style="width: 50%;">
{% csrf_token %}
{% for field in form %}
<table>
<colgroup>
<col style="width: 45%;">
<col style="width: 10%;">
<col style="width: 45%;">
</colgroup>
<tr>
<td>{{ field.label_tag }}</td>
<td></td>
<td>{{ field }}</td>
</tr>
</table>
{% endfor %}
</form>
Thanks!

You are sending the form in the context only when request type is POST. The first time the page loads, by default it is a GET request. Hence the issue
Something like this should work:
def profile(request):
form = ProfileForm()
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
perfil = form.save(commit=False)
perfil.user = request.user
perfil.save()
return HttpResponseRedirect("/profile/")
return render(request, "explore/profile.html" {'form': form})
Note that you dont need the else clause at all - if the form is invalid, it automatically sends the erroneous form in the context, and your error messages are displayed just fine.

Related

The 'image' attribute has no file associated with it

I have been trying to update image since I added an ImageField to model.py but it always gives me this error The 'image' attribute has no file associated with it.
From Admin panel given by Django I can do so I can add and update, but I need to create my own way of updating images but id doesn't work.
Here are my attachments
This is my model
class rooms(models.Model):
room_number = models.PositiveIntegerField(unique = True)
room_type = models.ForeignKey(room_types, on_delete=models.CASCADE)
number_of_beds = models.PositiveIntegerField()
image = models.ImageField(upload_to = 'room_pics/', null = True, blank = True)
price = models.PositiveIntegerField(default=0)
class Meta:
verbose_name_plural = 'Rooms'
def __str__(self):
room_number = "Room number: " + str(self.room_number)
return room_number
Here is a form from forms.py
class addRoomForm(forms.ModelForm):
class Meta:
model = rooms
fields = ['room_number', 'room_type', 'number_of_beds', 'price', 'image']
and here are the views from views.py to add and update
def add_room(request):
form = addRoomForm()
if request.method == 'POST':
form = addRoomForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, f'Room added successfully!')
return redirect('add_room')
else:
form = addRoomForm()
context = {
'form' : form,
}
myTemplate = 'hotel/addRoom.html'
return render(request, myTemplate, context)
def update_room(request, id):
instance = get_object_or_404(rooms, pk = id)
form = addRoomForm(request.POST or None, instance = instance)
if form.is_valid():
form.save()
messages.success(request, f'Room has been updated successifully!')
return redirect ('view_rooms')
context = {
'form': form,
}
myTemplate = 'hotel/addRoom.html'
return render(request, myTemplate, context)`
and the template source code is
<div class=" w3-card">
<table class="table table-hover table-bordered">
<thead>
{% if room.image.url %}
<tr>
<img src="{{room.image.url}}" alt="image" width="711px" height="400px;">
</tr>
{% endif %}
</thead>
<tbody>
<tr>
<td>Room number</td>
<td>{{room.room_number}}</td>
</tr>
<tr>
<td>Room Type</td>
<td>{{room.room_type}}</td>
</tr>
<tr>
<td>Number of beds</td>
<td>{{room.number_of_beds}}</td>
</tr>
<tr>
<td>Price</td>
<td>{{room.price}}</td>
</tr>
<tr>
<td><i class="fa fa-edit"></i>
<i class="fa fa-trash"></i>
</td>
</tr>
</tbody>
</table>
</div>
It should be form = addRoomForm(request.POST, request.FILES)
See File Uploads, Here is detailed and good documented tutorial for you.

Django - objects.all() shows nothing

I'm trying to get a list of objects in Django from a model.
I just want to get the list of 'dht node' from the request user, but it shows nothing in the html file (as if the list was empty). The user that I'm using has 2 'dht nodes' and they're shown in the django admin.
I don't know what is wrong, because if I use the instruction "member.dht.create(...)" in the views function and a create a new 'dht node' like this, this is shown. Only 'dht nodes' that I enter by form do not show. Can be the form?
Thanks a lot, Here's my code:
Models.py
class Node(models.Model):
name = models.CharField(primary_key=True, null=False, max_length= 50)
description= models.CharField(default=None, null=False, max_length= 250)
topic=models.CharField(default=None, null=False, max_length= 50, unique=True)
def __unicode__(self):
return self.name
class dht(Node):
temp = models.IntegerField(default=None, null=True)
hum = models.IntegerField(default=None, null=True)
class UserProfile(User):
uid = models.CharField(default=None, null=False, max_length= 250)
dht = models.ManyToManyField(dht, blank=True)
def __unicode__(self):
return self.user.username
Views.py -dht list-
#login_required(login_url = '/web/login')
def listDhtSensor(request):
member = request.user.userprofile
list = member.dht.all()
return render(request, 'web/listDhtSensor.html', {'list':list})
Html -listDhtSensor.html-
{% block content %}
{% for dht in list %}
{{ dht.name }}
{{ dht.topic }}
{% endfor %}
{% endblock %}
Forms.py
class newDHTSensorForm(forms.ModelForm):
class Meta:
model = dht
field = ['name',
'description',
'topic',]
labels = {'name': 'Name' ,
'description': 'Description',
'topic': 'Topic',}
exclude = ['temp', 'hum']
Views.py -dht form-
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Html -newDhtSensor.html-
{% block content %}
<div class="boxReg">
<form method="post">
{% csrf_token %}
<h2>{{ form.name.errors.as_text }}</h2>
<p><label for="id_name">Name:</label> <input class="barraForm" type="text" name="name" maxlength="150" autofocus="" required="" id="id_name"></p>
<p><label for="id_description">Description:</label> <input class="barraForm" type="text" name="description" maxlength="150" id="id_description"></p>
<h2>{{ form.topic.errors.as_text }}</h2>
<p><label for="id_topic">Topic:</label> <input class="barraForm" type="text" name="topic" maxlength="254" id="id_topic"></p>
<div class="boxButtonReg">
<button class="buttonReg" type="submit">Save</button>
</div>
</form>
</div>
{% endblock %}
It shows nothing because you did not link you dht objects to that UserProfile, so if you later query for the dhts for that UserProfile, evidently the list is empty. You should add it to the dht relation, like:
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save()
request.user.userprofile.dht.add(post)
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Note that you first need to save the post, so you should omit the commit=False aprameter.

Data not saving in sqlite db using Django

I am facing issues in saving data to my sqlite db using Django.
When i am accessing 127.0.0.1/personal/makeentry--> the page shows the form , but when i click on submit after entering the details, the detils are not saved in db.
Below is the code
model.py
from django.db import models
class Account(models.Model):
accountId = models.IntegerField(primary_key=True,unique=True,
blank=False, null=False, auto_created=True)
accountName = models.CharField(max_length=100)
countryName = models.CharField(max_length=100)
marketName = models.CharField(max_length=100)
msdmName = models.CharField(max_length=100)
deliveryManagedFrom = models.CharField(max_length=100)
location = models.CharField(max_length=100)
def __str__(self):
return self.accountName
admin.py
from django.contrib import admin
from .models import Account
# Register your models here.
class AccountAdmin(admin.ModelAdmin):
list_display = ['accountId', 'accountName','countryName', 'marketName',
'msdmName','deliveryManagedFrom','location']
admin.site.register(Account, AccountAdmin)
forms.py
from django import forms
from . models import Account
from django.forms import ModelForm
class AccountForm(forms.Form):
accountName = forms.CharField(label="Account Name", max_length=100)
countryName = forms.CharField(label="Country Name", max_length=100)
marketName = forms.CharField(label="Market Name", max_length=100)
msdmName = forms.CharField(label="MSDM Name", max_length=100)
deliveryManagedFrom = forms.CharField(label="Delivery Managed From", max_length=100)
location = forms.CharField(label="Location", max_length=100)
class AccountForm(ModelForm):
class Meta:
model = Account
fields = ['accountName','countryName', 'marketName', 'msdmName', 'deliveryManagedFrom', 'location']
views.py
from django.shortcuts import render
from django.views import generic
from .models import Account
from .forms import AccountForm
def index(request):
return render(request, 'personal/home.html')
# generic view to fetch the data then show in a list
class IndexView(generic.ListView):
# a name to refer to the object_list(to be used in the index.html)
context_object_name = 'account_list'
template_name = 'personal/index.html'
def get_queryset(self):
return Account.objects.all()
# generic view to show the details of a particular object
class DetailsView(generic.DetailView):
model = Account
template_name = 'personal/detail.html'
def makeentry(request):
if request.method == 'POST':
form = AccountForm(request.POST)
if form.is_valid():
accountName = request.POST.get('Account Name', '')
countryName = request.POST.get('Country Name', '')
marketName = request.POST.get('Market Name', '')
msdmName = request.POST.get('MSDM Name', '')
deliveryManagedFrom = request.POST.get('Delivery Managed From', '')
location = request.POST.get('Location', '')
account = Account(accountName=accountName, countryName=countryName, marketName=marketName, msdmName=msdmName, deliveryManagedFrom=deliveryManagedFrom, location=location)
account.save()
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
else:
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
makeentry.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Account Entry</title>
</head>
<body>
<form action="{% url 'makeentry' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
</body>
</html>
detail.html
{% if account_list %}
<table>
<tr>
<td> Account Name </td>
<td> Country Name </td>
<td> Market Name </td>
<td> MSDM Name </td>
<td> Delivery Managed From </td>
<td> Location </td>
</tr>
{% for account in account_list %}
<tr>
<td>{{ account.accountName }}</td>
<td>{{ account.countryName }}</td>
<td>{{ account.marketName }}</td>
<td>{{ account.msdmName }}</td>
<td>{{ account.deliveryManagedFrom }}</td>
<td>{{ account.location }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
I think you are making this harder than it needs to. You have a Form and a ModelForm of the same name. You should just be able to use the ModelForm. If there are attributes you want to pass with your ModelForm check out ModelForm Overriding default widgets. It has also been my experience to set action=“” and let the view handle the redirect on success.
def make_entry(request):
if request.POST:
form = AccountForm(request.POST)
if form.is_valid():
new_form = form.save()
return redirect('where-you-want-to-redirect ',
# View current saved info or change to what you want to show
pk=new_form.pk)

Django formset not saving my files

So I have these two models Lecture and FileUpload. I want that the user to be able to add a lecture to a specific course and also upload multiple files for that lecture. Thing is that after I submit the form the information gets saved except for the uploaded files, so I am guessing something is wrong with my formset. Please have a look:
FileFormset = inlineformset_factory(Lecture, FileUpload, exclude=[])
def classroom(request):
if request.method == 'POST':
form1 = LectureForm(request.POST)
if form1.is_valid():
lecture = form1.save()
formset = FileFormset(request.POST, request.FILES, instance=lecture, prefix='files')
if formset.is_valid():
formset.save()
else:
print(formset.errors)
formset.save()
return redirect('courses:index')
else:
form1 = LectureForm()
formset = FileFormset()
context = {'teacher_data': TeacherData.objects.all(),
'teachers': Teacher.objects.all(),
'courses': Course.objects.all(),
'form1': form1,
'formset': formset,
}
return render(request, 'courses/classroom.html', context)
<form method="post" action="">
{% csrf_token %}
{{ form1.as_p }}
{{ formset.management_form }}
{% for form in formset %}
{{ form }} <br>
{% endfor %}
<br>
<button type="submit">Add Lecture</button>
</form>
class LectureForm(forms.ModelForm):
class Meta:
model = Lecture
fields = ('course', 'lecture_title', 'lecture_category', 'content')
class FileForm(forms.ModelForm):
class Meta:
model = FileUpload
fields = ('files',)
class Lecture(models.Model):
LECTURE_CHOICES = (
('Courses', 'Courses'),
('Seminars', 'Seminars'),
)
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures',)
lecture_category = models.CharField(max_length=10, choices=LECTURE_CHOICES, default='Courses',)
lecture_title = models.CharField(max_length=100, blank=True, null=True)
content = models.TextField(blank=True, null=True)
def __str__(self):
return str(self.lecture_title)
class FileUpload(models.Model):
files = models.FileField(upload_to='documents', null=True, blank=True)
lecture = models.ForeignKey('Lecture', related_name='files', on_delete=None, default=None)
def __str__(self):
return str(self.files)
add enctype attribute to you from widget like,
<form method="post" action="" enctype= multipart/form-data>
Try this

Django save only first form of formset

I've looked through every similar question (and tried them), but still couldn't find answer.
I have two models:
class Project(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
name = models.CharField(max_length=120, verbose_name = "Название проекта")
url = models.URLField(max_length=120, unique=True, verbose_name = "Полный адрес сайта")
robots_length = models.CharField(max_length=5, default=0)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
def get_absolute_url(self):
from django.urls import reverse
return reverse('projects:detail', args=[str(self.id)])
class ProjectPage(models.Model):
page_project = models.ForeignKey(Project, on_delete=models.CASCADE)
page_url = models.URLField(verbose_name = "Адрес страницы")
page_title = models.CharField(max_length=300, blank=True, verbose_name = "meta-title",default="")
page_description = models.CharField(max_length=300, blank=True, verbose_name = "meta-description",default="")
page_h1 = models.CharField(max_length=300, blank=True, verbose_name = "Заголовок h1",default="")
def __unicode__(self):
return self.page_url
def __str__(self):
return self.page_url
For each model there is a form:
class ProjectFormUpdate(forms.ModelForm):
class Meta:
model = Project
fields = [
"name",
"url",
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Произвольное название'}),
}
class ProjectPageForm(forms.ModelForm):
class Meta:
model = ProjectPage
fields = [
'page_project',
'page_url',
'page_title',
'page_description',
'page_h1',
]
widgets = {
'page_project': forms.HiddenInput()
}
In views.py I have:
def projects_update(request, proj=None):
instance = get_object_or_404(Project, id=proj)
form = ProjectFormUpdate(request.POST or None, instance=instance)
formset_f = modelformset_factory(ProjectPage, form=ProjectPageForm, extra=3)
formset = formset_f(queryset=ProjectPage.objects.filter(page_project__id=proj), initial =[{'page_project': proj}])
if request.method == 'POST':
formset = formset_f(request.POST)
for formset_form in formset:
if formset_form.is_valid() and formset_form.has_changed():
formset_form.save()
if form.is_valid():
form.save()
context = {
'title': "Редактируем проект - "+instance.name,
'form': form,
'formset': formset,
'instance': instance,
}
return render(request, "projects_update.html", context)
And, finaly, html
<form method="POST" action="" class="create-form">
{{ formset.management_form }}
{% csrf_token %}
<div class="row">
<div class="col-lg-6 offset-lg-3 col-md-10 offset-md-1 col-xs-10 offset-xs-1 form-bg">
<h2>Общие данные</h2>
{{ form|crispy}}
<input type="submit" class="btn btn-success" value="Обновить проект" />
</div>
</div>
{% for formset_form in formset %}
<div class="row form-container">
<div class="col-lg-6 offset-lg-3 col-md-10 offset-md-1 col-xs-10 offset-xs-1 form-bg">
<h3>Страница {{forloop.counter}}</h3>
{{ formset_form|crispy}}
</div>
</div>
{% endfor %}
</form>
What I am trying to achieve is: when user enters a page, he gets a form with project name and project URL already filled in. So, he can correct them.
Below, I want to show a filled in form for every page allready created for this project and several empty forms for creating new.
What happens is all initial data is displayed correctly, but when I fill several empty forms - only first empty form is saved each time.
Here is how it was solved:
Included errors properly.
Saw that second to last form lack required field (hiddenInput)
Made changes in view so it looks like:
formset_f = modelformset_factory(ProjectPage, form=ProjectPageForm, extra=3)
formset = formset_f(queryset=ProjectPage.objects.filter(page_project__id=proj), initial =[{'page_project': proj}, {'page_project': proj}, {'page_project': proj}])
Initial values now match number of extra forms - every form got it's own foreign key.
Probably there is a better solution, but the the problem is found and solved for me!
My problem was that when I tried to render every form of the formset manually I added an unneded <form></form> html element
wrong:
{ form.management_form }}
{% for form in formset %}
<form class="form-class">
{{form.name}}
</form>
right:
{ form.management_form }}
{% for form in formset %}
<div class="form-class">
{{form.name}}
</div>
After that change my forms were recognized correctly.

Categories