I am have created a page in django, on this page I have create a button that calls a JavaScript function which in turn gets data from a API. This part of my code works as expected as it writes the response data to the console. However I cannot seem to get that data to be inserted into the model I have created in django.
I am not sure how python/javascript/models are meant to all link together.
models.py
from django.db import models
class Set(models.Model):
scry_id = models.CharField(max_length=255)
code = models.CharField(max_length=255)
name = models.CharField(max_length=255)
set_type = models.CharField(max_length=255)
release_date = models.DateField()
card_count = models.IntegerField()
block_code = models.CharField(max_length=255, null=True)
block_name = models.CharField(max_length=255, null=True)
parent_set_code = models.CharField(max_length=255, null=True)
digital_only = models.BooleanField(default=False)
foil_only = models.BooleanField(default=False)
nonfoil_only = models.BooleanField(default=False)
icon = models.CharField(max_length=255)
status = models.BooleanField(default=False)
def __str__(self):
return self.name
sets.html
{% extends "main/index.html "%}
{% block content %}
<div class="background card">
<div class="card-body">
<button class="btn" id="setRefresh" style="border: 1px solid" onclick="setRefresh()"><i class="fas fa-sync"></i></button>
</div>
</div>
{% endblock%}
custom.js
function setRefresh() {
const Url="https://api.scryfall.com/sets";
fetch(Url)
.then(res => res.json())
.then(data => obj = data.data)
.then(() => obj.sort(function(a,b){return a.released_at.localeCompare(b.released_at);}))
.then(() => {
for (var i = 0; i < obj.length; i++) {
//console.log(obj[i].name);
}
})
}
view.py
def sets(request):
return render(request,
"main/sets.html",
{"Sets": Set.objects.all})
There are two missing parts. First you need to have a url to listen for changes and then you need to have a view function where you want to set data. And you need to make some changes for the JS part of your code.Example below can clear this up and it is functional as well:
views.py
#ajax_required
def views_name(request):
try:
if request.method == 'POST':
post_id = request.POST.get('post')
YourModel.objects.create(id=post_id)
except Exception: # pragma: no cover
return HttpResponseBadRequest()
urls.py
urlpatterns = [
url(r'^whatever/$', views.views_name, name='whatever'),
]
custom.js:
$(function () {
$(".class-name").click(function () {
var csrf = $(this).attr('csrf');
var post = $(this).attr('page-id');
$.ajax({
url: '/whatever/',
data: {
'post': post,
'csrfmiddlewaretoken': csrf
},
type: 'post',
cache: false,
success: function (returned_values) {
// do whatever you want after success!
},
});
});
})
There are two ways to do it
Method 1 : After retrieving the data, send them to your django app instead of logging them into the console . have a django view that handles the corresponding request coming from your js code containing the data then adding them to the db. In other words you should fetch again , but this time to your django app using a post request .
.Your view should look like this :
from .models import Set
from django.http import HttpResponse
import json
def save(request):
data=json.loads(request.body)
for entry in data:
s = Set()
s.scry_id=entry["scry_id"]
#in the next lines you map entry fields to Set fields
s.save()
return HttpResponse("ok")
Method 2 : Your button call your django app on click , then your django app retrieve the data from https://api.scryfall.com/sets itself then save them to the db. Your code should look like this
from .models import Set
from django.http import HttpResponse
import json
import requests
def save(request):
response = requests.request("GET", "https://api.scryfall.com/sets")
data=response.json()
for entry in data:
s = Set()
s.scry_id=entry["scry_id"]
#in the next lines you map entry fields to Set fields
s.save()
return HttpResponse("ok")
Of course in either case don't forget to map your urlconf to the save view
Related
This the error message I got when I submit empty fields (which is behave like I want in my class form validators):
But when I try to submit with valid email, it give me this error message:
I basically want to submit a form using Flask-WTF but handling it from Javascript fetch. Because I want to perform it dynamically like New York Times Login Form: NYT Login Form
App.py
import os
from flask import Flask, jsonify, flash, redirect, render_template, request, session
from flask_session import Session
from flask_api import status
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import InputRequired
from flask_wtf.csrf import CSRFProtect
from werkzeug.security import check_password_hash, generate_password_hash
from helpers import login_required
# Configure flask application
app = Flask(__name__)
# Configure Secret Key
app.config["SECRET_KEY"] = "secret123"
# Create Form Class
class AuthenticationForm(FlaskForm):
email = StringField('Email Address', [InputRequired(message="Please enter your email address")])
# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Configure SQLAlchemy databases
basedir = os.path.abspath(os.path.dirname(__file__))
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(basedir, 'newspaper.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# Create SQLAlchemy object of class
class Readers(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.Text, unique=True, nullable=False)
hash = db.Column(db.Text, nullable=False)
def __repr__(self):
return f'<Readers {self.email}>'
#app.after_request
def after_request(response):
"""Ensure responses aren't cached"""
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
#app.route("/")
#login_required
def index():
"""Show Newspaper"""
return redirect('/auth/login')
#app.route("/auth/<authentication>", methods=["GET", "POST"])
def auth(authentication):
"""Log user in"""
# Forget any user_id
session.clear()
# Get form class
form = AuthenticationForm()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
if authentication == 'login':
if form.validate():
data = request.get_json()
email = data["email"]
# Check if email already registered in database
user = Readers.query.filter_by(email=email).first()
if not user:
return "Not Registered Yet", 200
return "Valid!", 200
return jsonify(form.errors), 400
# User reached route via GET (as by clicking a link or via redirect)
return render_template("auth.html", form=form)
auth.html
{% extends "layout.html" %}
{% block title %}
Login -
{% endblock %}
{% block main %}
<div class="auth__form-wrapper">
<div class="auth__title">
<h2>Log in or create an account</h2>
</div>
<div id="success-message"></div>
<form id="form" method="post">
{{ form.csrf_token }}
<fieldset type="email" class="mb-1">
{{ form.email.label }}
{{ form.email(autocomplete="off", autofocus=true, required=false) }}
</fieldset>
<div id="error-message">
<span style="color: #cf0000;" id="error"></span>
</div>
<button id="continue" class="btn btn-dark">Continue</button>
</form>
</div>
<script src="{{url_for('static', filename='authentication.js')}}"></script>
{% endblock %}
.js file to handling submit:
const form = document.querySelector('#form');
const successMessage = document.querySelector('#success-message');
const errorMessage = document.querySelector('#error');
const fields = {
csrf_token: {
input: document.querySelector('#csrf_token')
},
email: {
input: document.querySelector('#email')
}
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
const response = await fetch('/auth/login', {
'method': 'POST',
'headers': {
'Content-Type': 'application/json'
},
'body': JSON.stringify({
'csrf_token': fields.csrf_token.input.value,
'email': fields.email.input.value
})
});
if (response.ok) {
successMessage.innerHTML = await response.text();
} else {
const err = await response.json();
Object.keys(err).forEach((key) => {
errorMessage.innerHTML = err[key][0];
});
}
})
If I just use a traditional way instead of Javascript fetch to validate Flask-WTForm using validate_on_submit() it perform good. Because validate_on_submit() seems like handle all validators.
But I just don't know why this happen. Should I use Javascript to handle Flask WTF like my code above? Or I just use Flask WTF using validate_on_submit()? I just want to make a login form that behave like New York Times Login Form: NYT Login Form
I'm still new on this. I hope you guys can help.
I created Coupon code in django rest framework and now i like to redeem it using python script or any frontend method like html, javascript,Postman, i don't have way, path or logic which can guide me on how to do it.
Here is my models.py file :
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class Coupon(models.Model):
code = models.CharField(max_length=50, unique=True)
valid_from = models.DateTimeField()
valid_to = models.DateTimeField()
discount = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)])
active = models.BooleanField()
def __str__(self):
return self.code
here is my serializers.py file
from rest_framework import serializers
from .models import Coupon
class CouponSerializer(serializers.ModelSerializer):
class Meta:
model = Coupon
fields = '__all__'
here is my views.py file
from django.shortcuts import render
from .models import Coupon
from .serializers import CouponSerializer
from rest_framework import viewsets
class CouponViewSet(viewsets.ModelViewSet):
queryset = Coupon.objects.all()
serializer_class = CouponSerializer
Please do help
You can create a new action in your viewset where you can check the validity of the code and provide an appropriate response.
class CouponViewSet(viewsets.ModelViewSet):
queryset = Coupon.objects.all()
serializer_class = CouponSerializer
#action(detail=True, methods=['get'])
def redeem(self, request, pk=None):
obj = self.get_object()
// do all the checks here.
return Response(// return data what needed)
You can change the method of this custom method according to your need if you want to send additional data.
Also note that if you are using this coupon to create an order, do send this coupon in the final request where you can verify the discount again.
You can map the different serializer for each action in your viewset.
# mapping serializer into the action
serializer_classes = {
'list': PatientDischargeListSerializer,
'retrieve': PatientDischargeReadSerializer,
'create': PatientDischargeSerializer,
'update': PatientDischargeSerializer,
'partial_update': PatientDischargeSerializer,
'redeem': CustomSerializer,
}
default_serializer_class = PatientDischargeSerializer
def get_serializer_class(self):
return self.serializer_classes.get(self.action, self.default_serializer_class)
#action(detail=True, methods=['get'])
def redeem(self, request, pk=None):
serializer_class = self.get_serializer_class()
obj = self.get_object()
serializer = serializer_class(instance=obj, data=request.data)
// do all the checks here.
return Response(// return data what needed)
I am trying to build functionality into my webapp the does the following:
A user searches for an address
Nearby cafes are pulled from a database table and displayed to them
The user is able to click an "add-to-list" tag
The cafe name/address are added to a list made by the user
I have successfully built 1 and 2. I am struggling with 3 and 4.
The Current Situation
I am trying to pass the cafeName at this stage via an AJAX post call, but it doesn't look like it is firing correctly. Initially I was trying to do this with AJAX and views.py function but was advised to use Django Rest Framework, so I am now creating an api and using Ajax to pass the cafe details async.
I am currently getting this error when I click a venue name:
POST http://127.0.0.1:8000/api/venues/added 400 (Bad Request)
The Code
At this stage my models.py file looks like this
class mapCafes(models.Model):
id = models.BigAutoField(primary_key=True)
cafe_name = models.CharField(max_length=200)
cafe_address = models.CharField(max_length=200)
cafe_long = models.FloatField()
cafe_lat = models.FloatField()
geolocation = models.PointField(geography=True, blank=True, null=True)
class Meta:
managed = False
db_table = 'a_cafes'
class UserList(models.Model):
list_name = models.CharField(max_length=255)
user = models.ForeignKey(User, on_delete=models.CASCADE) #is this okay?
class Venues(models.Model):
venue_name = models.CharField(max_length=255)
venue_address = models.CharField(max_length=100)
venue_long = models.FloatField(null=True)
venue_lat = models.FloatField(null=True)
venue_geolocation = models.PointField(geography=True, blank=True, null=True)
user_list = models.ForeignKey(UserList, on_delete=models.CASCADE) #this may need to change to a manytomany model
class VenueList(models.Model):
title = models.CharField(max_length=100)
user = models.OneToOneField(User, on_delete=models.CASCADE)
venues = models.ManyToManyField(Venues)
created = models.DateTimeField(auto_now_add=True)
My project urls look like this
urlpatterns = [
path('venues/added', views.AddVenueList.as_view()),
path('venues/create', views.CreateVenueList.as_view()),
]
My api app urls look like this
urlpatterns = [
path('venues/added', views.AddVenueList.as_view()),
path('venues/create', views.CreateVenueList.as_view()),
]
The views.py for the API app looks like this
class AddVenueList(generics.ListAPIView):
serializer_class = VenueListSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
return VenueList.objects.filter(user=user)
class CreateVenueList(generics.ListCreateAPIView):
serializer_class = VenueListSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
return VenueList.objects.filter(user=user)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
And finally the template looks like this (I've stripped the Ajax success function back to simply show console.log at this stage).
<div>
<ul class = "cafe-details">
{% for cafe in cafes %}
<li>
<address>
<div>
<h6 class="cafe-name">{{ cafe.cafe_name }}</h6>
<p >{{ cafe.cafe_address }}</p>
</div>
</address>
<p>
Add to List / Recommend
</p>
</li>
{% endfor %}
</ul>
</div>
<script>
const cafeList = document.querySelector(".cafe-details");
cafeList.addEventListener('click', e => {
if (e.target && e.target.matches('a')) {
const listItem = e.target.closest('li');
var cafeName = listItem.querySelector('.cafe-name').innerText;
//Show the cafe name.
console.log(cafeName);
$.ajax({
type: "POST",
url : 'api/venues/added',
data: {
'cafeName': cafeName,
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
contentType: "application/json; charset=utf-8",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(data){
alert(data);
console.log('User clicked: ' + data)
},
failure: function(errMsg) {
alert(errMsg);
}
});
};
});
</script>
In Django, I want to render a page that includes a Chart js chart that relies on data from my database. I believe I need to implement an API for this. The same page with the chart will contain other info from the database that I think is rendered with a context dictionary and {{ variable }}. I know how to do one or the the other, but not both on the same page. Here is what I have so far. In views.py:
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views import generic
from django.views.generic import View
from .models import Article
from rest_framework.views import APIView
from rest_framework.response import Response
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
articles = Article.objects.all()
correlationlist = []
nocorrelationlist = []
for corr in articles:
if corr.correlation_type == "Correlation":
correlationlist.append(1)
nocorrelationlist.append(0)
elif corr.correlation_type == "No Correlation":
correlationlist.append(0)
nocorrelationlist.append(1)
else:
pass
correlation_items = correlationlist
nocorrelation_items = nocorrelationlist
data = {
"correlation_items": correlation_items,
"nocorrelation_items": nocorrelation_items,
}
return Response(data)
The Javascript I have on the page where the chart appears is:
$(document).ready(function(){
var endpoint = 'api/chart/data/'
var defaultData1 = []
var defaultData2 = [];
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
defaultData1 = data.correlation_items
defaultData2 = data.nocorrelation_items
setChart()
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
function setChart(){
CHART js code goes here
}
})
But on the page where the chart appears, I also want to include other information from the data base, such as:
The title of the article is: {{ title }}
To do this and to render the page, I think I need to create a function in views as follows:
def results(request):
myresults = Article.objects.all()
context = {'myresults': myresults}
return render(request, 'my_page_with_results_and_chart.html', context)
In short, how do you render a page that pulls data from an API for a chart, but also gets database information from the render(request, 'page.html', context) method? This is driving me crazy.
not really sure what you're asking, seems very ambiguous. From a glance it looks like, myresults = Article.objects.all() and articles = Article.objects.all() are the same and you just want to get the title from the article?
Just add articles into your data dictionary
data = {
"myresults": articles,
"correlation_items": correlation_items,
"nocorrelation_items": nocorrelation_items,
}
then just reference it in your html. You cant just do {{ title }} though like your example as 'title' is not a key to your dictionary. if 'articles' is a dictionary with title as a key, you'll need to do {{ myresults.title }} in the html. I hope i answered your question :/
I'm not sure if this is what you're asking as it seems too basic but just from your examples it looks like you are..? Anyway if you do need to make an api the Django RESTful library is really good and great documentation http://www.django-rest-framework.org/
I'm beginning with django and JSON and I'm trying to send the list of patients in JSON using the code bellow:
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
#api_view(('GET',))
#renderer_classes((TemplateHTMLRenderer,))
#csrf_exempt
def patient_list(request):
"""
List all records, or create a new snippet.
"""
if request.method == 'GET':
#data = Patient.objects.all()
data= Patient.objects.all()
#serializer = PatientSerializer(data, many=True)
#return JSONResponse(serializer.data)
return Response({'patients': data}, template_name='records.html')
In records.html, I have this javascript code:
<script type="text/javascript">
var data = "{{patients}}";
var parsed = JSON.parse(data);
</script>
...
<h2> <script type="text/javascript">document.write(data);</script></h2> This is not actually true, I'm trying to figure out how to do it
However, when printing data (in string just to see what I have) I'm receiving something like that
[<Patient: Patient object>, <Patient: Patient object>, <Patient: Patient object>, <Patient: Patient object>, <Patient: Patient object>, <Patient: Patient object>, <Patient: Patient object>]
From my understanding it is not necessary to serialize data when using Response so I did not do it. I just want to get the list of patients and print their firstName for instance. Any help about that ?
You should probably just use the JsonResponse class that Django provides if you want to do it the long way: https://docs.djangoproject.com/en/1.9/ref/request-response/#jsonresponse-objects. But since it looks like you're using DjangoRestFramework, in that case, you might want to consider just making a serializer class and then just making a ViewSet.
in seralizers.py:
from rest_framework import serializers
class MySerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
in views.py:
from rest_framework import viewsets
from .serializers import MySerializer
class MyViewSet(viewsets.ModelViewSet):
serializer_class = MySerializer
queryset = MyModel.objects.all()
in urls.py:
from rest_framework import routers
from .views import MyViewSet
router = routers.SimpleRouter()
router.register(r'mymodel', MyViewSet)