I am looking to change the wording of a button depending on a url path. I have tried to use some {% if blocks %} but unable to get it to work.
I have tried to the following if block
<div class="form-group">
{% if url == 'http://localhost:8000/client/<int:pk>/update/' %}
<button class="btn btn-outline-info" type="submit">Update</button>
{% else %}
<button class="btn btn-outline-info" type="submit">Post</button>
{% endif %}
</div>
This is my url in my apps urls.py
path('client/<int:pk>/update/', PostUpdateView.as_view(), name="post-update"),
Any help would be handy.
You can store the url in a temporary variable and then use it against if condition.
In django template:
{% url 'post-update' pk=1 as the_url %}
{% if request.path == the_url %}
<button class="btn btn-outline-info" type="submit">Update</button>
{% else %}
<button class="btn btn-outline-info" type="submit">Post</button>
{% endif %}
Here request.path is your current url.
Related
How are you community, I'm a little confused between my newbies and lack of knowledge, I'm working on a small project in Django and I'm also trying to send data from a form action in the html to another view function but I'm not understanding it well How does this work and on top of that I have to send several data not just one and it confuses me even more, I have the following HTML:
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="/interface/" method="POST" class="card card-body">
<h1>Interface</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devicess %}
<option>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
{% csrf_token %}
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.Interface}}</h2>
{% if interface.Description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.Description}}</P>
{% endif %}
<form action= "{% url 'send_description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.Status == "up" %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}
and aesthetically to better understand the first POST executed like this:
So far everything is perfect, if I press the "Send change" button it redirects me perfectly, the problem is that I need to send various data such as device.id, interface to that function that I am executing in the action= "{% url 'send_description' %} .Interface and also the content of the input that is inside the same form. Could you give me a hand or a guide on where to find the best way?
regards!
Let me start by saying that this would work way better with JS and AJAX. But, to answer your question, data is passed via Django http request object, in your case, since you have several different forms, it is possible to pass this data by adding a hidden field inside each form with the desired value:
<input type="hidden" name="interface" value="{{ interface.id }}">
And fetch this value form the request object in the view:
interface = request.POST.get('interface')
A full example:
models.py
class Device(models.Model):
name = models.CharField(max_length=100)
class Interface(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100, default='interface description field')
status = models.BooleanField(default=False)
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name='interfaces')
views.py
from django.core.exceptions import ObjectDoesNotExist
def list_interfaces(request):
devices = Device.objects.all()
interfaces = None
try:
selected_device = Device.objects.get(id=request.POST.get('dv'))
interfaces = selected_device.interfaces.all()
except ObjectDoesNotExist:
selected_device = Device.objects.all().first()
if selected_device:
interfaces = selected_device.interfaces.all()
else:
selected_device = None
context = {
'devices': devices,
'selected_device': selected_device,
'interfaces': interfaces
}
return render(request, 'list_device_interfaces.html', context)
def send_description(request):
command = request.POST.get('command')
device = request.POST.get('seleted_device')
interface = request.POST.get('interface')
print(f'command: {command}')
print(f'device_id: {device}')
print(f'device_id: {interface}')
return redirect('core:list-device-interfaces')
urls.py
from core import views
from django.urls import path
app_name = 'core'
urlpatterns = [
path("list/device/interfaces/" , views.list_interfaces, name="list-device-interfaces"),
path("send/description/" , views.send_description, name="send-description"),
]
list_device_interfaces.html
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="{% url 'core:list-device-interfaces' %}" method="POST" class="card card-body">
{% csrf_token %}
<h1>Device</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devices %}
<option value="{{ device.id }}" {% if device.id == selected_device.id %} selected {% endif %}>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
<hr>
<h2>Interfaces</h2>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.name}}</h2>
{% if interface.description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.description}}</P>
{% endif %}
<form action= "{% url 'core:send-description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<input type="hidden" name="seleted_device" value="{{ selected_device.id }}">
<input type="hidden" name="interface" value="{{ interface.id }}">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.status %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}
So, what I am using it for is to render a template that I have.
Here is the code it has a problem with.
`
#views.route('/')
def home():
return render_template("home.html")
`
By the way this is the code in home.html
{% extends "base.html" %} {% block title %}Home{% endblock %} {% block content
%}
<h1 align="center">Notes</h1>
<ul class="list-group list-group-flush" id="notes">
{% for note in user.notes %}
<li class="list-group-item">
{{ note.data }}
<button type="button" class="close" onClick="deleteNote({note,id })"
<span aria-hidden="true">×</span>
</button>
</li>
{% endfor %}
</ul>
<form method="POST">
<textarea name="note" id="note" class="form-control"></textarea>
<br />
<div align="center">
<button type="submit" class="btn btn-primary">Add Note</button>
</div>
</form>
{% endblock %}
I run it. It gives me a link to website. Everything there, No. I run it. It gives me a link to website. And then jinja2.exceptions.UndefinedError: 'user' is undefined is on my website
Check your html file, you may accidently got a variable called user in there
I'm trying to add flags to my dropdown for i18n, so far I've tried adding an img tag and using as background image but none of them seem to work
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
{% get_current_language as LANGUAGE_CODE %}
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ redirect_to }}">
<select name="language" id="" class="icon-menu">
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{language.code}}"
{% if language.code == LANGUAGE_CODE %} selected {% endif %}
{% if language.code == "en-gb" %}
style="background-image:url(/static/img/en-gb.png);" alt="english">english
{% elif language.code == "pt-br" %}
>portugues<img src="/static/img/pt-br.png" alt="">
{% else %}
{{ language.name_local }}
{% endif %}
</option>
{% endfor %}
</select>
<input type="submit" value="{% trans 'Go' %}">
</form>
</li>
you should consider using a 3rd javascript library like select2 (https://select2.org/).
To learn more why refer to this doc from Mozilla (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#Styling_with_CSS) :
The element's internal structure is complex, and hard to control. If you want to get full control, you should consider using a library with good facilities for styling form widgets, or try rolling your own dropdown menu using non-semantic elements, JavaScript, and WAI-ARIA to provide semantics.
I'm using Django-filters to filter results. The filter is working correctly, but now the pagination is not working. It's being rendered, but now all the products are being displayed in one page. I was using paginate_by = 6 as it is a class based view. Even after filtering results, for example there are 8 products matching the filter, everything is being displayed in one single page. Why is it not working? Can anyone please help me out? Thanks in advance!
My filters.py:
import django_filters
from .models import Item
class ItemFilter(django_filters.FilterSet):
class Meta:
model = Item
fields = {
'category': ['exact'],
'price': ['lte']
}
My views.py:
from .filters import ItemFilter
class homeview(ListView):
model = Item
template_name = 'products/home.html'
paginate_by = 6
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = ItemFilter(self.request.GET, queryset=self.get_queryset())
return context
My index.html:
<div class="card mb-4">
<div class="card-body">
<div class="container">
<form method="GET">
{{ filter.form|crispy }}
<button type="submit" class="btn btn-primary mt-4">Filter</button>
</form>
</div>
</div>
</div>
<h1>List Of Items</h1>
<div class="row mb-4">
{% for item in filter.qs %}
<div class="col-lg-4">
<img class="thumbnail" src="{{ item.image_url }}">
<div class="box-element product">
<h6><strong>{{ item.title }}</strong></h6>
<h6 class="text-success">Category - {{ item.get_category_display }}</h6>
<hr>
</div>
</div>
{% endfor %}
</div>
<ul class="pagination justify-content-center">
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-dark mb-4" href="?page=1">First</a>
<a class="btn btn-outline-dark mb-4" href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-dark mb-4" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-dark mb-4" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-dark mb-4" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-dark mb-4" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
</ul>
First of all You're not using page object created by django's ListView methods. Technically you pass a new queryset instead. Therefore you're listing all the results instead of paginated results.
super().context already has a page object which is not used here. since you use ItemFilter
Here's how I'd handle the situation. without django_filters though
forms.py
class FilterForm(forms.Form):
category = forms.CharField()
price = forms.IntegerField()
views.py
from .forms.py import FilterForm
class HomeView(ListView):
model = Item
template_name = 'products/home.html'
paginate_by = 6
def get_filter_args(self):
request = self.request
filter_args = {}
filter_args['category'] = request.GET.get('category')
filter_args['price__lte'] = request.GET.get('price')
# To remove filter arg if the value is null. to avoid errors
filter_args = {key: value for key, value in filter_args.items() if value}
return filter_args
def get_queryset(self):
filter_args = self.get_filter_args()
queryset = super().get_queryset().filter(**filter_args)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = FilterForm()
return context
In order to prevent the applied filters from losing on pagination, use a helper to build url for pagination add this file in a templatetags folder inside the app folder (same path where views.py, models.py etc...)
temptag.py
register = template.Library()
#register.simple_tag
def paginate_url(field_name, value, urlencode=None):
get_query = f'{field_name}={value}'
if urlencode:
qs = urlencode.split('&')
_filtered = filter(lambda p: p.split('=')[0] != field_name, qs)
querystring = '&'.join(_filtered)
get_query = f'{get_query}&{querystring}'
return get_query
you can import the template helper inside html file
html file
{% load temptag %}
<div class="card mb-4">
<div class="card-body">
<div class="container">
<form method="GET">
{{ form|crispy }}
<button type="submit" class="btn btn-primary mt-4">Filter</button>
</form>
</div>
</div>
</div>
<h1>List Of Items</h1>
<div class="row mb-4">
{% for item in object_list %}
<div class="col-lg-4">
<img class="thumbnail" src="{{ item.image_url }}">
<div class="box-element product">
<h6><strong>{{ item.title }}</strong></h6>
<h6 class="text-success">Category - {{ item.get_category_display }}</h6>
<hr>
</div>
</div>
{% endfor %}
</div>
<ul class="pagination justify-content-center">
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-dark mb-4" href="?{% paginate_url 'page' 1 request.GET.urlencode %}">First</a>
<a class="btn btn-outline-dark mb-4" href="?{% paginate_url 'page' page_obj.previous_page_number request.GET.urlencode %}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-dark mb-4" href="?{% paginate_url 'page' num request.GET.urlencode %}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-dark mb-4" href="?{% paginate_url 'page' num request.GET.urlencode %}"</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-dark mb-4" href="?{% paginate_url 'page' page_obj.next_page_number request.GET.urlencode %}">Next</a>
<a class="btn btn-outline-dark mb-4" href="?{% paginate_url 'page' page_obj.paginator.num_pages request.GET.urlencode %}">Last</a>
{% endif %}
{% endif %}
</ul>
Write your get_context_data() like that
def get_context_data(self, **kwargs):
items = Item.objects.all()
context = super().get_context_data(**kwargs)
context['filter'] = ItemFilter(self.request.GET, queryset=items)
return context
I had a similar problem when using django-filter. However, my solution was using List.js, as I had a table that I not only want paginated, but I wanted the table headers to be sortable.
You can probably use List.js here, even though you don't have a list or table of data (you can also check out some example codepens by the creator of List.js).
index.html:
<h1>List Of Items</h1>
<div id="paginate-items"> <!-- Need a container with a unique ID for List.js -->
<div class="row mb-4 list"> <!-- Must include the class "list" for the div containing the data to be paginated -->
{% for item in filter.qs %}
<div class="col-lg-4">
<img class="thumbnail" src="{{ item.image_url }}">
<div class="box-element product">
<h6><strong>{{ item.title }}</strong></h6>
<h6 class="text-success">Category - {{ item.get_category_display }}</h6>
<hr>
</div>
</div>
{% endfor %}
</div>
<ul class="pagination"></ul>
</div>
...
<!-- You'll need to include jQuery and List.js just before the close of the '<body>' tag: -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
Then, in a separate .js file:
var myData= new List('paginate-items', {
page: 3, // refers to how many items per page
pagination: true
});
And some simple styling in a separate .css file:
.pagination li {
display:inline-block;
padding:5px;
}
I have the following html that the button does a normal Save:
<form action="" method="post">
<input type="hidden" value="{{ people }}" name="people">
<input type="hidden" value="{{ number }}" name="number">
<p>{% trans 'Are you sure you want to save people' %} {{ people }} {% trans 'where number is' %} {{ number }}?
</p>
{% buttons %}
<button class="btn btn-default hover-linea" id="cancel" type="button">
{% bootstrap_icon "remove" %} {% trans 'Cancel' %}
</button>
<button type="submit" class="btn btn-default hover-linea">
{% bootstrap_icon "log-out" %} {% trans 'Save' %}
</button>
{% endbuttons %}
What I need when I do the Save, is to reload the previous page to the form. I want to press Save and do the same as now, but also make a location.reload() of a page whose relative link is (../people.html).
I await an answer, thank you very much.
Your server-side form handler (which you have specified the URL to in your action) attribute should respond with an HTTP redirect (status 302 and the Location: header) to the URL you want the browser to load.