Query database using POST data in FormView class - django

I'm very new to Django and need help with a simple task. I have two templates.
search.html: renders a simple form with a text field an a submit button and POSTs to /search_results/
search_results.html: need to render the result of database query POSTed to /search_results/
In my forms.py file:
from django import forms
class SystemsForm(forms.Form):
serial_num = form.CharField(label="Serial no.", max_length=45)
In my urls.py
urlpatterns = patterns('',
url(r'^search/$', SystemSearch.as_view()),
url(r'^search_results/$', SystemResult.as_view()),
)
In my views.py file
from django.views.generic.edit import FormView
from inventory.forms import SystemsForm
class SystemSearch(FormView):
# For displaying the form
template_name = 'inventory/search.html'
form_class = SystemsForm
class SystemResult(FormView):
template_name = 'inventory/search_result.html'
form_class = SystemsForm
# How to do these two things?
# Query the database model called Systems with the POST data
# -- Systems.objects.get(serial_num=??)
# pass context to search_result.html
I'm not even sure if I'm heading in the correct direction or completely off from what I should be doing.

Related

Updating post is not saving in the database

hello i'm a beginner to django, i made an edit button where i can edit a post, but the problem is it's not saving in the database[[enter image description here](https://i.stack.imgur.com/ZEtVa.png)](https://i.stack.imgur.com/mfr8g.png)
i tried everything i could went to youtube but nothing
I would use class based views. They are much simpler and less headache. This is how they work. More info here
In your urls you have to add .as_view()
from .views import UpdateView
path('post/<pk>/update', UpdatePost.as_view()),
in views.py
from django.views.generic import UpdateView
class UpdatePost(UpdateView):
template_name = "update_post.html"
model = Post
form = YourForm() or Fields = ["title", "content", "whatever you named them in your models"]
success_url ="/"

Django "extra_context" not being passed to form renderer when using FormView

Django version 4.1
Aim: to render a form, using a custom FORM_RENDERER and a class-based FormView with custom context (extra_context={'svg': {'id_batch': 'number'}}).
Problem: custom context added is successfully added (via the get_context_data method) at one stage of the render, but is not passed to the custom form renderer. You can see in the image of stack trace below (of two sequential calls of the stack) that {'svg': {'id_batch': 'number'}} is present in one context variable, but not in the one passed to the FORM_RENDERER.
The same issue is present if I use a CreateView instead. Below are snippets of the relevant files:
# settings.py
# All of my forms are rendered with this same html snippet
from django.forms.renderers import TemplatesSetting
class CustomFormRenderer(TemplatesSetting):
form_template_name = "form_snippet.html"
FORM_RENDERER = "project.settings.CustomFormRenderer"
# forms.py
from django.forms import ModelForm
from .models import Upload
class UploadForm(ModelForm):
class Meta:
model = Upload
fields = ['batch']
# views.py
from django.views.generic import FormView
from .forms import UploadForm
class MeasurementView(FormView):
# default template will be 'assays/upload_form.html'
template_name = 'assays/upload_form.html'
form_class = UploadForm
extra_context = {'svg': {'id_batch': 'number'}}

Image response from DetailView in Django

I'd like to have a DetailView respond with an image file that is saved to the model/object.
I have seen this related question but what I am doing is a little different.
I have the following model/views/urls - this allows me to display the image in an img tag inside a template when accessing the url localhost/MY-SKU-FIELD. I'd rather not use a template and just respond with the image directly.
# models.py
from django.db import models
class SignModel(models.Model):
sku = models.CharField('SKU', max_length=50)
sign_image = models.ImageField(upload_to='images/sign')
# views.py
from django.views.generic import DetailView
from signs.models import SignModel
class SignDetailView(DetailView):
model = SignModel
template_name = 'signs/sign_detail.html'
slug_url_kwarg = 'sku'
slug_field = 'sku'
# urls.py
from django.urls import path
from signs.views import SignDetailView
urlpatterns = [
path('<slug:sku>', SignDetailView.as_view(), name='sign-detail'),
]
{# 'signs/templates/sign_detail.html #}
<img src="{{object.sign_image.url}}" alt="">
Based on the related question/answer, I figure I need to define my own get() method, then fetch the image, and then respond accordingly, but I'm not quite sure how to fetch the image based on the object fetched in DetailView. I've tried fetching with r = requests.get(self.sign_image.url) but that is clearly not working.
How do I get the image and respond correctly?
I haven't done this before but I was able to quickly check, and you can give the value of the field to a django.http.FileResponse object. As for the view, I think you want to overwrite the render_to_response method.
from django.http import FileResponse
class SignDetailView(DetailView):
model = SignModel
template_name = 'signs/sign_detail.html'
slug_url_kwarg = 'sku'
slug_field = 'sku'
def render_to_response(self, context, **kwargs):
return FileResponse(self.object.sign_image)

How to accept form data and return it along with the results of some processing in Django RESTFramework?

I am trying to understand Django RESTFramework. I am already familiar with Django. I want to create an endpoint that accepts some text data and processes it and returns it to the user along with the results of the processing (in text). I have completed a couple of tutorials on the topic but I still don't understand how it works. Here is an example from a working tutorial project. How can I edit it to achieve my goal? It all looks automagical.
# views.py
from rest_framework import generics
from .models import Snippet
from .serializers import SnippetSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
​
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
# Here I would like to accept form data and process it before returning it along with the
# results of the processing.
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
Okay, I think you are a newbie in Django rest and try to understand its flow so I can explain it with an example of a subscription plan.
First, create a model in models.py file
from django.db import models
class SubscriptionPlan(models.Model):
plan_name = models.CharField(max_length=255)
monthly_price = models.IntegerField()
yearly_price = models.IntegerField()
Then create views in a view.py file like
from rest_framework.views import APIView
class SubscriptionCreateAPIView(APIView):
serializer_class = SubscriptionSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
{'message': 'Subscription plan created successfully.',
'data': serializer.data},
status=status.HTTP_201_CREATED
)
and then define a serializer for validation and fields in which we can verify which fields will be included in the request and response object.
serializers.py
from rest_framework import serializers
from .models import SubscriptionPlan
class SubscriptionSerializer(serializers.ModelSerializer):
plan_name = serializers.CharField(max_length=255)
monthly_price = serializers.IntegerField(required=True)
yearly_price = serializers.IntegerField(required=True)
class Meta:
model = SubscriptionPlan
fields = (
'plan_name', 'monthly_price', 'yearly_price',
)
def create(self, validated_data):
return SubscriptionPlan.objects.create(**validated_data)
Now add urls in src/subsciption_module/urls.py
from django.urls import path
from .views import SubscriptionCreateAPIView
app_name = 'subscription_plan'
urlpatterns = [
path('subscription_plan/', SubscriptionCreateAPIView.as_view()),
]
At the end include module url in root urls.py file where your main urls will be located. It will be the same directory which contains settings.py and wsgi.py files.
src/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('src.subscription_plan.urls', namespace='subscription_plan')),
]
That's it. This is how flow works in django rest and you can process data and display data in this way. For more details you can refer django rest docs.
But this is not in any way different from what you do with plain Django. Your SnippetDetail view is just a class-based view, and like any class-based view if you want to do anything specific you override the relevant method. In your case, you probably want to override update() to do your custom logic when receiving a PUT request to update data.

ListView and Form on the same view, using the form to filter the results

I'm new to Django and I've been trying to make so small app after reading the tutorial but I can't figure out what's wrong with my code.
What I'm trying to do is listing all the database entries of a model called project using a ListView with a form below it (using the same view) that the user can use to filter the entries to be shown by means of submitting data in text fields.
I managed to make that work, and it looks like this:
However, once the user clicks the "Filter results" button providing some filtering pattern on the textfields (let's say, filter by name = "PROJECT3", leaving the other fields blank), instead of rendering a page with the filtered data and the form below it, which is my intention, it just returns a white page.
Can anyone please explain me what is wrong with my code?
Here are the relevant parts:
forms.py
class FilterForm(forms.Form):
pjt_name = forms.CharField(label='Name', max_length=200, widget=forms.TextInput(attrs={'size':'20'}))
pjt_status = forms.CharField(label='Status', max_length=20, widget=forms.TextInput(attrs={'size':'20'}) )
pjt_priority = forms.CharField(label='Priority', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))
pjt_internal_sponsor = forms.CharField(label='Int Sponsor', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))
pjt_external_sponsor = forms.CharField(label='Ext Sponsor', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))
views.py
from App.models import Project
from django.views.generic import ListView
from django.shortcuts import render
from django.template import RequestContext
from App.forms import FilterForm
class ProjectListView(ListView):
context_object_name = 'project_list'
template_name='App/index.html'
def get_context_data(self, **kwargs):
context = super(ProjectListView, self).get_context_data(**kwargs)
if 'filter_form' not in context:
context['filter_form'] = FilterForm()
return context
def get_queryset(self):
form = FilterForm(self.request.GET)
if form.is_valid():
name = form.cleaned_data['pjt_name']
i_sp = form.cleaned_data['pjt_internal_sponsor']
e_sp = form.cleaned_data['pjt_external_sponsor']
status = form.cleaned_data['pjt_status']
pri = form.cleaned_data['pjt_priority']
return send_filtered_results(name, i_sp, e_sp, status, pri)
else:
return Project.objects.order_by('-project_creation_date')[:5]
def send_filtered_results(name, i_sp, e_sp, status, pri):
return Project.objects.filter(project_name__in=name,internal_sponsor_name__in=i_sp, external_sponsor_name__in=e_sp, project_status__in=status, project_priority__in=pri).exclude(alias__isnull=True).exclude(alias__exact='')
urls.py
from django.conf.urls import patterns, url
from App.views import ProjectListView
from django.views.generic import DetailView
from App.models import Project, Task
urlpatterns = patterns('',
url(r'^$',
ProjectListView.as_view())
The answer is in your response/status code:
After doing that I get a white page and runserver returns [23/Jan/2015 00:21:09] "POST /App/ HTTP/1.1" 405 0
You're POSTing to a view that has no POST handler. You should be getting an error saying so, but the 405 means method not allowed.
Add a post method to your CBV. Django class based views map request method to functions, so a GET is handled via CBV.get, POST via CBV.post
For demonstration purposes, add:
# essentially, mirror get behavior exactly on POST
def post(self, *args, **kwargs):
return self.get(*args, **kwargs)
And change your form handler to pull from request.POST not request.GET.
form = FilterForm(self.request.POST)
I suggest you start using print()s or log to start seeing what's happening. request.GET should be empty, as.. you're not using GET parameters. That data will be in request.POST.
Your code is messy and your Project.objects.filter(...) is far to aggressive. It just doesn't return any objects.
Don't use name__in=name but name__contains=name.