How to change the contents of a block dynamically on django? - javascript

SEE FIXED CODE BELOW
I'm working on my first web page project using django 1.8. My web page has a section that consists of a product menu and a column displaying a different view based on selected menu item.
At first I tried an approach where each of the menu buttons have a onclick js function assigned that changes the contents of the block. I was thinking that I would then write the html code of each product into separate file where it would be read by the js function. I got it partially working but it feels kinda sketchy.
My second approach was based on using django templates but I run into some errors as a beginner I couldn't quite figure out what exactly is the problem. I would highly appreciate if someone could pinpoint what I'm doing wrong or tell me what's the right approach for changing the contents dynamically.
The errors I'm getting currently:
http://127.0.0.1:8000/productmonitor/
NoReverseMatch at /productmonitor/
Reverse for 'product' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'productmonitor/(?P<product_name>[a-z]+)/$']
http://127.0.0.1:8000/productmonitor/
NoReverseMatch at /productmonitor/dualpol/
Reverse for 'product' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'productmonitor/(?P<product_name>[a-z]+)/$']
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<product_name>[A-Za-z0-9\-\_]+)/$', views.product, name='product'),
url(r'^information/$', views.information, name='information'),
url(r'^casedatabase/$', views.casedatabase, name='casedatabase'),
url(r'^contact/$', views.contact, name='contact'),
]
views.py
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from django.views import generic
# Create your views here.
from .models import Product
def index(request, product_name='default'):
#template = 'productmonitor/index.html'
if product_name == 'dualpol':
template = 'productmonitor/base_productmonitor_dualpol.html'
if product_name == 'rhi':
template = 'productmonitor/base_productmonitor_rhi.html'
template = 'productmonitor/base_productmonitor.html'
test_context = {
'products' : Product.objects.all(),
}
return render(request, template, test_context)
def product(request, product_name='dualpol'):
if product_name == 'dualpol':
template = 'productmonitor/base_productmonitor_dualpol.html'
if product_name == 'rhi':
template = 'productmonitor/base_productmonitor_rhi.html'
test_context = {
'products' : Product.objects.all(),
}
return render(request, template, test_context)
base_productmonitor.html
{% extends "productmonitor/base.html" %}
{% block content %}
<div class="productSelectMenu">
<ul>
<p>Test</p>
{% for product in products %}
<li><a href="{% url 'productmonitor:product' 'dualpol' %}">{{ product.name }}<a/></li>
{% endfor %}
</ul>
</div>
{% block productcontent %}
<div id="productView" class="productView">
<p>Default productView content</p>
</div>
{% endblock %}
{% endblock %}
base_productmonitor_dualpol.html
{% extends "productmonitor/base_productmonitor.html" %}
{% block productcontent %}
<p>
dualpol
</p>
{% endblock %}
EDIT: FIXED VERSION
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^product/(?P<product_name>[a-z]+)/$', views.product, name='product'),
url(r'^information/$', views.information, name='information'),
url(r'^casedatabase/$', views.casedatabase, name='casedatabase'),
url(r'^contact/$', views.contact, name='contact'),
]
views.py
enter code here
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render, redirect
from django.views import generic
# Create your views here.
from .models import Product
def index(request, product_name=''):
return redirect('productmonitor:product', product_name='dualpol')
def product(request, product_name):
if product_name == 'dualpol':
template = 'productmonitor/base_productmonitor_dualpol.html'
if product_name == 'rhi':
template = 'productmonitor/base_productmonitor_rhi.html'
test_context = {
'products' : Product.objects.all(),
}
return render(request, template, test_context)
def information(request):
template = 'productmonitor/base_information.html'
context = {}
return render(request, template, context)
def casedatabase(request):
template = 'productmonitor/base_case-database.html'
context = {}
return render(request, template, context)
def contact(request):
template = 'productmonitor/base_contact.html'
context = {}
return render(request, template, context)
base_productmonitor.html
{% extends "productmonitor/base.html" %}
{% block content %}
<div class="productSelectMenu">
<ul>
<li><a href="{% url 'productmonitor:product' 'dualpol' %}">Dual pol<a/></li>
<li><a href="{% url 'productmonitor:product' 'rhi' %}">Rhi<a/></li>
</ul>
</div>
{% block productcontent %}
<div id="productView" class="productView">
<p>Default productView content</p>
</div>
{% endblock %}
{% endblock %}
base_productmonitor_dualpol.html
{% extends "productmonitor/base_productmonitor.html" %}
{% block productcontent %}
<div id="productView" class="productView">
<p>
dualpol
</p>
</div>
{% endblock %}

I think what the error is saying that the render in your product function is not getting the right <product_name> to use. It's showing that the arguments that it has (the <product_name> that it is trying) are none. So what you have to do in your product function is to try and make sure that you are really getting a <product_name>.

Related

Image is not showing on my html page, using but only a link (path to image)

I have created an HTML(dashboard.html) page containing a div to display newly registered users' names, registration dates, and the user's pictures.
div shows user names, and registration dates, but not the user's picture. Here is just a link to the image:
Here are the files and their contents:
podcast_user.models.py:
class PodcastUser(AbstractUser):
user_id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
username = models.CharField(max_length=30,unique=True)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',message="Phone number must be in the format: '+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True, null=True, unique=True, default='+')
date_of_birth = models.DateField(blank=True, null=True)
date_of_join = models.DateField(blank=True, null=True,default=date.today)
address = models.CharField(max_length=100,blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE,blank=True, null=True)
image = models.ImageField(upload_to='user_images/', blank=True, null=True)
city_name = models.CharField(max_length=30, blank=True, null=True)
postal_code = models.CharField(max_length=10,blank=True, null=True)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
email = models.EmailField(max_length=30,
validators=[RegexValidator(regex="^[a-zA-Z0-9_.+-]+#[a-zA-Z0-9-]+\.["r"a-zA-Z0-9-.]+$",
message='please enter the correct format')],unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name','username']
def create_superuser(self, email, password, **extra_fields):
if self.filter(is_superuser=True).exists():
raise ValueError('Superuser already exists')
# set some default values for the superuser
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
# create the superuser with the provided email and password
return self._create_user(email=email, password=password, **extra_fields)
def __str__(self):
return f"{self.username} ({self.user_id})"
podcast_user.views.py:
def PodcastDashboard(request):
thirty_days_ago = datetime.now() - timedelta(days=30)
new_users = PodcastUser.objects.filter(date_of_join__gte=thirty_days_ago)
return render(request, 'pages/podcast_dashboard.html', {'new_users': new_users})
podcast_user.urls.py:
from django.urls import re_path,path
from .views import login_and_register,PodcastDashboard,logout_view,confirm_user_request
urlpatterns = [
re_path(r'^login_and_register/', login_and_register, name='login_and_register'),
re_path(r'^podcast_dashboard/', PodcastDashboard, name='podcast_dashboard'),
re_path(r'^logout/', logout_view, name='logout'),
path('confirm_user_request/<int:user_id>/', confirm_user_request, name='confirm_user_request'),
]
podcast.urls.py:
from django.contrib import admin
from django.urls import include, re_path,path
from django.views.generic import TemplateView
from django.conf.urls.static import static
from podcast.settings.base import MEDIA_URL, MEDIA_ROOT
urlpatterns = [
re_path(r'^admin', admin.site.urls),
re_path(r"^user/", include('podcast_user.urls')),
re_path(r"^", TemplateView.as_view(template_name="pages/home.html"), name="home"),
]+ static(MEDIA_URL, document_root=MEDIA_ROOT)
podcast_dashboard.html:
{% load static %}
{% if user.is_authenticated %}
{% block content %}
<div class="card-body p-0">
<h1>New Registered Users</h1>
<ul class="users-list clearfix">
{% for user in new_users %}
<li>
{% if user.image %}
<img src="{{ user.image.url }}" >
{% endif %}
<a class="users-list-name" href="#">{{ user.first_name }} {{ user.last_name }}</a>
<span class="users-list-date"> {{ user.date_of_join|date:"M d, Y" }}</span>
</li>
{% empty %}
<li>No new registered users.</li>
{% endfor %}
</ul>
</div>
{% endblock %}
{% endif %}
Here is finale result:
stractur:
podcast
|
├── podcast_user
|
└── templates_static_media
├── media
| └── user_images
| ├── default.jpg
| ├── dream_TradingCard.jpg
| ├── dream_TradingCard_1.jpg
| ├── Podcast-ddddd.png
|
├── static
└── templates
└── pages
├── podcast_dashboard.html
└── test.htm
and settings.py:
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
APPS_DIR = os.path.join(ROOT_DIR, "templates_static_media/")
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_URL = "static/"
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
STATICFILES_DIRS = (os.path.join(APPS_DIR, "static/"),)
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
MEDIA_ROOT = os.path.join(APPS_DIR, "/media/")
MEDIA_URL = "/media/"
when I use path in URLs, it is working fine, but when I change path to re_path image will not display.

'NoneType' object is not iterable problem solving

I want to show a list of question on my quiz.html templates... Here is my models.py
from django.db import models
# Create your models here.
DIFF_CHOICE = (
('easy','easy'),
('medium','medium'),
('hard','hard'),
)
class Quiz(models.Model):
name = models.CharField(max_length=120)
topic = models.CharField(max_length=120)
number_of_question = models.IntegerField()
time = models.IntegerField(help_text="Duration in Minutes")
required_score_to_pass = models.IntegerField(help_text="Required Score to Pass in %")
difficulty = models.CharField(max_length=6,choices=DIFF_CHOICE)
def __str__(self):
return f"{self.name}-{self.topic}"
def get_questions(self):
self.question_set.all()[:self.number_of_question]
class Meta:
verbose_name_plural = 'Quizes'
Here is my views.py
def quiz_data_view(request,pk):
quiz = Quiz.objects.get(pk=pk)
questions = []
for q in quiz.get_questions():
answers = []
for a in q.get_answers():
answers.append(a.text)
questions.append({str(q):answers})
return JsonResponse({
'data' : questions,
'time' : quiz.time,
})
and here is my quiz.html....and here i want to show my question list
{% extends "base.html" %}
{% load static %}
{% block scripts %}
<script src="{% static 'quizes/quiz.js' %}" defer></script>
{% endblock scripts %}
{% block title %}
{{obj.name}}
{% endblock title %}
{% block content %}
{{obj.name}}
<hr>
<form id ="quiz-form" class="mt-3 mb-3">
{% csrf_token %}
<div id="quiz-box"></div>
<button type="submit" class="btn btn-primary mt-3">Save
</button>
</form>
{% endblock content %}
Here is my js file...in my js file i used ajax...
const url = window.location.href
const quizBox = document.getElementById('quiz-box')
let data
$.ajax({
type: 'GET',
url: `${url}data`,
success : function(response){
// console.log(response)
data = response.data
data.forEach(el=>{
for(const [question,answers] of Object.entries(el)){
quizBox.innerHTML +=`
<hr>
<div class="mb-2">
<b> ${question}</b>
</div>
`
}
});
},
error : function(error){
console.log(error)
}
})
here is my urls.py
from django.urls import path
from .views import (
QuizListView,quiz_view,quiz_data_view
)
app_name='quizes'
urlpatterns = [
path('',QuizListView.as_view(),name='main-view'),
path('<int:pk>/',quiz_view,name='quiz-view'),
path('<int:pk>/data/',quiz_data_view,name='quiz-data-view'),
]
But I don't get my question list in the template
IT shows=> 'NoneType' object is not iterable

Not Found: /1/${url}data

I want to show a list of question on my quiz.html templates...
Here is my views.py
def quiz_data_view(request,pk):
quiz = Quiz.objects.get(pk=pk)
questions = []
for q in quiz.get_questions():
answers = []
for a in q.get_answers():
answers.append(a.text)
questions.append({str(q):answers})
return JsonResponse({
'data' : questions,
'time' : quiz.time,
})
Here is my js file...in my js file i used ajax...
const url = window.location.href
const quizBox = document.getElementById('quiz-box')
let data
$.ajax({
type: 'GET',
url: "${url}data",
success : function(response){
// console.log(response)
data = response.data
data.forEach(el=>{
for(const [question,answers] of Object.entries(el)){
quizBox.innerHTML +=`
<hr>
<div class="mb-2">
<b> ${question}</b>
</div>
`
}
});
},
error : function(error){
console.log(error)
}
})
here is my urls.py
from django.urls import path
from .views import (
QuizListView,quiz_view,quiz_data_view
)
app_name='quizes'
urlpatterns = [
path('',QuizListView.as_view(),name='main-view'),
path('<int:pk>/',quiz_view,name='quiz-view'),
path('<int:pk>/data/',quiz_data_view,name='quiz-data-view'),
]
Here is my models.py
from django.db import models
# Create your models here.
DIFF_CHOICE = (
('easy','easy'),
('medium','medium'),
('hard','hard'),
)
class Quiz(models.Model):
name = models.CharField(max_length=120)
topic = models.CharField(max_length=120)
number_of_question = models.IntegerField()
time = models.IntegerField(help_text="Duration in Minutes")
required_score_to_pass = models.IntegerField(help_text="Required Score to Pass in %")
difficulty = models.CharField(max_length=6,choices=DIFF_CHOICE)
def __str__(self):
return f"{self.name}-{self.topic}"
def get_questions(self):
self.question_set.all()[:self.number_of_question]
class Meta:
verbose_name_plural = 'Quizes'
and here is my quiz.html....and here i want to show my question list
{% extends "base.html" %}
{% load static %}
{% block scripts %}
<script src="{% static 'quizes/quiz.js' %}" defer></script>
{% endblock scripts %}
{% block title %}
{{obj.name}}
{% endblock title %}
{% block content %}
{{obj.name}}
<hr>
<form id ="quiz-form" class="mt-3 mb-3">
{% csrf_token %}
<div id="quiz-box"></div>
<button type="submit" class="btn btn-primary mt-3">Save
</button>
</form>
{% endblock content %}
But I don't get my question list in the template
IT Shows this error Not Found: /1/${url}data

NoReverseMatch from url tag inside include tag

I am trying to render a link inside an include html template with the url tag.
I have done this before and usually it works, but for some reason this time I can't make it.
I get a NoReverseMatch Error and suspect its because Django tries to load the url tag first but my object isn't ready, so the pk is empty. I believe that because it takes a moment until the dynamic data loads, while the static is already loaded.
The url works if I set pk to a fixed number, but I would like it to change dynamically.
Error:
Reverse for 'transaction' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['en/budget/account\\/(?P<pk>[0-9]+)\\/$']
Relevant urls:
from django.urls import path
from django.contrib import admin
from django.contrib.auth import views as auth_views
from . import views
app_name='budgetapp'
urlpatterns = [
path('', views.index, name='index'),
path('account/<int:pk>/', views.transaction, name='transaction'),
path('account/', views.account, name='account'),
]
Relevant views:
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.models import Group
from django.contrib.auth.decorators import login_required, user_passes_test
from .models import *
from .forms import *
def index(request):
context = {}
context['accounts'] = Account.objects.filter(author=request.user)
return render(request, 'budgetapp/index.html', context)
def account(request):
context = {}
context['account'] = get_object_or_404(Account, pk = request.POST['accountPk'])
return render(request, 'budgetapp/account.html', context)
def transaction(request, pk):
context = {}
context['account'] = get_object_or_404(Account, pk = pk)
return render(request, 'budgetapp/addTransaction.html', context)
index.html:
{% csrf_token %}
<h1>Personal Budget</h1>
<br />
<p>
<label for="accountSelector">Account:</label>
<select required = "" id="accountSelector">
{% for account in accounts %}
<option value="{{account.pk}}">{{account}}</option>
{% endfor %}
</select>
</p>
<hr />
{% include 'budgetapp/account.html' %}
<script>
$(document).ready(function () {
reload();
});
$("#accountSelector").change(function () {
reload();
});
function reload() {
var dictionary = {}
dictionary['csrfmiddlewaretoken'] = $('input[name="csrfmiddlewaretoken"]').val();
dictionary['accountPk'] = $('#accountSelector').val();
$('#accountDiv').load("account/", dictionary);
console.log('Changed account');
}
</script>
account.html:
<div id="accountDiv">
<p>
Name: {{account.name}} Account balance: {{account.balance}} Add a transaction
</p>
</div>
If I change {% url 'budgetapp:transaction' pk=account.pk %} to /budget/account/{{account.pk}} it works, but that feels wrong.
I tried to provide all necessary code, but please let me know if it is to much or something is missing.
If you want to use {% url 'budgetapp:transaction' pk=account.pk %} then account must be in the template context. This has nothing to do with your browser dynamically loading data. The entire template is rendered by the server before the response is sent to the browser.
Using /budget/account/{{account.pk}} won't give an error, but if you look at the rendered HTML you'll see /budget/account/ since {{ account.pk }} will evaluate as ''.

How to pass JavaScript variables to React component

I'm somewhat new to React and I'm having some trouble passing some variables from my Django server to my React components. Here's what I have:
The server is Django, and I have a url mydomain.com/testview/ that gets mapped to a views.py function testview:
def testview(request):
now = datetime.datetime.now()
return render(request, 'testview.html', {
'foo': '%s' % str(now),
'myVar': 'someString'
})
In other words, running testview will render the template file testview.html and will use the variables foo and myVar.
The file testview.html inherits from base.html which looks like this:
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
</head>
<body>
{% block main %}{% endblock %}
</body>
</html>
The file test.html basically inserts the needed code into block main:
testview.html:
{% extends "base.html" %}
{% load render_bundle from webpack_loader %}
{% block main %}
<script type="text/javascript">
var foo = {{ foo }};
var myVar = {{ myVar }};
</script>
<div id="App"></div>
{% render_bundle 'vendors' %}
{% render_bundle 'App' %}
{% endblock %}
Note that just before the div id="App", I created a couple of javascript variables foo and myVar and set them to the values from Django.
Now to REACT: my file App.jsx looks like this:
import React from "react"
import { render } from "react-dom"
import AppContainer from "./containers/AppContainer"
class App extends React.Component {
render() {
return (
<AppContainer foo={props.foo} myVar={props.myVar}/>
)
}
}
render(<App foo={window.foo} myVar={window.myVar}/>, document.getElementById('App'))
In other words, my App.jsx file renders the App component, passing in foo and myVar. Inside class App, I assumed these were props so I pass these to AppContainer using props.foo and props.myVar. My class AppContainer is inside a components folder and looks like this:
import React from "react"
import Headline from "../components/Headline"
export default class AppContainer extends React.Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-sm-12">
<Headline>Running App! foo is {props.foo}, Here is a string: {props.myVar}</Headline>
</div>
</div>
</div>
)
}
}
However, none of this seems to work. I just get a blank page. What am I doing wrong?
if foo and myVar is string you should declare
var foo = "{{ foo }}";
var myVar = "{{ myVar }}";
So this is what I needed to do to get it to work. First, I used Giang Le's answer above and in my testview.html file (a Django template file), I put quotes around the variables as they were indeed strings. Next, I changed the render statement in my App.jsx file to be this:
render(<App foo={foo} myVar={myVar}/>, document.getElementById('App'))
This used Bruno Vodola Martins' answer to access foo and myVar as javascript globals. I also had to use this.props.foo instead of props.foo in my App class:
class App extends React.Component {
render() {
return (
<AppContainer foo={this.props.foo} myVar={this.props.myVar}/>
)
}
}
And I did the same thing in containers/AppContainer.jsx:
export default class AppContainer extends React.Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-sm-12">
<Headline>App! foo is {this.props.foo}, Here is a string: {this.props.myVar}</Headline>
</div>
</div>
</div>
)
}
}
Bottom line: put quotes around string variables from Django, and use this.props.foo instead of just props.foo.

Categories