I'm trying to learn how to use vuejs in a django project (i'm not using DRF) and I'm having trouble configuring my url to display a detail page view.
So far i have configured urls.py like shown below:
app_name = 'contacts'
urlpatterns = [
path('', views.contacts_all, name='contacts_all'),
path('<int:contact_id>/', views.contact_details, name='contact_details'),
]
Also i have a views.py like shown below:
def contacts_all(request):
# Check if an Ajax Request
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
contacts = list(Contact.objects.values())
return JsonResponse(contacts, safe=False, status=200)
return render(request, 'contacts/all-contacts.html')
def contact_details(request, contact_id):
contact_detail = get_object_or_404(Contact, id=contact_id)
context = {
'contact_detail': contact_detail
}
return render(request, 'contacts/contact-detail.html', context)
Also i successfully getting all contacts from django server:
<script>
const app = new Vue({
delimiters: ['[[', ']]'],
el: '#contact-app',
data: {
contacts: [],
},
methods: {
// Get all contacts from server
async getContacts(){
const response = await axios({
url: 'http://127.0.0.1:8000/contacts/',
method: 'get',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => {
console.log(response.data);
this.contacts = response.data
}).catch(err => {
console.log(err)
});
},
},
async created(){
await this.getContacts();
}
});
</script>
And in template i'm successfully showing all contacts data like shown below:
<div class="flex-row-fluid ml-lg-8 d-block" id="contact-app">
<div class="card card-custom card-stretch">
<div class="card-body table-responsive px-0">
<div
class="list list-hover min-w-500px"
data-inbox="list"
v-if="contacts.length"
>
<div
class="d-flex align-items-start list-item card-spacer-x py-3"
data-inbox="message"
v-for="contact in contacts"
v-bind:key="contact.id"
>
<div class="d-flex align-items-center">
<div class="d-flex align-items-center flex-wrap w-xxl-200px mr-3" data-toggle="view">
<a
href="#"
class="font-weight-bold text-dark-75 text-hover-primary">
[[ contact.name ]]
</a>
</div>
</div>
<div class="flex-grow-1 mt-2 mr-2" data-toggle="view">
<div>
<a href="{% url 'contacts:contact_details' contact.id %}">
<span class="font-weight-bolder font-size-lg mr-2">[[ contact.subject ]] -</span>
<span class="text-muted mr-10">[[ contact.message.substring(0, 100) ]]</span>
</a>
</div>
</div>
<div class="mt-2 mr-3 text-right" data-toggle="view">[[ contact.date_sent| fromNow ]]</div>
</div>
</div>
<div v-else>
<center>
<span>{% trans 'No contacts' %}</span>
<center>
</div>
</div>
</div>
</div>
I have configured url to get details page but i got an error in getting detail page Reverse for 'contact_details' with arguments '('',)' not found. 1 pattern(s) tried: ['contacts/(?P<contact_id>[0-9]+)/\Z']
<div>
<a href="{% url 'contacts:contact_details' contact.id %}">
<span class="font-weight-bolder font-size-lg mr-2">[[ contact.subject ]] -</span>
</div>
Appreciate any help.
For those who face the same problem. I've managed to solve it by using v-bind directive.
From:
<div>
<a href="{% url 'contacts:contact_details' contact.id %}">
<span class="font-weight-bolder font-size-lg mr-2">[[ contact.subject ]] -</span>
</div>
To:
<div>
<a v-bind:href="'http://127.0.0.1:8000/contacts/' + contact.id">
<span class="font-weight-bolder font-size-lg mr-2">[[ contact.subject ]] -</span>
</div>
Related
I am trying to build some search functionality within a modal. When a user clicks a button it will open a modal with a search box. I then want the results of the search to be shown within the same modal?
<div class="modal" id="select2modal">
<div class="modal-dialog" role="document">
<div class="modal-content modal-content-demo">
<div class="modal-header">
<h6 class="modal-title">Search for product to add</h6><button aria-label="Close" class="close" data-dismiss="modal" type="button"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<h6>product Search</h6>
<div class="card-body pb-2">
<form method=POST action="{% url 'searchproduct' %}">
{% csrf_token %}
<div class="input-group mb-2">
<input type="text" class="form-control border-right-0 pl-3" name="search" placeholder="Enter product Name" value="">
<span class="input-group-append">
<button class="btn ripple btn-primary" type="submit"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button class="btn ripple btn-primary" type="button">Add product</button>
<button class="btn ripple btn-secondary" data-dismiss="modal" type="button">Close</button>
</div>
</div>
</div>
</div>
view
def search_product(request):
searched = request.POST['searched']
return render(request, 'index.html',{'searched':searched})
I don't think i should be doing return render(request, 'index.html',{'searched':searched}) think I should just be returning searched
The problem is this relies on the page being refreshed that closes the modal.
So what is the correct way - Do I need to use JavaScript or something.
UPDATE:
I have added jquery now
<script type="text/javascript">
$(document).on('submit','#post-form', function(e){
e.preventDefault();
$.ajax({
type:'POST',
url: '/searchproduct',
data:{
searched:$('#search').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success: function (){
}
});
});
</script>
Which seems is doing a POST and returning 200 but the data returned data isn't being shown in the modal.
def search_product(request):
searched = request.POST['searched']
returned_products = Product.objects.filter(product_name__contains=searched)
return {'searched':searched,'returned_products':returned_products}
and then within my modal i am using:
{% for t in returned_products %}
{{t.product_name}}
{% endfor %}
UPDATE 17/02
I think i have made some progress, but i still not getting the results back within the modal, but my search is returning a 200 rather than a error now.
In my AJAX:
<script type="text/javascript">
$(document).on('submit','#post-form', function(e){
e.preventDefault();
$.ajax({
type:'POST',
url: '/searchproducts',
data:{
searched:$('#search').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success: function (data){
$('jresponse').html(returned_products);
}
});
});
I'm returning returned_products and within my modal I have
<div id="jresponse">
{{ returned_products }}
</div>
```
My view
```
def products(request):
searched = request.POST['searched']
returned_products = Product.objects.filter(product_name__contains=searched).values()
return JsonResponse({"returned_products":list(returned_products)})
```
I think the best way to approach this is to use JavaScript and Ajax calls in your frontend/template and HTTP responses with JSON data in your view/backend. You would not do a form submit but instead POST HTTP calls via Ajax to your view (which most likely would be triggered by the button you already have in place). Your view would then respond with a HTTP response which has to be interpreted and incorporated again by JavaScript in your frontend. A good way to structure your response is using JSON format, which can be easily interpreted using JavaScript. Django Rest Framework can make this easier for bigger projects, but it might be good enough to build the JSON responses more or less manually at small projects.
I have a store page on my site (written in Django w/ a Passenger server) where users can add products to their shopping cart. The cart is stored as a cookie. When they proceed from the store page to the cart page, the cart view should list all of the items in their cart (which it gets from the cart cookie in the request). This works fine when I run it locally. However, when I run this in production, it almost always says the cart is empty. It only lists the cart items properly if I do a hard refresh of the page.
I've added some print statements to the server, and I can see that the view for the page is being called twice in prod (it's only called once in dev). The first time the view is called, the cart cookie has the correct values. The second time it's called however, the cart cookie in the request is an empty object {}. All other cookies in the request look normal (session id, csrftoken, etc). What's very strange is I can see in the browser's developer panel that the cart cookie is populated in both the request's header cookie tab as well as the storage tab.
Django view/utility functions:
def cart_view(request):
data = cart_data(request)
context = {
'items': data['items'],
'order': data['order'],
'cart_items': data['cart_items'],
}
return render(request, 'store/cart.html', context)
def cart_cookie(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
return cart
def cart_data(request):
cart = cart_cookie(request)
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0, 'shipping': False}
cart_items = order['get_cart_items']
'''
Logic to parse the cart cookie
'''
return {
'items': items,
'order': order,
'cart_items': cart_items,
}
Here's the functions on the store page to populate the cart:
var updateBtns = document.getElementsByClassName('update-cart');
for (var i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function() {
var productId = this.dataset.product;
var action = this.dataset.action;
updateCartCookie(productId, action);
})
}
function updateCartCookie(productId, action) {
if (action == 'add') {
if (cart[productId] === undefined) {
cart[productId] = {'quantity':0};
}
cart[productId]['quantity'] += 1;
} else if (action == 'remove') {
cart[productId]['quantity'] -= 1;
if (cart[productId]['quantity'] <= 0) {
delete cart[productId];
}
}
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
location.reload();
}
This code is in the page header to initialize the cookies. It's not being called on navigation to the cart page.
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++){
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken'); // this is just a string
var cart = JSON.parse(getCookie('cart')); // this is a json object, so we need to parse it
if (cart == undefined) {
cart = {};
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
}
</script>
And finally, here are the templates for the Store and Cart pages
#Store
{% block content %}
{% load static %}
<div class="container">
<h1 class="page-title">Store</h1>
<div class="row" style="margin-bottom: 20px">
{% for product in products %}
<div class="col-lg-4" style="margin-bottom: 20px">
<img class="thumbnail" src="{{product.imageURL}}">
<br>
<div class="box-element product">
<div>
<h4><strong>{{product.name}}</strong></h4>
<hr>
<p>
{{product.description}}
</p>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<h4>{{ product.price|floatformat:-2 }}</h4>
<button data-product={{product.id}} data-action="add" class="btn light update-cart">Add</button>
</div>
</div>
</div>
{% endfor %}
</div>
<div>
<a style="float: right; margin: 5px;" class="btn dark" href="{% url 'cart' %}">Cart</a>
</div>
</div>
{% endblock content %}
#Cart
{% block content %}
<div class="container">
<h1 class="page-title">Cart</h1>
<div class="">
<a class="btn button light" href="{% url 'store' %}">← Store</a>
<br>
<br>
{% if cart_items == 0 %}
<p style="text-align: center;">Your cart is empty.</p>
{% else %}
<div>
<div class="cart-row">
<div class="shrinking-flex-column-2-1"><strong>Item</strong></div>
<div class="static-flex-column-1"><strong>Price</strong></div>
<div class="static-flex-column-1"><strong>Quantity</strong></div>
<div class="static-flex-column-1"><strong>Total</strong></div>
</div>
{% for item in items %}
<div class="cart-row" style="align-items: center;">
<div class="shrinking-flex-column-2-1">{{item.product.name}}</div>
<div class="static-flex-column-1">${{item.product.price}}</div>
<div class="static-flex-column-1">
<p class="quantity">x{{item.quantity}}</p>
<div class="quantity">
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-up.png' %}" data-product={{item.product.id}} data-action="add" >
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-down.png' %}" data-product={{item.product.id}} data-action="remove" >
</div>
</div>
<div class="static-flex-column-1">${{item.get_total}}</div>
</div>
{% endfor %}
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h5>Total Order Items: <strong>{{order.get_cart_items}}</strong></h5>
<h5>Total Order Amount: <strong>${{order.get_cart_total}}</strong></h5>
</div>
<a class="btn dark" role="button" href="{% url 'checkout' %}">Checkout</a>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock content %}
This ended up being entirely a caching issue. Adding the #never_cache decorated to the cart/checkout views fixed the problem.
How to set cache control headers in a Django view class (no-cache)
I have 4 Users(2 X CP_USER, 2 X CP_SCRNS) and two subgroups(Login stats and Application stats) but two of then belong to one group and another 2 belong to another group.
Here is the screenshot.
Database
How to separate two group and display in the html page in the same box.Here is the referenceHere is the reference how the index page shouls look like.
.
Here is my models page:
from django.db import models
from datetime import datetime
Create your models here.
class Kpi_Data(models.Model):
kpi_key = models.CharField(max_length=200,default="")
kpi_date = models.DateField(blank=True,null=True)
kpi_value = models.CharField(max_length=200,default="")
kpi_Group = models.CharField(max_length=200,default="")
kpi_subgroup = models.CharField(max_length=200,default="")
kpi_delta_ind = models.CharField(max_length=200,default="")
Here is my views.py file
from django.shortcuts import render
from django.http import HttpResponse
from .models import Kpi_Data
from django.template import loader
Create your views here.
def home(request):
return render(request,"myApp/index.html")
def info(request):
ac = Kpi_Data.objects.all()
template = loader.get_template('myApp/info.html')
Context = {
'ac': ac,
}
return HttpResponse(template.render(Context, request))
Here is my info.html page.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="utf-8">
<style>
</style>
</head>
<nav class="navbar navbar-expand-xl navbar-dark bg-dark">
<div class = "logo"></div>
<img src= "" width="190" height="70" alt="">
</div>
enter code here
<!-- Collection of nav links, forms, and other content for toggling -->
<div class="input-group search-box">
<input type="text" id="search" class="form-control"
placeholder="Search here...">
</div>
</form>
<div class="navbar-nav ml-auto">
<a href="#" class="nav-item nav-link active"><i1 class="fa fa-
home"></i1></a>
<div class="nav-item dropdown">
<a href="#" data-toggle="dropdown" class="nav-item nav-link
dropdown-toggle user-action active">{{ request.headers.uid }}
</br>{{ request.headers.role}}</a>
<div class="dropdown-menu">
<a href="#" class="dropdown-item"><i class="fa fa-user-o">
</i> Profile</a>
<a href="#" class="dropdown-item"><i class="fa fa-calendar-
o"></i> Calendar</a>
<a href="#" class="dropdown-item"><i class="fa fa-sliders">
</i> Settings</a>
<div class="divider dropdown-divider"></div>
<a href="#" class="dropdown-item"><i class="material-
icons"></i> Logout</a>
</div>
</div>
</div>
</nav>
<body>
<div class="sidebar">
<a class = "nav-item nav-link" href="#">Home</a>
Reference Data
`enter code here` Report Registration
Role Management
Role maintenence
User Roles
User Management
</br>
</div>
<h1>Login statistics</h1>
<h2>Appication statictics</h2>
<div class="footer fixed-bottom">
# Copyright Maryland.gov
All rights Reserved
Contatc us
Privacy & Security
Accessbility
</div>
</body>
</html>
Thanks in advance.
I see your code.
rows = Kpi_Data.objects.objects.values('kpi_group', 'kpi_subgroup',
'kpi_key').annotate(value=sum('kpi_value'))
L_C_U = L_C_S = A_C_U = A_C_S = 0`
for row in rows
if (row[kpi_Group]=='LOGIN_STATIS' and row[kpi_subgroup]='CONSUMER_PORTAL' and row[kpi_key]='CP_USER'):
L_C_U = row[value]
elif (row[kpi_Group]=='LOGIN_STATIS' and row[kpi_subgroup]='CONSUMER_PORTAL' and row[kpi_key]='CP_SCRNS'):
L_C_S = row[value]
....
Context = {
'LCU': L_C_U,
'LCS': L_C_S,
....
}
Then, in info.html, an template file, use LCU, LCS ... to display data.
I'm glad if above code would help you.
I have several dropdowns in my form, which I am looking to populate using Ajax from backend. Given below are the relevant code segments:
HTML:
<div class="row">
<div class="col-xs-6">
<div class="col-xs-6">
<label name="start_date" class="control-label" style="width:35%">Start date</label>
<input type="date" style="color:black;width:100px" ></input>
</div>
</div>
<div class="col-xs-6">
<label name="end_date" class="control-label" style="width:35%">End Date(Default: Current Date)</label>
<input style="color:black;width:100px" type="date"></input>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<label name="fruit" class="control-label" style="width:35%; padding-left:15px">Select a Fruit</label>
<select style="width:150px;height:30px">
{% for option in options.fruit %}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
</div>
<div class="col-xs-6">
<label name="vendor" class="control-label" style="width:35%">Select a vendor</label>
<select style="width:150px;height:30px">
{% for option in options.vendor %}
{{ option }}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
</div>
</div>
{% block script %}
<script>
document.onload = function(){
$.ajax({
url : window.location.href,
type:'GET',
cache:false,
data:{type:'formdata'},
success:function(res){
if(typeof res.options == 'undefined'){
self.options = res.options;
}
if(typeof res.options.start_date == 'undefined'){
self.form.start_date = res.options.start_date;
}
if(typeof res.options.end_date == 'undefined'){
self.form.end_date = res.options.end_date;
}
if(typeof res.options.fruit == 'undefined'){
window.fruit = res.options.fruit;
}
if(typeof res.options.vendor == 'undefined'){
window.vendor = res.options.vendor;
}
},
error : function(err){
self.message = "Error getting data for the form";
}
});
}
</script>
{% endblock %}
Both the drop downs are independent of each other. The data is being given at the front end through this view:
class Search(View):
def get(self, request):
if request.GET.get('type') == 'formdata':
options = {'fruit': [], 'vendor': []}
try:
cursor = connections['RDB'].cursor()
options['end_date'] = today.strftime('%Y-%m-%d')
last_week_date = today - timedelta(days=7)
options['start_date'] = last_week_date.strftime('%Y-%m-%d')
options['fruit'] = [a[0] for a in cursor.fetchall()]
options['vendor'] = [a[0] for a in cursor.fetchall()]
return JsonResponse({'options': options})
The back end is working perfectly fine, the options dictionary is getting populated as I expected it to. However the drop down options are not showing up on the front end. Where am I going wrong? Any help is greatly appreciated.
Maybe try using select2 it's a pretty good utility for populating select boxes through Ajax, even has a search functionality in built. Here's a simple example.
html -
<html>
<head>
<title>Using Select2</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Select2 CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
</head>
<body>
<div class="jumbotron">
<div class="container bg-danger">
<div class="col-md-6">
<label>Single Select2</label>
<select class="js-data-example-ajax"></select>
</div>
</div>
</div>
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- Select2 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<script>
$('.js-data-example-ajax').select2({
ajax: {
url: 'https://api.github.com/search/repositories',
dataType: 'json'
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
}
});
</script>
</body>
</html>
Don't forget to import the relative JS and CSS CDN's.
I am trying to create password reset api using Django Rest Framework and Angular 6. But when I try to do POST call to the password reset url I am receiving error saying "CSRF verification failed. Request aborted"
my url.py file includes:
url(r'password-reset/', auth_views.PasswordResetView.as_view()),
url(r'password-reset/done/', auth_views.PasswordResetDoneView.as_view()),
url(r'password-reset-confirm/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view()),
url(r'password_reset_complete/',auth_views.PasswordResetCompleteView.as_view())
For the front end I am using Angular as follows:
my forgot-password.html includes:
<navbar></navbar>
<div class="container-fluid px-xl-5">
<section class="py-5">
<div class="row">
<div class="col-lg-12 mb-5">
<div class="card">
<div class="card-header" style="text-align: center;">
<h3 class="h6 text-uppercase mb-0">RESET PASSWORD FORM</h3>
</div>
<div class="card-body">
<form class="form-horizontal" #forgotPassword="ngForm">
<div class="form-group row">
<label class="col-md-3 form-control-label">Email Address</label>
<div class="col-md-6">
<input class="validate" #email="ngModel" [(ngModel)]="input.email" name= "email" type="email" placeholder="Email Address" class="form-control" [pattern]="emailpattern" required>
<div class="alert alert-danger" *ngIf="email.touched && !email.valid">Email is required!</div>
</div>
</div>
<div class="line"></div>
<div class="alert alert-success" *ngIf="successMessage">{{ successMessage }}</div>
<div class="alert alert-danger" *ngIf="errorMessage">{{ errorMessage }}</div>
<div class="form-group row">
<label class="col-md-3 form-control-label"><a routerLink="/login">Back to Login</a></label>
<div class="col-md-12" style="text-align: center;">
<button (click)="submitEmail()" type="submit" class="btn btn-primary shadow" [disabled]="!forgotPassword.valid">Send Reset Link</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</div>
and forgot-password.ts file is as follow:
import { Component, OnInit } from '#angular/core';
import { UsersService } from 'src/app/services/users.service';
#Component({
selector: 'app-forgot-password',
templateUrl: './forgot-password.component.html',
styleUrls: ['./forgot-password.component.scss'],
providers: [UsersService]
})
export class ForgotPasswordComponent implements OnInit {
input;
emailpattern = "[a-z0 - 9!#$%& '*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&' * +/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
errorMessage: string = '';
successMessage: string = '';
constructor(private userService: UsersService) { }
ngOnInit() {
this.input = {
email: ''
};
}
submitEmail() {
this.successMessage = '';
this.errorMessage = '';
this.userService.resetPassword(this.input).subscribe(
response => {
this.successMessage = 'Please Check you mail for password reset link!';
},
error => this.errorMessage = 'Please enter correct email or try again later!'
);
}
}
and finally .service is as follows:
resetPassword(data): Observable<any> {
return this.http.post('http://127.0.0.1:8000/api/password-reset/', data);
}
I am not able to understand what to do and how to solve this issue.
CSRF are usually used if session authentication. SPAs don't use this kind of auth (usually it's used another pattern such as JSON web tokens). You can disable CSRF in the Django as explained here: Django Rest Framework remove csrf