I am relatively new to Django framework and working on getting my first application running. I am encountering the below issue when i try to pass my queryset from my view to the template.
My view.py:
with connection.cursor() as cursor:
cursor.execute("SELECT TOP(5) * FROM xxx WHERE sbu = %s", [sbu])
def dictfetchall(cursor):
columns = [col[0] for col in cursor.description]
return [dict(zip(columns,row)) for row in cursor.fetchall()]
results = dictfetchall(cursor)
class DecimalEncoder(json.JSONEncoder):
def _iterencode(self, o, markers=None):
if isinstance(o, decimal.Decimal):
return (str(o) for o in [o])
return super(DecimalEncoder, self)._iterencode(o, markers)
json_result = json.dumps(data, cls=DecimalEncoder)
I end up with the below error:
Decimal('28.80') is not JSON serializable
Any suggestions? Am i missing a step somwhere? I have lot of decimal values in the queryset.
Related
I have PATCH button form on ModelViewSet
class CompanyViewSet(viewsets.ModelViewSet):
serializer_class = s.CompanySerializer
queryset = m.Company.objects.all()
def patch(self, request, id, format=None):
print(id)
Now I try to modify the existing data id = 1
So I write this in textarea and push PATCH button.
{
"id":1,
"name": ""
}
However , there comes error like
patch() missing 1 required positional argument: 'id'
Maybe my json is wrong?? How can I do PATCH?
patch() missing 1 required positional argument: 'id'
Use perform_update like this :
class CompanyViewSet(viewsets.ModelViewSet):
serializer_class = s.CompanySerializer
queryset = m.Company.objects.all()
def perform_update(self, serializer):
instance = serializer.instance
request = self.request
serializer.save(**modified_attrs)
return Response(status=status.HTTP_200_OK)
I'm creating an app that shows a webpage search according to a random word that is chosen by the program. I uploaded a dictionary into python to get a random word and now I want to put this word into the src= in my javascript code. What I need is some kind of placeholder that connects the 2 languages
Python
if request.method == 'GET':
#create an empty dictionary
d = {}
key = 0
#open dictionary file and store it in 'dic'
with open('dictionaries/nouns.rtf',encoding="utf8", errors='ignore') as dic:
#read every line and give it a number
for line in dic:
value = line.replace('\\', '')
key += 1
d[key] = value
#select a random number in the range of the dictionary (and store it in a variable)
rand = random.randrange(1, len(d) + 1)
#get the word with that number (and store it in a variable)
word = d[rand]
#print(word)
return render_template('/player.html', word = word)
Javascript
<script>
let is = document.getElementById('innerSpace');
query = encodeURI({{word}})
is.src = `https://www.bing.com/images/search?q=weirdest+${query}&form=QBLH&sp=-1&pq=cats&sc=8-4&qs=n&cvid=20659354CDFD49C6B03ED29A4F35EC64&first=1&tsc=ImageBasicHover`
</script>
To get the randomly generated word from Python to Javascript, you need to return a JSON response from your view.
from django.http import JsonResponse
if request.method == 'GET':
...
data = { 'word': word}
return JsonResponse(data)
You can then access the word within JavaScript using AJAX or Fetch. I will use Jquery as an example.
let is = document.getElementById('innerSpace');
$.ajax({
url: '/URL_for_your_view/',
action: 'GET',
// when the server returns data, the success method is run
success: function (data) {
query = encodeURI({{data.word}})
is.src = `https://www.bing.com/images/search?q=weirdest+${query}&form=QBLH&sp=-1&pq=cats&sc=8-4&qs=n&cvid=20659354CDFD49C6B03ED29A4F35EC64&first=1&tsc=ImageBasicHover`
}})
Now, the problem with this solution is that the view will no longer return the template player.html which seems essential in your code.
return render_template('/player.html', word = word)
To my knowledge, you cannot return a JSON response and a template in the same view. It's impossible.
So you need to use JavaScript to recreate the player.html code inside the success method and append it to the DOM.
I have a javascript application (in angular) that calls my django application. It uses lists of integers to filter the response. In Django I'm using a form to clean the data.
Javascript:
app.factory('SearchData',
function(){
return {
shop:[],
sort:'',
xhr:'',
brand:[],
};
});
app.factory('SearchQuery',
['$http', '$location', '$route', 'SearchData',
function($http, $location, $route, SearchData){
return {
getItems: function(){
return $http.get('/search/',{
params: SearchData,
responseType: 'json',
});
}
};
}
]);
Python form:
class SearchForm(forms.Form):
shop = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
sort = forms.CharField(max_length=1, min_length=1, required=False)
brand = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
I get a list of integers in shop and brand but I do not how to handle it on the django side. I don't want to use MultipleChoiceField as I need to supply choices in form (which creates an unnecessary query). All I want to do is have a list of integers.
The form above throws "Enter a whole number.". I could just ditch the form and use request.GET.getlist('shop') (which works). But I'd rather use a form if possible...
Update, for now I'm using a MultipleChoiceField and pass the choices before validation in the view. Like:
shops = request.GET.getlist('shop', None)
sf = SearchForm(request.GET)
sf.fields['shop'].choices = shops
It works, but it isn't pretty.
Use a custom widget/field:
from django import forms
from django.core.exceptions import ValidationError
class MultipleValueWidget(forms.TextInput):
def value_from_datadict(self, data, files, name):
return data.getlist(name)
class MultipleValueField(forms.Field):
widget = MultipleValueWidget
def clean_int(x):
try:
return int(x)
except ValueError:
raise ValidationError("Cannot convert to integer: {}".format(repr(x)))
class MultipleIntField(MultipleValueField):
def clean(self, value):
return [clean_int(x) for x in value]
class SearchForm(forms.Form):
shop = MultipleIntField()
You can use TypedMultipleChoiceField from Django forms with coerce=int and to avoid validation against predefined list of choices override the def valid_value(self, value): method:
class MultipleIntegersField(forms.TypedMultipleChoiceField):
def __init__(self, *args, **kwargs):
super(MultipleIntegersField, self).__init__(*args, **kwargs)
self.coerce = int
def valid_value(self, value):
return True
class SearchForm(forms.Form):
shop = MultipleIntegersField()
Udi's code is good, but there is a problem (under Django 1.11.7) if you want to use this as (say) a hidden field of a completely general user-input form. The problem is that if the user input fails to validate and is re-POSTed with corrections, the multi-valued POST data comes back the second time around as a repr of itself, i.e
['a','b'] comes back as ["['a', 'b']"] and further mangled with each re-POST
So I wrote the following function which can be used to repair the damage every time the view processes POST data. It's a hack, because it involves making request.POST temporarily mutable using a private variable. Also it doesn't properly handle lists of strings containing commas, escaped quotes etc.
def sanitize_keys( request, only=None):
""" Restore multi-valued keys that have been re-posted. there's a repr
in the round trip, somewhere.
only = list of keys to sanitize. Default is all of them."""
mutt = request.POST._mutable
request.POST._mutable = True
keylist = only or request.POST.keys()
for key in keylist:
v = request.POST.get(key)
if v.startswith("[") and v.endswith("]"):
#print( "Debug: sanitizing " + v )
sanitized=[]
for s in v[1:-1].split(','):
s = s.strip()
if s.startswith("'") and s.endswith("'"):
s=s[1:-1].replace("\\'","'")
sanitized.append(s)
#print( "Debug: sanitized= ", sanitized )
request.POST.setlist( key, sanitized)
request.POST._mutable = mutt
return
Usage (fragments):
class TestForm( forms.Form):
name = forms.CharField()
...
customer_iid = MultipleValueField( required=False)
...
# POST
sanitize_keys( request, only=('customer_iid',) )
#print( 'Debug: customer_iid', request.POST.getlist('customer_iid', []) )
form = TestForm( request.POST)
I am using Django with the Google Charts API. I need to construct a JavaScript array to render a bar chart showing the # of objects created in a given day.
The expected array printed to the template should look like:
...
function drawStuff() {
var data = new google.visualization.arrayToDataTable([
['Date', '# of records'],
['2015-03-07', 3], // Expected format: ['Date', # of objects]
['2015-03-08', 8],
]);
...
views.py:
class LogsView(TemplateView):
template_name = 'logs.html'
def ValuesQuerySetToDict(self, vqs):
return [ [item['date_created'], item['created_count'] ] for item in vqs]
def render_chart_data(self, **kwargs):
queryset = LogEntry.objects.filter(user=self.request.user).extra(
{'date_created': 'date(created)'}
).values('date_created').annotate(created_count=Count('id'))
modified_dict = self.ValuesQuerySetToDict(queryset)
return json.dumps(modified_dict)
def get_context_data(self, **kwargs):
context = super(
LogsView, self
).get_context_data(**kwargs)
context['chart_data'] = self.render_chart_data()
The following is rendered to my django template (I bypassed sending it to JavaScript for now to see what was returned...
When I believe I need to return a JavaScript array like the following:
["2015-02-18", 3],
["2015-02-19", 12],
["2015-02-21", 1],
And feed that to the drawStuff function which will render the barchart.
Alternate Method
I followed the this thread on StackOverflow and modified the render_chart_data to use django serializer like this but I am getting an error: " 'dict' object has no attribute '_meta'
Thanks to all who offered assistance on this.
Two things needed to changed; the ValuesQuerySetToDict function needed to be rewritten as follows:
def ValuesQuerySetToDict(self, vqs):
list_vals = [ ['Date', '# of records'] ]
for item in vqs:
list_vals.append(
# convert datetime object to string otherwise JSON serialization error
[ str(item['date_created']), item['created_count'] ]
)
return list_vals
And the render_chart_data function needed to be rewritten as follows:
def render_chart_data(self, **kwargs):
queryset = LogEntry.objects.filter(user=self.request.user).extra(
{'date_created': 'date(created)'}
).values('date_created').annotate(created_count=Count('id')).order_by('created-date')
modified_list = list(self.ValuesQuerySetToDict(queryset))
json_data = json.dumps(modified_list)
return json_data
Finally, {{ chart_data }} needed to be passed to to the drawStuff function, like so:
function drawStuff() {
var data = new google.visualization.arrayToDataTable(
{{ chart_data|safe }}
);
I've posted views.py and logs.html here.
In your queryset, render created_count as string and not as integer. Json's do not behave well with Integers.
In your JS function drawStuff, chart_data should be parsed as json. See below:
var json_string = '{{chart_data}}';
var json = JSON.parse(json_string);
var data = new google.visualization.arrayToDataTable(json)
I work a project which server site is Grails, Client Site is Extjs4.1, I use relational database. In this situation i work fine but when i call store then i facing some problem.
This problem based on parents. when I call store like below..... then i must call its parents but i do not want to call its parents..
def stote(){
def prices = []
Price.getAll()?.each{ v ->
def a = v.article,
b = a.brand,
bt = b.brandType,
gp = b.genericProducts,
c = gp.categories,
m = b.manufacturers
def manufacture = [id:m.id, name:m.name]
def category = [id:c.id, name:c.name]
def genericProduct = [id:gp.id, name:gp.name, m01i001001:category]
def brandType = [id:bt.id, name:bt.name]
def brand = [id:b.id, name:b.name, m01i002001:manufacture, m01i003001:genericProduct, m01i004001:brandType]
def article = [id:a.id, name:a.name, mbcode:a.mbcode, pbcode:a.pbcode, details:a.details, m01i005001:brand]
def price = [id: v.id, m01i006001:article, price:v.price, date:v.date]
prices << price
}
return prices
}
Those are belongTo association key
m01i001001, m01i002001, m01i003001,m01i004001,m01i005001,m01i006001
my belongTo like as
belongsTo : [{
model : '${pkgName}.M01I005001',
associatedName : 'M01I005001' ,
associationKey : 'm01i005001' ,
primaryKey : 'id' ,
foreignKey : 'brandId'
}],
i want to call like this store...
def stote(){
def prices = []
Price.getAll()?.each{ v ->
def a = v.article
def article = [id:a.id, name:a.name, mbcode:a.mbcode, pbcode:a.pbcode, details:a.details]
def price = [id: v.id, m01i006001:article, price:v.price, date:v.date]
prices << price
}
return prices
}
but when i call this store then client side loading problem. I can not lazy its parents. its show always eager.
Please let me know if you have any idea to resolve this error.
Thanks in advance
This is not a solution for this. I create a proxy model for this and i remove all relation which are not necessary then i solve my problem that means i keep only one belongsto so keep only one association key.