How do i add a searchbar through class based view - django

I am new to django and I am trying to create a simple clone version of [pastebin.com][1] that has only one model with name and content. I have created the searchbar in my root template. But what is the actual Class View to filter only the name and show a list of name and content? ` Patebin Assesment Project
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search"/>
<input class="searchbutton" type="submit" value="Search"/>
</form>`
As I have already said I am very new with django. Here's My model
from django.db import models
from django.urls import reverse
# Create your models here.
class Post(models.Model):
name = models.CharField(db_index=True, max_length=300, blank=False)
content = models.TextField()
generated_url = models.CharField(db_index=True, max_length=10, blank=False)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("pastebin_app:detail",kwargs={'pk':self.pk})

You need to create a view to handle the search behavior. There is no such generic view, but it's quite easy to create:
class SearchView(TemplateView):
template_name = 'search.html'
def get(self, request, *args, **kwargs):
q = request.GET.get('q', '')
self.results = Post.objects.filter(name__icontains=q)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
return super().get_context_data(results=self.results, **kwargs)
Add your view to your urls.py:
url(r'^search/$', SearchView.as_view(), name='search')
And make sure you set the right action and method attributes to your search form:
<form method="GET" action="{% url 'pastebin_app:search' %}">

Related

error with slug in django - template it show all posts data in each post

Error with a slug in Django - template it shows all posts data in each post
when I create a new post and write my data it shows all data from other posts why is that?
and how I can fix it?
also how I can add an auto-generation slug?
models.py :
from django.urls import reverse
from django.utils.text import slugify
class Android(models.Model):
title = models.CharField(max_length=50,default="",help_text="this is title for slug not post!")
name = models.CharField(max_length=50,default="")
app_contect = models.CharField(max_length=240,default="")
app_image = models.ImageField(upload_to='images/',null=True, blank=True)
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
post_tag = models.CharField(max_length=50,default="",choices = BLOG_SECTION_CHOICES)
slug = models.SlugField(null=True,uniqe=True) # new
def get_absolute_url(self):
return reverse('android_posts', kwargs={'slug': self.slug}) # new
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
views.py :
def android_posts(request,slug):
android_posts = Android.objects.all()
context = {'android_posts':android_posts}
return render(request,'android/android_problems_fix.html', { 'android_posts': android_posts })
html page :
{% for android in android_posts %}
<h1 id="font_control_for_header_in_all_pages">{{android.name}}</h1>
<hr>
<p id="font_control_for_all_pages">{{android.app_contect}}</p>
{% endfor %}
url :
path('Android/<slug:slug>', views.android_posts, name='android_posts'),
To autogenerate your slug (and only do it on initial save, so that it remains consistent), add the generation to your model save method:
def save(self, *args, **kwargs):
super(<Model>, self).save(*args, **kwargs)
if not self.pk:
self.slug = <slugify code here>
As for your view/Template, you are specifically selecting all posts using:
android_posts = Android.objects.all()
Passing them to the template, then looping over them with the for loop to display them all.
Instead of this, select only a single object with:
android_post = Android.object.get(pk=<pk value>)
Edit after you added your urls.py:
You can get the unique object for a slug with:
android_post = get_object_or_404(Android, slug=slug)
The use of get_object_or_404 will also handle the case where that record doesn't exist.
You haven't posted your urls.py, so not sure how you're linking to this view, but if it includes the slug in the url, you will be able to get this in the view. My guess is you're not accessing via slug in the url, but via the id field.
Personally, when I slugify some text, I always include the id - it is a better way of ensuring uniqueness. By specifying unique=True on your non-pk slug field, you are likely restricting the titles people can use (2 people couldn't use the same title then!)
To give you an example, this is how I am doing it on one of my models:
def save(self, *args, **kwargs):
if not self.id or not self.slug:
super(Android, self).save(*args, **kwargs)
self.slug = slugify(f"{self.title} {str(self.id)}")
super(Android, self).save(*args, **kwargs)
This slug will always be unique because it includes id - and 2 people could have a record with the same title value without the system objecting.

405 error on submitting a modelform using class based views

I created a ModelForm which renders correctly and displayed but whenever i try to submit the form I get a 405 error and the page doesnt redirect to success page.
Ive gone through the django 2.2 documentation trying many different things but nothing seems to work
My code is configured as such the template:
<form enctype="multipart/form-data" action="{% url 'order_thanks' %}"
method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<input name="Submit" type="submit" class="btn btn-success" value="Git my
food!"></input>
The model:
from django.db import models
from django.forms import ModelForm, Textarea, Select,
CheckboxSelectMultiple, CheckboxSelectMultiple
from django import forms
BURGER_CHOICES = (("AFBB", "Aurion's Famous Beef Burger"), ("AIPB",
"Aurion's Infamous Pork Burger"), ("AULB", "Aurion's Undiscovered Lamb
Burger"), ("POG", "Pureed Otter Giblets"))
BUN_CHOICES = (("WHITE","White Bread"), ("RYE","Rye"), ("TPOODLE",
"Teacup Poodles"), ("AFOSSIL","Ammonite Fossils"))
TOPPING_CHOICES = (("CHEESE", "Cheese"), ("LETTUCE", "Lettuce"),
("TOMATOE", "Tomatoe"), ("ONION", "Onion"), ("WSHAVE", "Wood Shavings"))
SAUCES_CHOICES = (("OZTS", "Our Zesty Barbaque Sauce"), ("SEZBS",
"Someone Elses Zesty Barbaque Sauce"), ("VS", "Varmint Squeezings"))
EXTRAS_CHOICES = (("P", "Pinapple"), ("SG", "Soylent Green"), ("SB",
"Soylent Blue"), ("MWS", "More Wood Shavings"))
class Order(models.Model):
burger = models.CharField(max_length=50,choices=BURGER_CHOICES )
bun = models.CharField(max_length=50, choices=BUN_CHOICES)
toppings = models.CharField(max_length=60, choices=TOPPING_CHOICES)
sauces = models.CharField(max_length=60, choices=SAUCES_CHOICES)
extras = models.CharField(max_length=60, choices=EXTRAS_CHOICES)
# def get_absolute_url(self):
# return reverse('burger', kwargs={'pk': self.pk})
def __str__(self):
return self.burger
def get_absolute_url(self):
return reverse('order-thanks', kwargs={'pk': self.pk})
class OrderForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['toppings'].widget = forms.CheckboxSelectMultiple()
for field_name in self.fields:
field = self.fields.get(field_name)
if field and isinstance(field , forms.TypedChoiceField):
field.choices = field.choices[1:]
self.fields['extras'].widget = forms.CheckboxSelectMultiple()
class Meta:
model = Order
fields = ['burger', 'bun', 'toppings', 'sauces', 'extras']
the view:
class OrderView(CreateView, FormView):
template_name = 'order_form.html'
form_class = OrderForm
success_url = 'order/thanks/'
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
def get(self, request):
return Response(code=200)
class OrderThanksView(TemplateView):
template_name = 'order_thanks.html'
the urls:
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.HomePage.as_view(),name='home'),
path('about/', views.AboutPage.as_view(),name='about'),
path('order/', views.OrderView.as_view(),name='order'),
path('order/thanks/',
views.OrderThanksView.as_view(),name='order_thanks'),
]
Appologies I dont know how to display the code correctly in the post.
I added some debugging to the code and it turns out that the form is not valid so the redirect doesnt happen?
===============
I got the redirect working by making the multiple choice checkboxes as blank=True and setting the action in the template to "{% url 'order' %}
There seems to be an issue with the form when you select multiple options with eh check-boxes. Any help would be appreciated.

How do i implement my ClassView to my template html for a search behavior?

I'm super new to django. I am trying to create a clone of pastebin.com which has only one model (Post) with name , content and generated_url.
I am having problem with the searchbar . I dont know how to implement the SearchView into search.html that generate
here's my model
from django.db import models
from django.urls import reverse
# Create your models here.
class Post(models.Model):
name = models.CharField(db_index=True, max_length=300, blank=False)
content = models.TextField()
generated_url = models.CharField(db_index=True, max_length=10, blank=False)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("pastebin_app:detail",kwargs={'pk':self.pk})
here's my root.html for the searchbar
<form action="{% url 'pastebin_app:search' %}" method="get" accept-charset="utf-8">
<input name="q" type="text" placeholder="Search">
<input type="submit" value="Search"/>
</form>
and here's the views.py for searchview
class SearchView(ListView):
template_name = 'pastebin_app/search.html'
model = models.Post
def get(self, request, *args, **kwargs):
q = request.GET.get('q', '')
self.results = models.Post.objects.filter(name__icontains=q)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
return super().get_context_data(results=self.results, **kwargs)
Can someone please help me creating the show.html template that produce the search result from the SearchView?
You need to checkout django-filter contains a simple api to help you get setup with filtering objects and also how to handle complex filters.
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render(request, 'my_app/template.html', {'filter': f})

django form drop-down choices are displayed "objects" instead of string representation of the model __str__

In my django form I am using a method to filter the drop down options to the ones that are related to the logged-in user. After the implementation the displayed values changed to objects rather than the __str__ value. I am posting the simplified codes and a snapshot that shows this. I have followed everything needed, but I cannot figure out why this is happening:
models.py
class Business(models.Model):
client=models.ForeignKey('Client',on_delete=models.CASCADE, limit_choices_to={'is_active':True},)
name=models.CharField(max_length=30,blank=False, unique=True,)
def __str__(self):
return self.name
class MMRequestAttributes(models.Model):
client=models.ForeignKey('Client',on_delete=models.CASCADE, limit_choices_to={'is_active':True},)
business=models.ForeignKey('Business', on_delete=models.CASCADE,limit_choices_to={'is_active':True},)
class Ticket(MMRequestAttributes):
no=models.CharField('Ticket Number',max_length=50,default=uuid.uuid4,null=False, blank=False, editable=False, unique=True)
subject=models.CharField('Subject',max_length=100,null=False, blank=False)
description=models.TextField('Description',max_length=500,null=True,blank=True)
created_at=models.DateTimeField('Created at',auto_now_add=True, editable=False)
updated_at=models.DateTimeField('Updated at',auto_now=True, editable=False)
created_by= models.ForeignKey(settings.AUTH_USER_MODEL)
status=StateField(editable=False)
def __str__(self):
return 'Ticket #' + str(self.pk)
views.py
def new_ticket(request):
form=NewTicket(request.user)
return render(request,'mmrapp/new_ticket.html',{'form':form})
admin.py
class UserExtend(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=False,null=False,)
client=models.ForeignKey('Client', on_delete=models.CASCADE,limit_choices_to={'is_active': True},)
forms.py
from django import forms
from .models import Ticket, Business
from .admin import UserExtend
from django.forms import ModelChoiceField
class NewTicket(forms.ModelForm):
def __init__(self,user, *args, **kwargs):
super(NewTicket, self).__init__(*args, **kwargs)
try:
client_id = UserExtend.objects.values_list('client_id', flat=True).get(user=user)
self.fields['business'].queryset=Business.objects.filter(client__id=client_id)
except UserExtend.DoesNotExist:
### there is not userextend corresponding to this user, do what you want
pass
class Meta:
model=Ticket
fields = ('subject','business')
new-ticket.html
{% extends 'mmrapp/__l_single_column.html' %}
{% load static %}
{% block main_col %}
<h1>New Ticket</h1>
<form method="POST" class="new-ticket">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Submit</button>
</form>
{% endblock main_col %}
Finally I found the problem. Somehow django cannot load the original models' string representation of their objects (__str__) when showing them as choices in the drop downs. I had to explicitly define them again inside the from model. The attribute is called label_from_instance. The good thing is this way one can display them different from what they are originally defined in the models.
so the monkey patch would be:
self.fields['business'].label_from_instance = self.business_label
#staticmethod
def business_label(self):
return str(self.name)
In Python 2.7 we were using
def unicode(self):
return self.name
After the python upgrade from 2.7 to 3.6 it was showing all object references in the dropdown so I added
def str(self):
return self.name
I added this method to the model in question:
def __str__(self):
return self.whatever_prop_suits_your_needs

NoReverseMatch for SlugField?

I 'slugified' the team_name field for model Team so that spaces would display more beautifully in the URL. However when I try to switch the pk variable that you pass into the URL, I get a NoReverseMatch for the slug. It is working fine for with team_name.
models
class Team(models.Model):
team_name = models.CharField(max_length=25, unique=True)
team_name_slug = models.SlugField(max_length=25, unique=True)
views + template URL (this doesn't work)
def team_public_profile(request, pk):
team = get_object_or_404(Team, team_name_slug=pk)
... other code
---
<form action="{% url 'team_public_profile' pk=team_name_slug %}">
this works
def team_public_profile(request, pk):
team = get_object_or_404(Team, team_name=pk)
... other code
---
<form action="{% url 'team_public_profile' pk=team_name %}">
First of all, you need to populate the team_name_slug using django.utils.text.slugify on the Team model save() method like:
from django.utils.text import slugify
class Team(models.Model):
...
def save(self, *args, **kwargs):
if self.team_name:
self.team_name_slug = slugify(self.team)
super(Team, self).save(*args, **kwargs)
Your URL should look like:
url(r'^teams/(?P<team_name_slug>[\w-]+)/$', views.team_public_profile, name='team_public_profile')
And your View + Template:
def team_public_profile(request, team_name_slug):
team = get_object_or_404(Team, team_name_slug=team_name_slug)
... other code
<form action="{% url 'team_public_profile' team_name_slug=team_name_slug %}">