Wrong url in pagination. Django - python

I want to search by two fields (q1 and q2):
home.html
<form action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Search...">
<select name="q2" class="form-control" id="exampleFormControlSelect1">
<option>All locations</option>
<option>RU</option>
<option>Ukraine</option>
<option>USA</option>
</select>
<button> Search </button>
</form>
When I click "search" I go to http://127.0.0.1:8001/search/?q=mos&q2=RU (it's OK)
Then I click "next". I go to
http://127.0.0.1:8001/search/?city=2&q=mos&q2=%20RU (ERROR: "Page not found)
but I want
http://127.0.0.1:8001/search/?city=2&q=mos&q2=RU
How can I fix it? Why do I have "%20" ???
search results.html
<h1>Search Results</h1>
<ul>
{% for city in object_list %}
<li>
{{ city.name }}, {{ city.state }}
</li>
{% endfor %}
</ul>
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
models.py
from django.db import models
class City(models.Model):
name = models.CharField(max_length=255)
state = models.CharField(max_length=255)
COUNTRY = (
('RU', 'Russia'),
('UKR', 'Ukraine'),
('US', 'USA'),
)
category = models.CharField(max_length=100, choices=COUNTRY, default='RU')
class Meta:
verbose_name_plural = "cities"
def __str__(self):
return self.name
urls.py
urlpatterns = [
path('search/', SearchResultsView.as_view(), name='search_results'),
path('', HomePageView.as_view(), name='home'),
path('city/<int:pk>/', views.city_detail, name='city_detail'),
]
views.py
class HomePageView(ListView):
model = City
template_name = 'cities/home.html'
paginate_by = 3
page_kwarg = 'city'
def city_detail(request, pk):
city = get_object_or_404(City, pk=pk)
return render(request, 'cities/city_detail.html', {'city': city})
class SearchResultsView(ListView):
model = City
template_name = 'cities/search_results.html'
paginate_by = 3
page_kwarg = 'city'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query'] = self.request.GET.get('q')
# added param
context['query2'] = self.request.GET.get('q2')
#print("BBBBBBBBBBBBBBBBb {}".format(context['query2']))
return context
def get_queryset(self): # new
query = self.request.GET.get('q')
query2 = self.request.GET.get('q2')
#print("AAAAAAAAAAAAAAAAAAAAA", query2, type(query2))
object_list = City.objects.filter(
(Q(name__icontains=query) | Q(state__icontains=query)) & Q(category=query2)
)
return object_list

%20 is the url code for a space. You need to remove the extra spaces in :
previous
# ^
and
next
# ^

Related

i want to display the list of pruducts based on the choice of the category chosing -django

so i want to khow what i have to add in the urls.py and in the views.py to add this functionnality: if i click in one of this categories here my categories display some products based on the category chosen.
and this the models.py
class Product(models.Model):
name=models.CharField(max_length=200,null=True)
price=models.DecimalField(max_digits=7,decimal_places=2)
digital=models.BooleanField(default=False,null=True,blank=True)
image=models.ImageField(blank=True,null=True,upload_to ='images/',default="images/default.jpg")
categories = models.ForeignKey(Category,on_delete=models.CASCADE,blank=True, null=True)
def __str__(self):
return self.name
#property
def imageURL(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return '/static/images/default.png'
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True,
help_text='Unique value for product page URL, created from name.')
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'categories'
ordering = ['-created_at']
verbose_name_plural = 'Categories'
def __unicode__(self):
return self.name
and this is the template :
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href='#'>{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>
This is simplest way. You can change code as per requirement.
urls.py
from . import views # import views.py file
urlpatterns = [
path('product_list/<id>', views.product_list, name='product_list'),
]
views.py
def product_list(request, id):
products = Product.objects.filter(categories__pk=id)
context = {
'products': products,
}
return render(request, 'product_list.html', context)
link template (Check the change in link)
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href="{% url 'product_list' id=c.pk %}">{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>
product_list.html
Your regular html things +
{% for product in products %}
<p>{{ product.name }}</p>
<p>{{ product.price }}</p>
{% empty %} # in case there is no product in this category
<p>No product available for this category</p>
{% endfor %}
I hope this will help. Please comment if get any error.
If you products to load without refreshing the page, you can use ajax. Reply if need that.
You can try this:
views.py
def my_view(request):
category_id = request.GET.get('category_id')
context = {}
if category_id:
products = Product.objects.filter(categories__id=category__id)
context["products"] = products
return render(request, 'template', context)
template
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href='?category_id={{ c.id }}'>{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>

how to display specific results from the dropdown in models.py in django

I want to display only employees which emp_type is 'Doctor'?
** Here is Models.py **
class Employee(models.Model):
name = models.CharField(max_length=50)
emp_type_choices = [
('Nurse', 'Nurse'),
('Doctor', 'Doctor'),
('Other', 'Other'),
]
emp_type = models.CharField(
max_length=6, choices=emp_type_choices, default='Nurse')
def __str__(self):
return self.name
class Ticket(models.Model):
patient = models.CharField(max_length=50)
doctor = models.ForeignKey(Employee, on_delete=models.CASCADE)
def __str__(self):
return self.patient.name
This is my Forms.py
class TicketModelForm(forms.ModelForm):
class Meta:
model = Ticket
fields = ['doctor', 'status']
widgets = {
'doctor': forms.Select(attrs={'class': 'form-control','placeholder': 'Doctor Name'}),
}
This is my Views.py
#login_required
def TicketToGenerateView(request, pk):
ticket = get_object_or_404(Patient, pk=pk)
form = TicketModelForm(request.POST or None)
if form.is_valid():
obj.save()
return redirect('/dashboard/ticket')
context = {
'form': form,
'ticket': ticket,
}
return render(request, 'dashboard/ticket.html', context)
This is my Template
<form action="." method="POST">
{% csrf_token %}.
{% for field in form %}
<div class="form-group">
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<p class="text-danger">{{ error|escape }}</p>
{% endfor %}
{% endif %}
</div>
{% endfor %}
<div class="form-group float-right">
<button type="submit" class="btn btn-success btn-sm" value=" {{ valueBtn }} "> <span
class="glyphicon glyphicon-plus"></span> </button>
</div>
</form>
In the template, I'm displaying all registered employees as a dropdown list, but I would like to display only employees which their emp_type is 'Doctor'.
Also the Admin site I would like to see the only emp_type which are 'Doctor'.
Thanks
# You have to use filter for your query
emp_doctor = Employee.objects.filter(emp_type='Doctor')
print(emp_doctor)

Error: "Cannot use None as a query value" When trying to paginate with ListView in Django

I want to implement pagination in search results. After search I see good result (e.g. http://127.0.0.1:8001/search/?q=mos)
But, when I click "next", I have an error:
ValueError at /search/, Request URL: http://127.0.0.1:8001/search/?city=2
Cannot use None as a query value
I think that problem in urls (search_results.html).
How can I fix it?
How can I change:
next
models.py
from django.db import models
class City(models.Model):
name = models.CharField(max_length=255)
state = models.CharField(max_length=255)
class Meta:
verbose_name_plural = "cities"
def __str__(self):
return self.name
views.py
class HomePageView(ListView):
model = City
template_name = 'cities/home.html'
paginate_by = 3
page_kwarg = 'city'
def city_detail(request, pk):
city = get_object_or_404(City, pk=pk)
return render(request, 'cities/city_detail.html', {'city': city})
class SearchResultsView(ListView):
model = City
template_name = 'cities/search_results.html'
paginate_by = 3
page_kwarg = 'city'
def get_queryset(self): # new
query = self.request.GET.get('q')
object_list = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return object_list
urls.py
urlpatterns = [
path('search/', SearchResultsView.as_view(), name='search_results'),
path('', HomePageView.as_view(), name='home'),
path('city/<int:pk>/', views.city_detail, name='city_detail'),
]
search_results.html
<ul>
{% for city in object_list %}
<li>
{{ city.name }}, {{ city.state }}
</li>
{% endfor %}
</ul>
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
home.html
<form action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Search...">
</form>
<ul>
{% for city in object_list %}
<li>
<h1>{{ city.name }}</h1>
</li>
{% endfor %}
</ul>
You get an error saying ValueError, query is None because you do not pass in the query q in the href for your next and previous anchor tags.
Modify search_results.html by defining the next and previous anchor tags like so:
next
Now open views.py. Inside SearchResultsView, you need to add another key calledquery to your context dictionary. To do so, define a method called
get_context_data(self, **kwargs) inside the SearchResultsView class.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query'] = self.request.GET.get('q')
return context
With that, query will be passed in to the template so that your
next link looks like http://localhost:8000/search/?city=2&q=a
Modify search_results.html
Change the next & previous page link in your template as given below.
Previous
Next
Modify urls.py
remove "/" from search_results like given below...
path('search', SearchResultsView.as_view(), name='search_results'),
Then your search URL will be something like that...
http://localhost:8000/search?q=abcd&city=2

django two ModelForms with same field name on one template

I have two models and both have field 'status' which has different meaning for them.
class Order(models.Model):
...
status = models.PositiveIntegerField(default=0, choices=ORDER_STATUSES)
...
class ACS(models.Model):
status = models.IntegerField(default=-1, choices=STATUSES)
order = models.ForeignKey(Order, blank=True, null=True)
...
Their forms looks like:
class ACSForm(forms.ModelForm):
status = forms.ChoiceField(
choices=STATUSES,
widget=forms.Select(attrs={'class': 'form-control'})
)
...
class Meta:
model = ACS
fields = ('status',)
class OrderACSEditForm(forms.ModelForm):
status = forms.ChoiceField(
choices=ORDER_STATUSES,
widget=forms.Select(attrs={'class': 'form-control'})
)
class Meta:
model = Order
fields = ('status',)
I want to edit both this fields on the same page. My view.py looks like
def edit(request, item_id=""):
data = ACS.objects.get(pk=item_id)
form = ACSForm(instance=data)
order = Order.objects.get(id=data.order.id)
form_edit = OrderACSEditForm(instance=order)
if request.POST:
form = ACSForm(request.POST, instance=data)
form_edit = OrderACSEditForm(request.POST)
if form.is_valid() and form_edit.is_valid():
form_edit.save()
obj = form.save()
messages.add_message(request, messages.SUCCESS, 'Your data successfully saved.')
if request.POST['action'] == "save_stay":
return redirect("/panel/packages/acs/edit/" + str(obj.id))
else:
return redirect("/panel/packages/acs/")
return render(request, 'ui/packages/acs/edit.html', dict(data=data, form=form, form_edit=form_edit, item_id=item_id))
And template:
<div class="form-group {% if form.status.errors %}has-error{% endif %}">
<label>{% trans "Status" %}</label>
{% if form.status.errors %}
{% for error in form.status.errors %}
<label class="control-label">{{ error }}</label>
{% endfor %}
{% endif %}
{{ form.status }}
</div>
<div class="form-group {% if form_edit.status.errors %}has-error{% endif %}">
<label>{% trans "Order status" %}</label>
{% if form_edit.status.errors %}
{% for error in form_edit.status.errors %}
<label class="control-label">{{ error }}</label>
{% endfor %}
{% endif %}
{{ form_edit.status }}
</div>
But in result form.status gets values from form_edit.status which is not correct. I need to solve this problem without changing names of model fields but don't know how.
Use the prefix argument for your forms, to namespace the field names.
form = ACSForm(prefix='acs', instance=data)
form_edit = OrderACSEditForm(prefix='edit', instance=order)
Remember to use the same prefix when you instantiate the form with POST data as well.

Using Check boxes in Taggit

I am trying to use Taggit for users to be able to tag their posts while they are submitting a form. But I can successfully let them type manually(their tags), I am trying to change to check boxes. Any ideas?
forms.py
class TalesForm(ModelForm):
class Meta:
model = Tale
fields = ('title', 'body', 'tags')
m_tags = TagField()
models.py
class Tale(models.Model):
title = models.CharField(max_length = 50)
body = models.TextField(max_length = 10000)
pub_date = models.DateTimeField(default = datetime.now)
poster = models.CharField(max_length = 30)
tags = TaggableManager()
def __unicode__(self):
return self.title
views.py
def add(request):
if request.user.is_authenticated():
if request.method=='POST':
form=TalesForm(request.POST)
if form.is_valid():
m_tags = form.cleaned_data['tags']
newTale=Tale(title=form.cleaned_data['title'], body=form.cleaned_data['body'], poster = request.user)
newTale.save()
for m_tag in m_tags:
newTale.tags.add(m_tag)
#form.save_m2m()
return HttpResponseRedirect('/home/%s'%newTale.id)
else:
return render_to_response('story/add.html', {'form':form}, context_instance=RequestContext(request))
else:
form=TalesForm()
args = {}
args.update(csrf(request))
args['form'] = form
context= {'form': form}
return render_to_response('story/add.html',context, context_instance=RequestContext(request))
else:
return HttpResponseRedirect('/home')
html
<form method="post" action="/home/add/">
{% csrf_token %}
<div class="register_div">
{% if form.title.errors %}<p class="error" >{{ form.title.errors }}</p>{% endif %}
<p><label for="title"{% if form.title.errors %} class="error"{% endif %}>Title:</label></p>
<p>{{ form.title}}</p>
</div>
<div class="register_div">
{% if form.body.errors %}<p class="error" >{{ form.body.errors }}</p>{% endif %}
<p><label for="body"{% if form.body.errors %} class="error"{% endif %}>Body:</label></p>
<p>{{ form.body }}</p>
</div>
<div class="register_div">
<p><label for="tag">Tags:</label></p>
<p>{{ form.tags }}</p>
</div>
<input type="submit" value="Add Story" name="submit" />
</form>
Define your form this way:
from taggit.models import Tag
class TalesForm(ModelForm):
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=forms.CheckboxSelectMultiple())
class Meta:
model = Tale
fields = ('title', 'body', 'tags')

Categories