UnboundLocalError: local variable 'form' referenced before assignment in Django - python

So I'm working on a Django project and this is my views.py file:
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
When I ran my server, I got an error saying:
UnboundLocalError: local variable 'form' referenced before assignment
This is my new_topic.html file
{% extends 'base.html' %}
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}

The line if form.is_valid(): fails on a GET request, because you're only defining form when request.method == 'POST'.
This can be fixed by changing some indentation:
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})

I don't find any issue with indentation, but with initialization. Kindly initialize for before rendering it! Make changes as shown below will definitely work out and it's a very genuine and proper way to get rid of it:
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
form = NewTopicForm()
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})

Related

Why is my Django form not "valid"? Can't get the POST request to update database

I am trying to create a user profiles for users in my Django app. I have the form displaying where I want it to and when I try to submit, nothing happens.
I put a print statement after the form.is_valid in my view.py and found that it wasn't 'valid' but I have no idea why.
I have tried several different ways to 'clean' / 'validate' data but I can't get past the form being 'invalid.'
Any help would be greatly appreciated!
urls:
path('userinfo/', views.user_info, name='userinfo')
form template:
{% extends "base.html" %}
{% load bootstrap4 %}
{% block content %}
<div class="container">
<h1>Enter User Info</h1>
<form method="POST" class="form">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary" value="Create Profile">
</form>
</div>
{% endblock %}
view:
def user_info(request):
form = ProfileForm()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
else:
form = ProfileForm()
return render(request, 'miraDashboard/form.html', context={'form': form})
model:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
name = models.CharField("Full Name", max_length=1024)
job_role = models.CharField("Role", max_length=254, default="Seeking Job Opportunities")
zip_code = models.CharField("Zip Code", max_length=5)
user_image = models.ImageField("Upload Profile Picture", upload_to='images/')
def __str__(self):
return f'{self.user.username} Profile'
form:
from django.forms import ModelForm
from .models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['name','job_role','zip_code', 'user_image']
if you want to see errors in form change else statmant:
def user_info(request):
form = ProfileForm()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
else:
print(form.errors.as_data()) # here you print errors to terminal
return render(request, 'miraDashboard/form.html', context={'form': form})
after form.is_valid() you don't need to set it again (form = ProfileForm() in else statment). this way your form will get errors( you cen see them in form.errors).

How do I get the ID of an image

I'm a Django beginner, how do I get the ID of each image uploaded with form?
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
return redirect....
else:
form=UploadForm
return render......
view.py
def home(request) :
all_images=Image objects.filter(imageuploader_profile=request.user)
context={'all_images':all_images}
return render(request, 'home.html', context)
My home.html
{% for post in all_images %}
{% if post upload_images %}
<img src="{{ post upload_image.url }}">
{% endif %}
{% endfor%}
I want to get all IDs in my template.
You can write a new method/view to get all IDs:
def get_images_ids():
images_ids = Image.objects.values_list('id)
print(images_ids)
return images_ids
Here the explanation for values_list (you also can use values() if you need more, or the attribute flat=True).
If you call get_images_ids() you get all IDs of all images in a queryset (or in a list with flat=True). If you need to filter them use .filter().
In your views.py
def home(request) :
all_images=Image objects.filter(imageuploader_profile=request.user)
context={'all_images':all_images, all_images_ids: get_images_ids()}
return render(request, 'home.html', context)
In your template do this:
{% for post in all_images %}
{% if post upload_images %}
<img src="{{ post.upload_image.url }}">
<span>{{ post.id }}</span>
{% endif %}
{% endfor%}
or
<ul>
{% for id in all_images_ids %}
<li>{{ id }}</li>
{% endfor%}
</ul>
You can't get id of the image unless you first create an object in database, in other words you will have to execute post.save() first and then you can run post.id to get id. Here is an example with your code.
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
print(post.id) # This will print id of submitted post in your console
return redirect....
else:
form=UploadForm
Note: ID of post is automatically created in the database after you run post.save()
You can get the ID of the image after post.save() executes.
So before the return statement you can access post.id or post.pk to get the image ID.
UPDATE:
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
# here you can access post.id or post.pk
return redirect....
else:
form=UploadForm
If you want to get all uploaded images id then use Image.objects.values_list('id)

View is not refreshing after post

I use a simple form to edit the name of a invoice (invoice_text). When I submit the changes it redirects back to index page. The problem is that the index page is showing the old records. This is only in Firefox. Internet Explorer shows the changes directly. F5 helps, but of course it needs to show the new (edited) information.
forms.py
class InvoiceForm(ModelForm):
class Meta:
model = Invoice
fields = ('Invoice_text',)
views.py
def index(request):
latest_invoice_list = Invoice.objects.order_by('-pub_date')[:5]
context = {'latest_invoice_list': latest_invoice_list}
return render(request, 'invoices/index.html', context)
def invoice_edit(request, pk):
obj = get_object_or_404(Invoice, pk=pk)
if request.method == "POST":
form = InvoiceForm(request.POST, instance=obj)
if form.is_valid():
obj = form.save(commit=False)
obj.Invoice_text = request.POST['Invoice_text']
obj.save()
return HttpResponseRedirect('/invoices/')
else:
form = InvoiceForm(instance=obj)
return render(request, 'polls/edit_Invoice.html', {'form': form})
Index.html template
{% if latest_invoice_list %}
<ul>
{% for invoice in latest_invoice_list %}
<li>{{ invoice.invoice_text }} | edit</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
This is strange, but you should be able to use the #never_cache decorator to prevent it:
from django.views.decorators.cache import never_cache
#never_cache
def index(request):
....

Require help in Django 'local variable 'form' referenced before assignment'

I am having problem in django. I have created a form in my app where I can take details of a client. Now I want to create a form which can allow me to edit a form. However I am having some problems when I go to /index/edit_client/1, I get this error.
local variable 'form' referenced before assignment
I do not know what the reason why I have got this error, but from what I have looked at, it does not help matters unless of course there is another way how to create an edit form to edit the clients form. Here are some output that can be helpful too.
# urls.py
urlpatterns = patterns('',
(r'^index/$', login_required(direct_to_template), { 'template': 'index.html' }),
(r'^index/clients/$', client_info),
(r'^index/clients_details/(?P<id>\d+)/$', clients_details),
(r'^index/edit_client/(?P<id>\d+)/$', edit_client),
)
# views.py
#login_required
def edit_client(request, id=1):
clients_list = Client.objects.filter(pk=id)
if request.method == 'POST':
form = ClientForm(request.POST or None)
if form.is_valid():
form.save()
return HttpResponseRedirect('/index/clients/')
else: form = ClientForm()
return render_to_response('edit_client.html', {'form': form}, context_instance=RequestContext(request))
#edit_client.html
{% extends "base.html" %}
{% block content %}
<font face="verdana,news gothic,arial,heltevica,serif">
<h3>Edit Client</h3>
</font>
<form method= "POST" action="">
<font face="verdana,news gothic,arial,heltevica,serif">
<div id="form">
<table>
{{form.as_table}}
</table>
<div align="center" STYLE=" margin-right:190px">
<input type="submit" value="Submit" STYLE="background-color:#E8E8E8; color:#181818 "/>
</div>
</div>
</form>
{% endblock %}
This will always run:
return render_to_response('edit_client.html', {'form': form}
But if request.method is not POST, nothing is assigned to form.
Fixed code:
#login_required
def edit_client(request, id=1):
clients_list = Client.objects.filter(pk=id)
form = ClientForm()
if request.method == 'POST':
form = ClientForm(request.POST or None)
if form.is_valid():
form.save()
return HttpResponseRedirect('/index/clients/')
return render_to_response('edit_client.html', {'form': form}, context_instance=RequestContext(request))
In your edit_client method, you pass form in the response, however, if the method wasn't a POST, you won't have initialized a form.

Management form error while using modelformsets ('ManagementForm data is missing or has been tampered with')

I have a models.py class as below
class Educational_Qualification(models.Model):
user = models.ForeignKey(User)
exam = models.CharField(max_length=40)
pass_month = models.CharField(max_length=40)
I have a views.py as below
def create_qualification(request):
QFormSet = modelformset_factory(Educational_Qualification, extra=3, exclude=("user",))
if request.method == "POST":
formset = QFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
for form in formset.forms:
if form.is_valid():
quali= form.save(commit=False)
quali.user = request.user
quali.save()
return HttpResponse("Saved")
else:
return HttpResponse("Snafu")
else:
formset = QFormSet()
return render_to_response("register/edu.html", {"formset":formset}, context_instance=RequestContext(request))
When I submit the form, it throws up the validation Error. stating that ManagementForm data is missing or has been tampered with'
I have formset.management_form in my template.
What could be the issue?
The error is not in your views or the models, but in the templates.
The right way to render the formset, is:
<form method="post" action="">
<table>
{{ formset }}
</table>
</form>
or
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
</form>
I guess, you are looping over the forms in the templates without including the management form?
It also happens if there are multiple views involved and one of them is not aware of the formset prefix.
Get view:
def someview(request):
...
formset = Formset(prefix="foo")
...
Post view (Potentially an Ajax form submit handler):
def ajaxview(request):
...
formset = Formset(request.POST, prefix="foo") # here
...

Categories

Resources