limit django query to current session and pass it to a function view - django-views

So I'm trying to make a calculator of sorts where the user enters some data and then they are presented with a view that gives them the results they need (printer-friendly format so they can print it).
What I've done so far:
Created a model and a form which they work as intended.
**class CalcModel**(models.Model):
income = models.DecimalField...
civil_status = models.CharField...
have_children = models.CharField..
**class CalcForm**(ModelForm):
class Meta:
**model = Calculate**
fields = ['income', 'civil...]
The view that processes the form and redirects to another view if submitted data is valid:
data_d = {}
def createcalculation(request):
form = CalcForm()
if request.method == 'POST':
form = CalcForm(request.POST)
if form.is_valid():
**data_d['cleaned_data'] = form.cleaned_data**
form.save()
return redirect('res-view')
context = {'c_form': form}
return render(request, 'calc/calc.html', context)
I think there should be a way to pass the model instance data to the view where the user is redirected but I can't figure it out. So, help is highly appreciated. Right now, I'm 'manually' passing a dictionary containing the data from the form but it doesn't work:
def res_ca(request):
context = data_d
return render(request, 'calc/res_ca.html', context)
I can't seem to figure out how to pass the data for the current session to the res_ca view.
The urls if that helps:
path('calc', createcalculation, name='calculate'),
path('res/', res_ca, name='res-view'),

As suggested by #vinkomlacic, I found a way to include the id of the model instance by switching to the render method instead of redirect and it worked like a charm.
if form.is_valid():
messages.success(request, f'Successful!')
item = form.save()
m_data = Calculate.objects.get(id=item.id)
context = {'c_data': form.cleaned_data, 'm_data': m_data}
return render(request, 'calc/res_ca.html', context)
This way, the form is saved, I can pass that instance of the model to the next view and it also allows me to add additional context to the template directly from model methods.

Related

Suggestions on improving a form view

I'm building an app where the user enters data and then gets redirected to a page that shows results based on their input with some simple equations. However, every time I refresh the results page, a new model instance is saved on the database.
Is there another (more efficient and effective) way of passing the data from this view to another view where I have access to the instance of that model submitted through the form view? What's the Django way of passing form data to a view?
The only limitation is I don't want user authentication so using self.request.user is not an option unless it can be implemented in a way that doesn't require users to sign up and sign in.
I'm still somewhat new to Django so any pointers to obvious solutions that I'm overlooking would be greatly appreciated.
This is the view that processes the model form:
def createcalculation(request):
form = CalcForm()
if request.method == 'POST':
form = CalcForm(request.POST)
if form.is_valid():
item = form.save()
m_data = get_object_or_404(Calculate, id=item.id)
context = {'c_data': form.cleaned_data, 'm_data': m_data}
return render(request, 'calc/res_ca.html', context)
context = {'c_form': form}
return render(request, 'calc/calc.html', context)
It is advisable to always do a redirect after a successful POST. Your code should look something like this:
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
...
def createcalculation(request):
form = CalcForm()
if request.method == 'POST':
form = CalcForm(request.POST)
if form.is_valid():
item = form.save()
m_data = get_object_or_404(Calculate, id=item.id)
context = {
'c_data': form.cleaned_data,
'm_data': m_data
}
return redirect(reverse('app_name:view_name', kwargs=context))
context = {'c_form': form}
return render(request, 'calc/calc.html', context)
You can pass the newly created item object in the context as well. Also, you should change app_name and view_name text to match your situation.

Why won't my text posts save, it worked before?

My text posts were working before adding a notification feature but now they aren't, I have a debug print but instead of seeing the post object, I'm seeing the user that posted it. I haven't changed anything other than getting the post id, timesince and the notify function, I've used the exact same method with my picture and video posts and they work fine, so it doesn't make sense to me. I've got a debug print in the notification function to make sure the post type and id have been passed correctly and those indeed show the id and type
views.py
#login_required()
def text_post(request):
if request.method == "POST":
form = TextPostForm(request.POST)
if form.is_valid():
t_post = form.save(commit=False)
t_post.author = request.user
t_post.save()
id = t_post.id
time = timesince
print(t_post) # t_post shows the user instead of the post
followers = list(request.user.followers.all())
notify(followers,
request.user,
f"{request.user.username} posted {time}",
id,
'text'
)
print(t_post)
#redirect to last page
return redirect('home')
else:
form = TextPostForm()
post_type = 'text'
return render(request, 'create_post.html', {'form': form, 'post_type': post_type})
forms.py
class TextPostForm(forms.ModelForm):
class Meta:
model = TextPost
fields = ('description','privacy', 'categories')

Is there a method to post form data from one url to another url, and then render the template based on the form data

I am trying to create a simple one item product store, in which customers would go to a product page and choose the quantity they would like to purchase in a form. After completing the form, I would then like for it to redirect to the checkout page and render the quantity they chose. Is there a simple way to do this? At the moment, I am posting the form data to the product page url and then redirecting the user to the checkout page, however I am unsure how to access that data.
def proxy_detail(request, proxy_slug):
if request.method == 'POST':
form = forms.AddProxyAmountForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
number_of_proxies = int(cd['number_of_proxies'])
return redirect('payment:checkout')
else:
add_proxy_form = forms.AddProxyAmountForm()
proxy_product = get_object_or_404(models.ProxyProduct, slug = proxy_slug)
return render(request, 'shop/product/proxy_detail.html', {'proxy_product' : proxy_product, 'add_proxy_form' : add_proxy_form })
Its not an exact answer but I am new here so I can't really comment :p
Anyways, I think in your view, what you can do is, get the data in a variable and pass it as a context to render another page.
def viewname(request):
if request.method == "POST":
#your logic to save here
context = {variableOfInterest : request.POST.valueOfInterest} #considering you are getting it from the form
return render(request, "redirected.html", context)

How to use form.cleaned_data django

After form.is_valid(), we get form.cleaned_data. How can i use this cleaned data on the next page.
For example, after the form page is processed we redirect the customer to next page, where I want to use the cleaned_data's info like name, contact, address..etc fields to be shown in next page.
def ind(request):
if request.method == 'POST':
form = form_name(request.POST)
if form.is_valid():
print(form.cleaned_data)
return render(request, 'app_one/abc.html', {'data': form.cleaned_data})
# form.save(commit=True)
# return render(request,'app_one/index.html')
else:
form=form_name()
return render(request,'app_one/index.html',{'form':form)
We will have a validated data after calling the form.is_valid() method. Once we have a validated data then we can use as we like.
For your case
customer details which are filled on the first page need show those details on the second page as receipt.
You can create a model named Reciept and save the details in the model for future reference. If you want these details in the other page views then simply pass the model object in context to render the details.
You can use the cleaned data like below
def ind(request):
if request.method == 'POST':
form = form_name(request.POST)
if form.is_valid():
context = {}.update(form.cleaned_data)
return render(request, 'app_one/abc.html', context)
# form.save(commit=True)
# return render(request,'app_one/index.html')
else:
form=form_name()
return render(request,'app_one/index.html',{'form':form)
Example Form:
class MyForm(forms.Form):
reciept_num = forms.CharField()
consider above form as an example
You can access the reciept_num data in template using the name reciept_num.
You can assign the cleaned_data to variables as usual for forms
e.g. your_data=form.cleaned_data['your_data']
After that, pass those variables to context.
e.g. context = {
'your_data':your_data
}
Lastly return the template.
e.g. return(request,'template.html',context=context)
At the 'template.html', use the variables as {{your_data}}.

Django initial value for MultiChoice Field ignored for ModelForm

this is my first post here and I am very new to Django but I just can't seem to find a solution for this problem... I've searched stackoverflow and google but nothing seems to work for me...
I have a wine-app and want to be able to add and remove wines from the user's stock. In the list of wines the user can choose a wine to add and the ID of this wine is passed in the POST data. Since the data is getting lost after the first time the view is rendered I saved the ID in a cookie, which is working, but the problem is when I work with ModelForm de user has to select the foreign key for the user and for the wine, which is bad, so I tried to make it hidden and set the Fk_user and Fk_wine after the user choose the number of bottles to be added but before validation. Here's the problem after google everyone suggested I should use the "initial" and pass that to the form, but this is clearly not working because if I make the fields visible in the form I can see that it is not preselected...
viewy.py:
def addStockView(request):
wineId = request.POST.get('addStock')
if 'addStock' in request.POST:
wine = get_object_or_404(Wine, idwine=int(wineId))
userId = request.user.id
user = get_object_or_404(AuthUser, id=userId)
if request.method == 'POST':
#wineIdNew = request.COOKIES.get('wineIdToAdd')
#wineNew = get_object_or_404(Wine, idwine=wineIdNew)
form = StockForm(request.POST, initial={'fk_wine': wineNew.idwine, 'fk_auth_user': user.id})
if form.is_valid():
form.save()
return redirect('home')
else:
form = StockForm(initial={'fk_wine': wine.id,
'fk_auth_user': user.id})
response = render(request, 'addToStock.html', {'form': form})
response.set_cookie('wineIdToAdd', wineId)
return response
forms.py:
class StockForm(forms.ModelForm):
#fk_wine = ModelChoiceField(queryset=Wine.objects.all(),
# widget=HiddenInput())
#fk_auth_user = ModelChoiceField(queryset=AuthUser.objects.all(),
# widget=HiddenInput())
class Meta:
model = UserWineStock
fields = ['fk_auth_user', 'fk_wine', 'number']
can anyone help me with this..?
Yes, initial data is ignored when a form is bound to submitted data.
Instead of using initial here, you should exclude those two fields from the form and set them on the created object:
form = StockForm(request.POST)
if form.is_valid():
item = form.save(commit=False)
item.fk_wine = wine
item.fk_auth_user = request.user
item.save()
return redirect('home')
(Also, please don't call your fields things like fk_auth_user. Just call it user.)