Django filtering based on data - django

I'm using django to develop a web app. Right now I am trying to make a page that will initially render a blank form and all data objects of a certain model, and then once the user submits the form, will then filter the objects displayed to show those that have the desired attributes.
My form class is as follows
class AreaForm(forms.Form):
seating = forms.IntegerField(label='Seating', default=False)
whiteboards = forms.BooleanField(label='Whiteboards', default=False)
outlets = forms.IntegerField(label='Outlets', default=False)
tables = forms.IntegerField(label='Tables', default=False)
And the view for this page thus far is
def search(request):
if request.method == 'GET':
form = NameForm(request.POST)
if form.is_valid():
# do filtering logic here somehow
return render(request, 'SpotMe/search.html', {'form': form}) # ????
else:
return render(request, 'SpotMe/search.html', {}) # ????
I'm as of yet unsure how to implement the templates page. Am I headed in completely the wrong direction?

To show the form empty and do some logic when user post data, you need to pass the form to the template and it'll render empty if there is not post data.
view.py
def search(request):
form = AreaForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
# do filtering logic here somehow
return render(request, 'SpotMe/search.html', {'form': form})
search.html
.....
{{ form.as_p }}
.....

Based on your reply to my question below your original post, this is an easy solution that will show all data object of a model, and then you can use an input and submit it from a template to filter the results on the same page.
Note: Substitute MODEL for your actually model name. You don't need a form if you are looking to filter results (it is an extra, unnecessary step).
def search(request):
if request.method == 'GET':
if request.GET.get('seating_no'):
seating_no = request.GET.get('seating_no')
queryset = MODEL.objects.filter(seating=seating_no)
else:
queryset = MODEL.objects.all()
return render(request, 'SpotMe/search.html', {'queryset': queryset})
and in your SpotMe/search.html you can have a <form><input name="seating_no" /></form> and submit button that will lead to the same URL, and make the input name(s) into whatever you want to capture via request.GET.get()

Related

Do I really need to accommodate both GET and POST request formats in a django form?

I'm new to django but something I don't understand is the need for accommodating both the GET and POST request types when developing a form. Please refer to code below from django docs:
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
The reason this confuses me is because I have developed a GET based form and it is working and I have no need for the POST portion above? See below:
# views.py
def simplifier_form(request):
form = LabelForm()
return render(request, "simplifier.html", {"form": form})
def process_simplifier(request):
label_name = request.GET.get('labels')
results = Disturbance.objects.filter(labeldisturbances__label_name=label_name)
painsresults = Pain.objects.filter(disturbances__pk__in=results).distinct()
total_disturbances = Disturbance.objects.filter(pain__pk__in=painsresults)
total_labels = Label.objects.filter(disturbances__pk__in=total_disturbances).distinct()
context = {'results': results, 'painsresults': painsresults, 'total_disturbances': total_disturbances, 'total_labels': total_labels}
return render(request,'process_simplifier.html', context)
# forms.py
class LabelForm(ModelForm):
labels = forms.ModelChoiceField(
queryset=Label.objects.all(),
to_field_name='label_name',
widget=forms.Select(attrs={'class': 'labels'}),
)
class Meta:
model = Label
fields = ['labels']
So why do the django docs and most examples include code for both methods when you only really use one like in my example above?
The question is... How do you want to process your from when submitted on POST?
Remember, your form can also be submitted on GET... You can decide what you would want to do if submitted on GET.

Views are different but rendering same template

i want to use slug field in both url which is
path('<slug:title>/',views.news_read,name="news_read"),
path('<slug:title>/',views.movie_read,name="movie_read"),
but both the url picking same template instead of their template i am trying to create blog site
i don't understand both the url are uniques so why django is picking wrong template
my views for both the url
def movie_read(request, title):
movie = Movie.objects.filter(urltitle=title)
if request.method == 'POST':
form = Commentform(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Thank You For Your Comment')
else:
form = Commentform()
return render(request,'movie_read.html',{'movie':movie,'form':form})
def news_read(request, title):
news = News.objects.filter(urltitle=title)
if request.method == 'POST':
form = Commentform(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Thank You For Your Comment')
else:
form = Commentform()
return render(request,'news_read.html',{'news':news,'form':form})
but i when do some change like this it work
path('<slug:title>/news',views.news_read,name="news_read"),
path('<slug:title>/movie',views.movie_read,name="movie_read"),
but this doesn't look good any idea what to do solve the issue
Django will "fire" the first path that matches the URL. This thus means that for every slug you enter, news_read will fire.
You can solve this by trying to query both models, and then decide which to use, like:
def my_view(request, title):
is_movie = Movie.objects.filter(urltitle=title).exists()
if is_movie:
return movie_read(request, title)
else:
return news_read(request, title)
def movie_read(request, title):
# …
def news_read(request, title):
# …
and then thus trigger the my_view function if it is a slug:
path('<slug:title>/', views.my_view, name='news-movie-read'),
but a more elegant solution is to simply define two non-overlapping URL patterns:
path('news/<slug:title>/', views.news_read,name='news_read'),
path('movie/<slug:title>/', views.movie_read,name='movie_read'),
This also will prevent clashes where a Movie object and a News object have both the same url_title since in that case, it will always use the movie_read view.
I seems that tou url path is the same, that is why django picking wrong view.
Try to change urls to this:
path('news/slug:title/',views.news_read,name="news_read"),
path('movies/slug:title/',views.movie_read,name="movie_read"),

how to do i automatically set the user field to current user in django modelform

How can i set the current login user to the user field of django model .In my view ,i am using function base view .My model is something like this .
Model.py
class DistributionProfile(Abstract_Class):
Distributortype =(
('B2B1','b2b'),
('b2c','b2c'),
('c2c','c2c'),
('govt4','govt'),
)
ManufacturerType=(('Machine1','Machines'),
('Pharmaceutical2','Pharmaceutical'),
('Jewelries3','Jewelries'),
('Furniture4','Funitures'),
('Electronics5','Electronics'),('Textile6','Textile'),
('Constructionmaterials7','ConstructionHardware'),
('Beverages8','Beverages'),
('Cosmetics9','Cosmetics'),
('Convectionaries10','Convectionaries'),
('AgriculturalProduce11','AgriculturalProduce'),
('RawMaterials12','RawMaterials'),
('CrudOil13','CrudOil'),
('SeaFood14','SeaFood'),
)
title =models.CharField(choices=Distributortype ,null=True,max_length=250,blank=False)
ManufacturerOfInterest =MultiSelectField(choices=ManufacturerType,null=True,blank=False,max_choices=14)
verified = models.BooleanField(default=False,blank=True)
promot=models.BooleanField(default=False,blank=False)
slug = models.SlugField(default='')
user=models.ForeignKey(User,null=True,on_delete=models.CASCADE)
bellow is my form.I would love the form to automatically have the information of the login user filling the form .Meaning the user field should automatically have the information of the login in user .So that i can easily query and display objects created by the login user
form.py
class DistributionProfileForm(forms.ModelForm):
class Meta:
model= DistributionProfile
exclude= ['slug','user','CreatedTime','verified','promot','UpdatedTime']
widgets ={
'CompanyRegisteredName':forms.TextInput(attrs={'class':'distributorform','placeholder':'Name of your company','autofocus':'True'}),
'CompanyRegisteredState':forms.TextInput(attrs={'class':'distributorform','placeholder':' StateOfRegistry'}),
'CompanyRegisteredAddress':forms.TextInput(attrs={'class':'distributorform','placeholder':'Company Address'}),
'CompanyRegisteredCity':forms.TextInput(attrs={'class':'distributorform','placeholder':'Company registered city'}),
'CompanyWebsiteLink':forms.TextInput(attrs={'class':'distributorform','placeholder':'www.mycompany.com'}),
'RegisteredCompanyType':forms.Select(attrs={'class':'distributorform '}),
'Country':forms.Select(attrs={'class':'distributorform'}),
'ManufacturerOfInterest ':forms.CheckboxSelectMultiple(attrs={'class':'multiple_select'}),
}
fields=['CompanyRegisteredName',
'CompanyRegisteredState',
'CompanyRegisteredAddress',
'CompanyRegisteredCity',
'CompanyWebsiteLink',
'RegisteredCompanyType',
'Country','title',
'ManufacturerOfInterest'
]
view.py
def SetUpDistributor(request):
if not request.user:
return HttpResponse('login to access this page ')
if request.method =='POST':
distributor = DistributionProfileForm(request.POST,request.FILES)
if distributor.is_valid():
distributor.save(commit=False)
distributor.user=request.user
distributor.save()
messages.success(request,'Distributor profile created ')
return redirect('gbiz1990:distributor_profile_setup')
else:
messages.error(request,'Something went wrong')
else:
distributor=DistributionProfileForm()
return render(request,"gbiz1990/User_function_pages/distributors.html",{'distributor':distributor})
Your views, may looks like that:
def your_view(request):
form = YourForm(request.POST or None)
if form.is_valid():
your_object = form.save(commit=False)
your_object.user = request.user
your_object.save()
return redirect('your_success_url')
context = {'form': form}
return render(request, 'your_template.html', context)
You need to adapt some parts, but in the general the should be your view. You need to pay attention to that this view needs a login_required decorator in order to not allow non-logged users to create objects.
Use the request.user. I don't know how your app works but when creating, do this:
model = ModelName(user = request.user)
model.save()
I used ModelName because it is best practise to start a class name with a capital, which is not fulfilled in your create model. I suggest you change this.
There also seems to be a mistake in your view, it should be request not reques.
Your view could be like so:
def index(request):
form = FormName(request.POST or None)
if form.is_valid():
form.save()
return render(request, "path/to/template", {"form": form})
And your template could be:
<form method="POST" action="">
{{ form }}
<input type="submit">
</form>
So i solved my problem
in my model.py
class SetdistributorProfile(models.Model):
user=modelss.foreignkey(settings.AUTH_USER_MODEL,null=True,unique=True)
views.py
def SetDistribution(request):
if not requested.user.is_authenticated:
return redirect('app_name:url_name)
if request.method === 'POST':
dis = MymodelForm(request.POST or None)
if dis.is_valid():
instance=dis.save(commit=False)
instance.user=request.user
instance.save()
return redirect('myappname:urlname')
else:
instance=MymodelFomr()
context={'intance':intance}
return render(request,'page.hmtl',context)
Another way to solve this in your views.py
if request.method == "POST":
yourModel = YourModel(user_id = request.user.id)
form = YourModelForm(request.POST, request.FILES, instance=yourModel)
if form.is_valid():
form.save()

Using session to store form input values in order to uso in another view

I am storing some form values, which is a list filter, from a post method in the request.session in order to use it in another view function to render the filtered results. The problem is any user that I log in keep the results stored, if they access the results page directly they will see other users filter results.
I use pagination (digg without AJAX), I am using django-el-pagination.
the views.py
def search(request):
if request.method == 'POST':
form = ComprarBuscaForm(request.POST)
if form.is_valid():
cidade = form.cleaned_data['cidade']
request.session['cidade'] = form.cleaned_data['cidade']
request.session['quartos'] = form.cleaned_data['quartos']
request.session['tipo_imovel'] = form.cleaned_data['tipo_imovel']
request.session['preco_minimo'] = form.cleaned_data['preco_minimo']
request.session['preco_maximo'] = form.cleaned_data['preco_maximo']
request.session['area_minima'] = form.cleaned_data['area_minima']
request.session['area_maxima'] = form.cleaned_data['area_maxima']
return HttpResponseRedirect(reverse('imoveis:resultado_busca'))
else:
form = ComprarBuscaForm()
return render (request, 'imoveis/busca_comprar.html', {'form':form})
def search_result(request):
anuncios = Anuncio.objects.filter(quartos=request.session['quartos'],
cidade=request.session['cidade'],
tipo_imovel=request.session['tipo_imovel'],
preco_venda__gte=request.session['preco_minimo'],
preco_venda__lte=request.session['preco_maximo'],
area_construida__gte=request.session['area_minima'],
area_construida__lte=request.session['area_maxima'],
tipo_anuncio='Venda')
return render(request, 'imoveis/resultado_busca_comprar.html', {'anuncios': anuncios})
Everything is working fine although the fact I mentioned before. I am wondering if what I am doing is the right approach for this kind of situation.
Is it really necessary to use two views for this? I would filter and render in the same form view if I were you.
def search(request):
if request.method == 'POST':
form = ComprarBuscaForm(request.POST)
if form.is_valid():
anuncios = Anuncio.objects.filter(quartos=request.session['quartos'],
cidade=request.session['cidade'],
tipo_imovel=form.cleaned_data['tipo_imovel'],
preco_venda__gte=form.cleaned_data['preco_minimo'],
preco_venda__lte=form.cleaned_data['preco_maximo'],
area_construida__gte=form.cleaned_data['area_minima'],
area_construida__lte=form.cleaned_data['area_maxima'],
tipo_anuncio='Venda')
return render(request, 'imoveis/resultado_busca_comprar.html', {'anuncios': anuncios})
else:
form = ComprarBuscaForm()
return render (request, 'imoveis/busca_comprar.html', {'form':form})

How to get Django Form to return the same page

I have a form that I've been working on, currently displaying in a template called search_test.html, that I've finally gotten working right. I want to actually integrate it into my site, but on my site it's not going to be its own page, it's going to be a sidebar that's present on most pages. I know when I do that, this line
return render_to_response('corpus/search_test.html',
{'form': form}, context_instance=RequestContext(request))
is going to give me problems, because I don't want to actually redirect to search_test.html.
What can I replace this 'render_to_response' with, to tell it to just stay on the same page, but still pass the form info? I know this has got to be something simple, but I've looked all over online and in the docs and I can't find a similar example. (The view code for the form is below.)
Thank you.
def concord_test(request):
if request.method == 'POST': # If the form has been submitted...
form = ConcordanceForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
searchterm = form.cleaned_data['searchterm'].encode('utf-8')
search_type = form.cleaned_data['search_type']
category = form.cleaned_data['category']
context, texts_len, results_len = make_concordance(searchterm, search_type, cat=category)
return render_to_response('corpus/concord.html', locals()) # Redirect after POST
else:
form = ConcordanceForm() # An unbound form
return render_to_response('corpus/search_test.html',
{'form': form}, context_instance=RequestContext(request))
In a function page view (as per example)
you can do something like
def other_page(request):
if request.method == 'POST':
return concord_test(request)
else:
form = ConcordanceForm()
#Processing for other_page
object_list = OtherPageModel.objects.all()
return render_to_response('corpus/other_page.html',
{'form': form , 'object_list': object_list }, context_instance=RequestContext(request))
my advice: study class based views , you can have more granular capabilities dealing with 'repetitive' tasks like this & more.