Do not print media from django form - javascript

I created a custom widget and included a Media class.
class MyWidget(forms.MultiWidget):
class Media:
css = {
'all': ('path-to-css.css',),
}
js = (
'path-to-js.js',
)
def __init__(self, visible_input_attrs=None, hidden_input_attrs=None):
widgets = (
TextInput(attrs=visible_input_attrs),
HiddenInput(attrs=hidden_input_attrs),
)
super(MyWidget, self).__init__(widgets)
def decompress(self, value):
if value:
return ['', value]
return [None, None]
In my form I use this widget as follows
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'phone_number',
]
widgets = {
'phone_number': MyWidget(),
}
My template file
{% extends "base.html" %}
{% load static i18n crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<form id="my-form" action="" method="post" enctype="multipart/form-data">
<h2>Contact details</h2>
{% crispy user_form %}
</form>
</div>
</div>
{% endblock content %}
{% block javascript %}
{{ block.super }}
{{ user_form.media.js }}
{% endblock %}
In my template file I include the form with {% crispy user_form %} (using crispy forms). Django hereby automatically adds the CSS and JS files at the beginning of the form. Since I load JS files at the very end of every HTML page and since the included path-to-js.js file requires jQuery, I append {{ user_form.media.js }} to my javascript block in my template. As a consequence, path-to-js.js appears more than once on my page and leads to error messages because the first time path-to-js.js is loaded, jQuery is not loaded yet.
How can I avoid to load the JS files when I use {% crispy user_form %}?

Set include_media = False in your helper class.
class UserForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.include_media = False

Related

How can i array to grid table in Django HTML?

I can send my model to the html page and bring it to the array structure, but I cannot integrate this array into the grid table. Does anyone know how I can do this?
views.py
def tests(request):
resultQueryet = ResultsModel.objects.all()
requests = serialize('json', resultQueryet)
context = {
"requests" : requests
}
return render(request, 'admin/tests.html', context=context)
html
{% block content %}
<div class="card-body">
<div id="table-card" class="table-card"></div>
</div>
{% endblock %}
{% block extra_js %}
<script>
var model = {{requests|safe}};
console.log(model)
document.getElementById("table-card") &&
new gridjs.Grid({
columns: ["Name", "Surname", "Date", "Amount", "Result", "Details"],
sort: !0,
pagination: { limit: 5 },
data: [
[
{% for x in model %}
{{x.name}},
{{x.surname}},
{{x.date}},
{{x.amount}},
{{x.result}},
{{x.details}},
{% endfor %}
],
],
}).render(document.getElementById("table-card"))
</script>
<script src="{% static 'libs/prismjs/prism.js'%}"></script>
<script src="{% static 'libs/gridjs/dist/gridjs.umd.js'%}"></script>
<script src="{% static 'js/pages/gridjs.init.js'%}"></script>
{% endblock extra_js %}
I can view the model as array on the console screen, but I cannot print it to the table via a for loop.

JavaScript: unable to disable/enable an input button

I'm building a web app using the Django framework. I'm attempting to use some JavaScript to disable a button that users can press to submit a text-based review.
The JavaScript in the listing.js file looks as follows:
document.addEventListener('DOMContentLoaded', function () {
hide_submit_review_button();
});
// Hide the 'Submit Review'button until the user begins typing a review
// Prevent the user from typing more than 100 characters
function hide_submit_review_button() {
var submit_review_button = document.getElementById('submit-review-button');
if (submit_review_button !== null) {
document.getElementById('submit-review-button').disabled = true;
document.getElementById('review-contents').onkeyup = () => {
if ((document.getElementById('review-contents').value.length > 0 &&
document.getElementById('review-contents').value.length <= 100 )) {
document.getElementById('submit-review-button').disabled = false;
} else {
document.getElementById('submit-review-button').disabled = true;
}
};
}
}
In my listing.html file, I identify the review-contents and submit-review-button. Here's the code:
{% extends "layout.html" %}
{% load static %}
{% block body %}
{% if user.is_authenticated %}
<form action="{% url 'review' listing.id %}" method="POST">
{% csrf_token %}
<input type="text" class="form-control" name="review" id="review-contents" placeholder="Write a review...">
<input class="btn btn-primary mt-1" type="submit" id="submit-review-button" value="Submit Review">
</form>
{% endif %}
{% endblock %}
{% block script %}
{% if user.is_authenticated %}
{{ block.super }}
<script src="{% static 'listing.js' %}"></script>
{% endif %}
{% endblock %}
An example of a page where the button appears is: http://127.0.0.1:8000/listings/7
And, here is what the urls.py file looks like (if it matters):
urlpatterns = [
path('', views.index, name='index'),
path('listings/<int:listing_id>', views.listing, name='listing'),
]
Can anyone see why this button doesn't disable?
Thanks!
The problem resulted from not having the following in the header tag in the layout.html file:
{% block script %}
{% endblock %}

How can you change Django loop body using javascript?

i was wondering if there is a way i can change the body of for loop in django using javascript each time i press a button.
in my case i want to display matches this week and when i press next i want to change the list using javascript and then pass it django template in the regroup part, i want to change the matches list.
i know how to write the code to make the new list and the previous and next buttons using javascript but i don't know how to pass it to django template
or maybe another way could be to write django code in javascript, anyone can help with either way?
in views.py , matches return a list of dictionaries from today to 6 days later
def home(request):
start = datetime.now().date()
end = today + timedelta(6)
matches = request_games(today, after_week)
return render(request, "sporty/home.html",{
"matches": matches,
"start" : start,
"end": end
})
in home.html
{% extends "sporty/layout.html" %}
{% load static %}
{% block body %}
<div class="box">
{{start}},{{end}}
{% regroup matches by date as date_list %}
{% for date in date_list %}
<div class="the_date">
{{date.grouper}}
</div>
{% for match in date.list %}
<div class="match_container">
<div class="status">
{% if match.status_code == 1%}
{{match.minute}}'
{% elif match.status_code == 11%}
HT
{% elif match.status_code == 3 %}
Finished
{% endif %}
</div>
<div class="match">
<div class="home">
{{match.home_name}} <img src="{{match.home_logo}}">
</div>
<div class="score">
{% if match.status_code == 0 %}
{{match.time}}
{% elif match.status_code == 17 %}
TBD
{% elif match.status_code == 1%}
{{match.home_score}} : {{match.away_score}}
{% elif match.staus_code == 11%}
{{match.home_score}} : {{match.away_score}}
{% elif match.status_code == 3 %}
{{match.home_score}} : {{match.away_score}}
{% endif %}
</div>
<div class="away">
<img src="{{match.away_logo}}">
{{match.away_name}}
</div>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}
def request_games(start, end):
params = (
("season_id","1511"),
("date_from",start.strftime("%Y-%m-%d")),
("date_to",end.strftime("%Y-%m-%d"))
);
headers = {
"apikey": //my api key
}
response = requests.get('https://app.sportdataapi.com/api/v1/soccer/matches', headers=headers, params=params)
r = response.json()
data = r["data"]
number = len(data)
matches = []
for i in range(number):
match = {}
match['status'] = data[i]["status"]
match['status_code'] = data[i]["status_code"]
match['minute'] = data[i]['minute']
full_date = data[i]["match_start"]
dt = datetime.strptime(full_date, '%Y-%m-%d %H:%M:%S')
match['date'] = dt.date()
match['time'] = dt.time()
match['start'] = full_date
home_team = data[i]["home_team"]
match['home_name'] = home_team['name']
match['home_logo'] = home_team['logo']
away_team = data[i]["away_team"]
match['away_name'] = away_team['name']
match['away_logo'] = away_team['logo']
stats = data[i]['stats']
match['home_score'] = stats['home_score']
match['away_score'] = stats['away_score']
matches.append(match)
matches.sort(key = lambda x: datetime.strptime(x['start'], '%Y-%m-%d %H:%M:%S'))
return matches
First thing first, once you decide to start working on pages that do not refresh but still query the server and change, one of your solutions is to start using AJAX calls to query the server for different data.
This would add a bit of code to your project.
For example, your home.html template will need to be split into two. Make sure to also add jQuery to your head.
sporty/home.html
{% extends "sporty/layout.html" %}
{% load static %}
{% block body %}
<div id="matchweek" class="box">
{% include "sporty/matchweek.html" %}
</div>
<button type="button" value="p" onclick="weekControl(this)">Previous</button>
<button type="button" value="n" onclick="weekControl(this)">Next</button>
{% comment %}
Either place weekupdate.js in /static/ or give the path within static,
best would be to have a folder for javascript in static and use 'js/weekupdate.js'
{% endcomment %}
<script src="{% static 'js/weekupdate.js' %}"></script>
{% endblock %}
and sporty/matchweek.html
{{start}},{{end}}
{% regroup matches by date as date_list %}
{% for date in date_list %}
<div class="the_date">
{{date.grouper}}
</div>
{% for match in date.list %}
<div class="match_container">
<div class="status">
{% if match.status_code == 1%}
{{match.minute}}'
{% elif match.status_code == 11%}
HT
{% elif match.status_code == 3 %}
Finished
{% endif %}
</div>
<div class="match">
<div class="home">
{{match.home_name}} <img src="{{match.home_logo}}">
</div>
<div class="score">
{% if match.status_code == 0 %}
{{match.time}}
{% elif match.status_code == 17 %}
TBD
{% elif match.status_code == 1%}
{{match.home_score}} : {{match.away_score}}
{% elif match.staus_code == 11%}
{{match.home_score}} : {{match.away_score}}
{% elif match.status_code == 3 %}
{{match.home_score}} : {{match.away_score}}
{% endif %}
</div>
<div class="away">
<img src="{{match.away_logo}}">
{{match.away_name}}
</div>
</div>
</div>
{% endfor %}
{% endfor %}
Because you will need to update the entire content of matchweek div every time.
views.py
def home(request):
if request.is_ajax():
template = 'matchweek.html'
direction = request.GET.get('dir')
if direction == 'n':
request.session['weekoffset'] += 1
elif direction == 'p':
request.session['weekoffset'] -= 1
else:
template = 'home.html'
request.session['weekoffset'] = 0
offset = request.session['weekoffset']
start = datetime.now().date() + timedelta(days=7*offset)
end = start + timedelta(days=6)
matches = request_games(start, end)
return render(request, f"sporty/{template}",{
"matches": matches,
"start": start,
"end": end
})
What you see in the function is a check if the request is coming from the AJAX call or not and determination on what to do from there.
/static/js/weekupdate.js
function weekControl(id) {
var value = id.value;
$.ajax({
url: '', // The url suffix that leads to your home function, example: '/home/'
type: "GET", // Http method
data: {'dir': value}, // The data to be sent to the server.
success: function (htmlres) { // What to do on success and response reaching back
$("#matchweek").html(htmlres);
}
});
}
What you see here is the AJAX get call to your django view with the data of 'dir' and its value. When it is returned, jQuery will change the content of the matchweek div with the new content.
I haven't tested this but let me know if this works and if you have any questions.

How do you change an HTML tag with certain conditions?

I'm trying to make an e-commerce site with Django and I'm stuck at my home page not being able to display which products are already in my cart. I am pretty sure I haven't got the JavaScript right but I'm an absolute beginner to web-dev so could also be the Python.
This is my home :
{% extends 'base.html' %}
{% block content %}
{% for pett in pets.all %}
<div class="row pt-3" onfocus="func(pett)">
<div class="col-8" onclick="window.location='{% url 'detail' pett.id %}';" style="cursor: pointer">
<h2>{{ pett.name }}</h2>
<h4>{{ pett.breed }}</h4>
</div>
<div class="col-4">
<a id="link{{pett.id}}" href= "javascript:{document.getElementById('add{{pett.id}}').submit()}"><button id="button{{pett.id}}" class='btn btn-primary btn-xs'><h1>Add to cart +</h1></button></a>
</div>
</div>
<form id="add{{pett.id}}" method="POST" action="{% url 'add_to_cart' pett.id %}">
{% csrf_token %}
<input type="hidden"/>
</form>
{% endfor %}
<script type="text/javascript">
function func(pett){
if(cart.objects.filter(pet=pett).count()>0) {
document.getElementById('button{{pett.id}}').innerHTML = "Added ✔︎";
document.getElementById('link{{pett.id}}').href = "";}
}
</script>
{% endblock %}
This is the call to my home method :
from django.shortcuts import render
def home(request):
pets = Pet.objects
if request.user :
cart = Cart.objects.get(buyer=request.user)
else:
cart=NULL
return render(request,'pets/home.html',{'pets':pets,'cart':cart})
This is my cart model :
from django.db import models
class Cart(models.Model):
buyer = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
pet = models.ManyToManyField('pets.Pet')
Everything else is working perfectly.

NoReverseMatch at /blog/ in django 2.0

am getting this error trying to set a blog category page
NoReverseMatch at /blog/
Reverse for 'category_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['blog\/category\-detail\/(?P[-a-zA-Z0-9_]+)$']
Here is my url.py
from django.urls import path,include
from .import views
urlpatterns = [
path('blog/',views.post_list,name="post_list"),
path('blog/post-detail/<slug:slug>',views.post_detail,name="post_detail"),
path('blog/category-detail/<slug:slug>',views.category_detail,name="category_detail"),
]
views.py
from django.shortcuts import render,get_object_or_404
from.models import Post,Category
# Create your views here.
def post_list(request):
object_list=Post.objects.all()
context={
'object_list': object_list,
}
return render(request,"blog.html",context)
def post_detail(request,slug=None):
post=get_object_or_404(Post,slug=slug)
context={
'post':post,
}
return render(request,"post_detail.html",context)
def category_detail(request,slug=None):
category=get_object_or_404(Category,slug=slug)
post=Post.objects.filter(category=category,status='Published')
context={
'category':category,
'post':post,
}
return render(request,"category_detail.html",context)
blog.html
{% for obj in object_list %}
{% if obj.status == 'Published' %}
<article>
<div class="embed-responsive embed-responsive-16by9">
<img src="images/blog1.jpg" alt="" />
</div>
<div class="post-content">
<h2>{{obj.title}}</h2>
<div>
{{obj.created}} Author {{obj.user}} <h4>{{obj.Category}}</h4>
<hr/>
<p>{{obj.body}}</p>
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' obj.slug %}">Continue reading →</a><br>
</div>
</article>
{% endif %}
{% endfor %}
category_detail.html
{% extends "base.html" %}
{% load static %}
{% block seo_title %}{{category.seo_title}}{% endblock %}
{% block seo_description %}{{category.seo_description}}{% endblock %}
{% block Content %}
<h2>{{category.title}}</h2>
<p>{{category.description}}</p>
{% for item in post %}
{{item.title}}
{{item.body|truncatechars:50}}
{% endfor %}
{% endblock Content %}
NOTE THE OTHER VIEWS.PY ARE WORKING FINE JUST THE category_detail function
As the error said, the argument is missing here. Maybe you need to change {% url 'category_detail' slug=post.Category.slug %} with {% url 'category_detail' slug=obj.category.slug %} because I do not see any post variable reference in the blog.html template.
update
You have not shared your Model codes, but I am assuming your Post Model has Foreign Key to Category Model and it looks like Category=models.ForeignKey(Category). So you need to update the view like this:
def category_detail(request,slug=None):
category=get_object_or_404(Category,slug=slug)
post=Post.objects.filter(Category=category,status='Published')

Categories