UnboundLocalError: local variable 'formset' referenced before assignment in DJANGO - python

Hey so I have this list of campaigns that have a button to start and stop the process.
'''
from django.shortcuts import render
from .models import Campaign
from .forms import CampaignForm, CampaignStatusFormSet
def home_view(request):
queryset = Campaign.objects.all()
if request.method == 'POST':
form_type = request.POST.get('id')
if form_type == 'campaign_status':
formset = CampaignStatusFormSet(
request.POST, request.FILES,
queryset=queryset,
)
for form in formset.forms:
if form.is_valid():
form.save()
else:
formset = CampaignStatusFormSet(queryset=queryset)
campaigns_and_forms = list(zip(queryset, formset))
context = {
'formset': formset,
'campaigns_and_forms': campaigns_and_forms,
}
return render(request, 'campaigns_in_progress.html', context)
'''
But when I run it and click on the button to change play/pause it shows this error.
UnboundLocalError: local variable 'formset' referenced before assignment
Can anyone help me refactor this code so that it doesn't show this error?

You can remove the else block so that the formset is available even after clicking on the play/pause buttons. When you send a POST request, and campaign_status is as expected, formset variable is not available in the conext and hence the error.
from django.shortcuts import render
from .models import Campaign
from .forms import CampaignForm, CampaignStatusFormSet
def home_view(request):
queryset = Campaign.objects.all()
if request.method == 'POST':
form_type = request.POST.get('id')
if form_type == 'campaign_status':
formset = CampaignStatusFormSet(
request.POST, request.FILES,
queryset=queryset,
)
for form in formset.forms:
if form.is_valid():
form.save()
# Set form with new created campaign
queryset = Campaign.objects.all()
formset = CampaignStatusFormSet(queryset=queryset)
campaigns_and_forms = list(zip(queryset, formset))
context = {
'formset': formset,
'campaigns_and_forms': campaigns_and_forms,
}
else:
formset = CampaignStatusFormSet(queryset=queryset)
campaigns_and_forms = list(zip(queryset, formset))
context = {
'formset': formset,
'campaigns_and_forms': campaigns_and_forms,
}
return render(request, 'campaigns_in_progress.html', context)

I don't know if this is the right solution and if it won't break something else but for now it works perfectly. I just declared the formset before the if statement so it kind of declares 2 times.
If anyone could tell me if this is a good solution I would be greatful
'''
def home_view(request):
queryset = Campaign.objects.all()
formset = CampaignStatusFormSet(
request.POST, request.FILES,
queryset=queryset,
)
if request.method == 'POST':
form_type = request.POST.get('id')
if form_type == 'campaign_status':
formset = CampaignStatusFormSet(
request.POST, request.FILES,
queryset=queryset,
)
for form in formset.forms:
if form.is_valid():
form.save()
else:
formset = CampaignStatusFormSet(queryset=queryset)
campaigns_and_forms = list(zip(queryset, formset))
context = {
'formset': formset,
'campaigns_and_forms': campaigns_and_forms,
}
return render(request, 'campaigns_in_progress.html', context)
'''

Related

Why does my Django registration form is not rendered?

I have default Django registration form. It is sent to render to the page based on type of request and user login status. This logic is implemented in views.py file. Somehow, if user is not logged in and GET request is sent to the page, my view returns UnboundLocalError: local variable 'form' is referenced before assignment. How could this happen?
P.S. Here's my view.
def EmplRegisterView(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
group = Group.objects.get(name = 'Employers')
user.groups.add(group)
login(request, user)
return redirect('ProfileSetup')
else:
if request.user.is_authenticated:
logout(request)
form = UserCreationForm()
else:
form = UserCreationForm()
context = {
'form':form,
}
return render(request, "registerPage.html", context)
Try this way
def EmplRegisterView(request):
form = UserCreationForm()
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
group = Group.objects.get(name = 'Employers')
user.groups.add(group)
login(request, user)
return redirect('ProfileSetup')
if request.user.is_authenticated:
logout(request)
context = {
'form':form,
}
return render(request, "registerPage.html", context)

Django Formset - Update Value in Views.py before saving

I am trying to set a value on each form in the formset to a single value.
I am not sure how to accomplish this... views.py function below:
Like:
formset.idcst_cnt = id
views.py
def customer_contacts(request, id):
ContactFormSet = modelformset_factory(AppContactCnt, can_delete=True, fields=(
'name_cnt', 'phone_cnt', 'email_cnt', 'note_cnt', 'receives_emails_cnt'), max_num=3, extra=3)
formset = ContactFormSet(queryset=AppContactCnt.objects.filter(idcst_cnt=id), prefix='contact')
if request.method == 'GET':
context = {'formset': formset}
return render(request, 'customer_contacts.html', context=context)
if request.method == 'POST':
formset = ContactFormSet(request.POST, prefix='contact')
if formset.is_valid():
print("we're updating contacts for " + str(id))
# formset.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
Under if request.method == 'POST' you can do for form in formset

how do i show the products that are uploaded by the logged in user only?

Here's my problem, when a user logs in they can see the products uploaded by the other user also but i am trying to show when an user logged in they can see the products uploaded by them only**
views.py
from django.shortcuts import render, get_object_or_404, redirect
from .forms import ProductForm
from .models import Product
from django.contrib.auth.models import User
prodcut create or upload
def product_create_view(request):
form = ProductForm(request.POST or None)
if form.is_valid():
form.save()
form = ProductForm()
context = {
'form': form
}
return render(request, "products/product_create.html", context)
product update
def product_update_view(request, id=id):
obj = get_object_or_404(Product, id=id)
form = ProductForm(request.POST or None, instance=obj)
if form.is_valid():
form.save()
context = {
'form': form
}
return render(request, "products/product_create.html", context)
tried by changing in the list view but getting this error product_list_view() missing 1 required positional argument: 'user'
def product_list_view(request, user):
queryset = Product.objects.filter(user=request.user)
context = {
"object_list": queryset
}
return render(request, "products/product_list.html", context)
**product detail **
def product_detail_view(request, id):
obj = get_object_or_404(Product, id=id)
context = {
"object": obj
}
return render(request, "products/product_detail.html", context)
product delete
def product_delete_view(request, id):
obj = get_object_or_404(Product, id=id)
if request.method == "POST":
obj.delete()
return redirect('../../')
context = {
"object": obj
}
return render(request, "products/product_delete.html", context)
this is product list template page
template/product.list.html
{% extends 'accounts/base.html' %}
{% block content %}
{% for instance in object_list %}
<p>{{ instance.id }} - <a href='{{ instance.get_absolute_url }}'>{{ instance.title }}</a></p>
{% endfor %}
{% endblock %}
here's the **
**models.py
from django.db import models
from django.urls import reverse
from django.conf import settings
from django.contrib.auth.models import User
class Product(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=10000)
summary = models.TextField(blank=False, null=False)
featured = models.BooleanField(default=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
def get_absolute_url(self):
return reverse("products:product-detail", kwargs={"id": self.id}) #f"/products/{self.id}/"
urls.py
urlpatterns = [
path('', product_list_view, name='product-list'),
path('create/', product_create_view, name='product-create'),
path('<int:id>/', product_detail_view, name='product-detail'),
path('update/<int:id>/', product_update_view, name='product-update'),
path('<int:id>/delete/', product_delete_view, name='product-delete'),
]
You never set the logged in user in your Product when you create or update it:
def product_create_view(request):
if request.method == 'POST':
form = ProductForm(request.POST)
if form.is_valid():
form.instance.user = request.user
form.save()
form = ProductForm()
context = {
'form': form
}
return render(request, 'products/product_create.html', context)
def product_update_view(request, id):
obj = get_object_or_404(Product, id=id, user=request.user)
if request.method == 'POST':
form = ProductForm(request.POST, instance=obj)
if form.is_valid():
form.instance.user = request.user
form.save()
else:
form = ProductForm(instance=obj)
context = {
'form': form
}
return render(request, 'products/product_create.html', context)
In your product_detail_view and product_delete_view, you should filter on the user as well:
def product_detail_view(request, id):
obj = get_object_or_404(Product, id=id, user=request.user)
context = {
'object': obj
}
return render(request, "products/product_detail.html", context)
def product_delete_view(request, id):
obj = get_object_or_404(Product, id=id, user=request.user)
if request.method == "POST":
obj.delete()
return redirect('../../')
context = {
'object': obj
}
return render(request, 'products/product_delete.html', context)
in your list view, you should not use user as a parameter:
def product_list_view(request):
queryset = Product.objects.filter(user=request.user)
context = {
'object_list': queryset
}
return render(request, 'products/product_list.html', context)
Additional remarks:
usually in case of a successful POST request, you should make a redirect, in order to implement the Post/Redirect/Get pattern [wiki];
you might want to make the user column non-NULLable, since now it will have NULL if you do not specify a value, and you allow to construct products without a user;
please do not use request.POST or None. A POST request can be valid, even if it is empty;
please do not write urls yourself, Django's redirect(..) [Django-doc] can resolve a URL based on the name of a view, and the values for the parameters. This is more safe if you later want to rewrite the URLs; and
you might want to take a look at class-based views like CreateView [Django-doc], UpdateView [Django-doc], and DeleteView [Django-doc]. These will reduce the amount of boilerplate logic.

Using Value From One View in Another View Django

In View 1's form their is a field called 'reference'. I need to access whatever value is submitted in that field in View 2 and set a variable equal to it. Right now I am just getting an error "orders matching query does not exist".
This is what I'm trying (I've commented the code in view2 to indicate where im getting the error).
views.py
def view1(request, pk):
item = get_object_or_404(Manifests, pk=pk)
if request.method == "POST":
form = CreateManifestForm(request.POST, instance=item)
if form.is_valid():
form.save()
return redirect('view2')
else:
form = CreateManifestForm(instance=item)
return render(request, 'edit_manifest_frombrowse.html', {'form': form})
def view2(request):
form = CreateManifestForm(request.POST)
if request.method == "POST":
if form.is_valid():
form.save()
...
reference_id = request.POST.get('reference') #this is how Im trying to get reference from the previos view
data = Manifests.objects.all().filter(reference__reference=reference_id)
form = CreateManifestForm(initial={
'reference': Orders.objects.get(reference=reference_id), #this is where im getting "does not exist"
})
total_cases = Manifests.objects.filter(reference__reference=reference_id).aggregate(Sum('cases'))
context = {
'reference_id': reference_id,
'form': form,
'data': data,
'total_cases': total_cases['cases__sum'],
}
return render(request, 'manifest_readonly.html', context)
forms.py
class CreateManifestForm(forms.ModelForm):
class Meta:
model = Manifests
fields = ('reference', 'cases', 'product_name', 'count', 'CNF', 'FOB')
I just want to be able to use whatever value is submitted in the 'reference' field in view1 in view2 and assign it equal to reference_id
Something like this:
from django.urls import reverse
def view1(request, pk):
item = get_object_or_404(Manifests, pk=pk)
if request.method == "POST":
form = CreateManifestForm(request.POST, instance=item)
if form.is_valid():
obj = form.save()
reference_id = request.POST.get('reference') or obj.reference.id
return redirect(reverse('view2')+f'?reference={reference_id}')
else:
form = CreateManifestForm(instance=item)
return render(request, 'edit_manifest_frombrowse.html', {'form': form})
def view2(request):
if request.method == "POST":
form = CreateManifestForm(request.POST)
if form.is_valid():
form.save()
...
data = getattr(request, 'POST', None) or getattr(request, 'GET', {})
reference_id = data.get('reference') #this is how Im trying to get reference from the previos view
data = Manifests.objects.all().filter(reference__reference=reference_id)
form = CreateManifestForm(initial={
'reference': Orders.objects.get(reference=reference_id), #this is where im getting "does not exist"
})
total_cases = Manifests.objects.filter(reference__reference=reference_id).aggregate(Sum('cases'))
context = {
'reference_id': reference_id,
'form': form,
'data': data,
'total_cases': total_cases['cases__sum'],
}
return render(request, 'manifest_readonly.html', context)

How to save to a database on click

In my previous question, I recently asked how to make forms.py in Django 1.9 show in HTML. now that this is done im trying to make a button which when the selection has been made (in this case it's radiobuttons) it will post to the database and move on with the questionaire.
Currently im attempting to make it post in my views.py but im having no luck in making it send the data.
def question1(request):
question_form = QuestionForm()
if request.method == 'POST':
form = QuestionForm(request.POST)
if form.is_valid():
return render(request, 'music.questions2,html')
return render(request, 'music/question1.html', locals())
Would really appreciate the help in making this happen.
def question1(request):
question_form = QuestionForm()
if request.method == 'POST':
form = QuestionForm(request.POST)
if form.is_valid():
form.save() # save to db!
return render(request, 'music.questions2,html')
return render(request, 'music/question1.html', locals())
# models.py
class Question(models.Model):
# Q_CHOICES is the previous declared one
question = models.CharField(max_length=20, choices=Q_CHOICES)
# forms.py
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = ['question']
widgets = {
'question': forms.RadioSelect()
}
Use: form.save()
def question1(request):
if request.method == 'POST':
form = QuestionForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'music.questions2,html')
else:
form = QuestionForm()
return render(request, 'music/question1.html', locals())

Categories