I'm writing a document search website on flask. So I have a page where users form query. When a query is posted I save it into the session and create a session variable to keep liked documents.
#app.route('/', methods=['GET', 'POST']) def main():
search_form = SearchForm()
if search_form.is_submitted():
query = FormMainSearchQuery(search_form)
body = {"query": query}
session["body"] = body <<<<<
session["doc_relevance"] = [1, 2, 3] <<<<
resp = es.search(index="test", body=body, size=24) # 7.x
data = resp['hits']['hits']
return jsonify({'html': render_template('doc_cards.html', data=data)})
else:
return render_template('home.html', form=search_form)
I have document cads on the page that users can like or dislike. On click I send XMLHttpRequest
function LikeDislikeDoc (id,relevance) {
const url = '/relevance';
const xhr = new XMLHttpRequest();
sender = JSON.stringify({"id": id, 'doc_relevance': relevance});
xhr.open('POST', url);
xhr.send(sender);
}
Here /relevance page code. I get data and save it into session.
#app.route('/relevance', methods=['POST'])
def relevance():
if request.method == 'POST':
information = request.data
doc_id = json.loads(information)["id"]
doc_relevance = json.loads(information)["doc_relevance"]
print(session['doc_relevance'])
session['doc_relevance'].append((doc_id, doc_relevance))
print(session['doc_relevance'])
return 'ok'
When I liked one document, it works (data is added to the session), but when I liked the next document, it turns out that the first document wasn't saved.
Here prints
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
127.0.0.1 - - [12/Aug/2022 20:00:28] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [12/Aug/2022 20:00:28] "GET /static/CSS/main.css HTTP/1.1" 304 -
127.0.0.1 - - [12/Aug/2022 20:00:30] "POST / HTTP/1.1" 200 -
[1, 2, 3]
[1, 2, 3, (86743520, 1)]
127.0.0.1 - - [12/Aug/2022 20:00:31] "POST /relevance HTTP/1.1" 200 -
127.0.0.1 - - [12/Aug/2022 20:00:32] "POST /relevance HTTP/1.1" 200 -
[1, 2, 3]
[1, 2, 3, (86740324, 1)]
What happened?
I found out the problem. You need to explicitly equate the value as here
if request.method == 'POST':
doc_id = request.form["id"]
doc_relevance = request.form["relevance"]
data = session['doc_relevance']
data[str(doc_id)] = doc_relevance
session['doc_relevance'] = data
print(session['doc_relevance'])
return 'ok'
I changed the code a little, but the idea should be understood.
Related
When redirecting the url in the console changes but not in the browser
view.py
def tables(request):
if request.method == 'POST':
text = request.POST.get('data_table')
table_to_file(text)
return redirect(reverse('result'))
else:
matrix = Matrix.objects.all()
context = {'matrix': matrix}
return render(request, 'methods/tables.html', context)
def result(request):
return render(request, 'methods/result.html')
urls.py
urlpatterns =[
path('result/', result, name = 'result'),
path('tables/', tables, name='tables'),
In console
[20/Jun/2022 00:22:17] "POST /methods/tables/ HTTP/1.1" 302 0
[20/Jun/2022 00:22:17] "GET /methods/result/ HTTP/1.1" 200 571
But nothing changes in the browser
Your POST is hitting the if statement in tables() and returning results, your GET is being directed to result() which is also returning results, your GET is not going to tables(), so your else statement is never being hit
I wish to create new a data when any user was make any requests like Create Export Delete or Update but now I am working on Export.. I have two urls one is having data of tables (average_data urls) and one url which is have (audit_logs url) a data of user which will be created after when any user download an pdf format of the data .. so basically I wish to show which user on which time and which action he does it will get it on the audit_logs url
I am making request of post in data/views but getting error bad request at /audit_logs/create/
views.py
def averagePDF(request):
global fromDate
global toDate
global site
global device
global parameters
global interval
global data
headers = {
'authorization': "Bearer X...............",
}
devices_url = "http://127.0.0.1:8000/stations/list"
devices_params = {
'id': device
}
devices = requests.request("GET", devices_url, headers=headers, params=devices_params)
response = HttpResponse()
response['Content-Disposition'] = 'attachment; filename=Average Data.pdf'
elements = []
company_name = Paragraph(devices.json()[0]['site'], header_style)
elements.append(company_name)
report_data = Paragraph("Date: " + fromDate + " to " + toDate + " Station: " + devices.json()[0]['station'], title_style)
elements.append(report_data)
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleN.wordWrap = 'CJK'
file_data = []
header = []
header.append("Timestamp")
header.append("Station")
for parameter in parameters:
header.append(parameter)
file_data.append(header)
data2 = [[Paragraph(cell, styleN) for cell in row] for row in file_data]
width = (PAGE_WIDTH-50) / len(header)
table_header = Table(data2, colWidths=width, style=table_header_style)
elements.append(table_header)
table_data = []
for key, values in data.items():
raw_data = []
raw_data.append(str(key))
raw_data.append(devices.json()[0]['station'])
for value in values:
raw_data.append(str(value))
table_data.append(raw_data)
table_data2 = [[Paragraph(cell, styleN)for cell in row] for row in table_data]
tableRaw = LongTable(table_data2, colWidths=width, style=table_style)
elements.append(tableRaw)
doc.title = "Average Data"
meta_data = request.META.get('HTTP_X_FORWARDED_FOR')
if meta_data:
ip = meta_data.split(',')[-1].strip()
else:
ip = request.META.get('REMOTE_ADDR')
**now=datetime.datetime.now()
# date_time = now.strftime('%Y-%m-%dT%H:%M:%S.%f')
username=str(request.user)
action_type="Export"
action="Export"
ip_address=ip
audit_url="http://127.0.0.1:8000/audit_logs/create/"
audit_parms={
"username":username,
"action_type":action_type,
"action":action,
"ip_address":ip_address
}
audit_obj=requests.post(audit_url, headers=headers, params=audit_parms)
print(audit_obj.json())**
when I am posting response its give me following response
{'username': 'abcpadmin', 'action_type': 'Export', 'action': 'Export', 'ip_address': '127.0.0.1'}
Bad Request: /audit_logs/create/
[15/Nov/2021 16:08:24] "POST /audit_logs/create/?username=abcpadmin&action_type=Export&action=Export&ip_address=127.0.0.1 HTTP/1.1" 400 160
<Response [400]>
{'username': ['This field is required.'], 'action_type': ['This field is required.'], 'action': ['This field is required.'], 'ip_address': ['This field is required.']}
When you use requests for post in your case, you need pass data instead of params
It should be :
audit_obj=requests.post(audit_url, headers=headers, data=audit_parms)
Technically, when you do requests.post(url=your_url, params=your_params), the url will be like https://localhost?key=value with key value in params dictionary.
You should take a look at djangorestframework
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/
This is the recommended way to write APIs with django.
I have a generic list view from which I paginate using the querysets from two separate models : Message and safeTransaction.
django terminal output gives this warning upon entry to my inbox view :
/usr/local/lib/python3.6/dist-packages/django/views/generic/list.py:88: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: QuerySet.
allow_empty_first_page=allow_empty_first_page, **kwargs)
This is the View and get_context_data method :
### Inbox list class
class InboxListView(ListView):
#This view lets the user view all the messages created in a list
model = Message
template_name = "myInbox/inbox.html"
paginate_by = 3 # paginating twice here
#so the page gets paginated in a convenient way for my template.
def get_context_data(self, **kwargs):
message_list = Message.objects.filter(recipient=self.request.user)
.order_by('-date')
safeTransaction_list = SafeTransaction.objects
.filter(trans_recipient=self.request.user)
.order_by('-date')
queryset = list(chain(message_list, safeTransaction_list))
#paginator setup start
paginator = Paginator(queryset,3)
page = self.request.GET.get('page')
safe_T_list = paginator.get_page(page) #iterable list for template
#paginator setup done
context = super(InboxListView, self).get_context_data(**kwargs)
context.update({
'now': timezone.now(),
'message_list':safe_T_list,
})
return context
What I am doing in this method is chaining the filtered querysets into a list, then paginating that as one queryset. The problem is that even before I do that, my filtered Messages and SafeTransactions are seen as unordered lists.
This confuses me because the typical usage of order_by() on the django website is similar to what I have done.
In summary, I want to paginate using a queryset built from different object bases, but my filtered objects are consider unordered for reasons I don't understand.
stack trace :
Starting development server at http://127.0.0.1:4200/
Quit the server with CONTROL-C.
[17/Dec/2018 07:52:52] "GET / HTTP/1.1" 200 1490
[17/Dec/2018 07:52:52] "GET /static/css/mystyle.css HTTP/1.1" 200 1555
[17/Dec/2018 07:52:52] "GET /static/css/w3pro.css HTTP/1.1" 200 15672
[17/Dec/2018 07:52:52] "GET /static/css/w3.css HTTP/1.1" 200 23293
[17/Dec/2018 07:52:52] "GET /static/favicon.ico HTTP/1.1" 200 8192
/usr/local/lib/python3.6/dist-packages/django/views/generic/list.py:88: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'account.models.Message'> QuerySet.
allow_empty_first_page=allow_empty_first_page, **kwargs)
[17/Dec/2018 07:52:58] "GET /inbox HTTP/1.1" 200 3134
[17/Dec/2018 07:52:58] "GET /static/css/mystyle.css HTTP/1.1" 200 1555
In my Model, a __str__(self) that derives the quarter and year from the DateTimeField of when Response was created.
Models.py
class Response(models.Model):
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
msg = u"Q%d %d" %(((self.created.month-1)//3)+1, self.created.year)
return msg
In Admin, I want to be able to filter records based on the Quarter in which they were submitted (actually, I want to filter by who hasn't submitted a Response for a particular quarter, which I think I can achieve with a well placed tilde later), so I have the following:
Admin.py
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'latest_response')
list_filter = ('response__created', 'response')
def latest_response(self, obj):
return obj.response_set.latest('created')
I have submitted four responses so far in testing (through the def __str__ I have 2 x "Q1 2018", and 2 x " - "), and the result looks like this:
Any ideas why I am getting 3 x "Q1 2018" and 1 x " - "? I want Only 1 x "Q1 2018" in the filter list
Bonus question - any idea how to set a limit to the number of items listed in the filter_list (by response)? I want to limit them to the latest 4 which, might be problematic as I'm using a string.
EDIT
Just noticed in the console log that the filters are using a GET request based on the Response ID:
"GET /admin/auth/user/?response__id__exact=1 HTTP/1.1" 200 14277
"GET /admin/jsi18n/ HTTP/1.1" 200 3217
"GET /admin/auth/user/?response__id__exact=2 HTTP/1.1" 200 14277
"GET /admin/jsi18n/ HTTP/1.1" 200 3217
"GET /admin/auth/user/?response__id__exact=3 HTTP/1.1" 200 14270
"GET /admin/jsi18n/ HTTP/1.1" 200 3217
"GET /admin/auth/user/?response__isnull=True HTTP/1.1" 200 14599
"GET /admin/jsi18n/ HTTP/1.1" 200 3217
So, as I understand it, the by response filter is displaying the common name (Q1 2018) for four object's (distinguished by their ID).
How do I go about filtering the objects based on their common name/self? I guess via another def to the Response class?
Usually I reserve the def __str__(self): as an identification for my class.
Create a
def Quarter(self):
msg = u"Q%d %d" %(((self.created.month-1)//3)+1, self.created.year)
return msg
And then use that to filter:
list_filter = ('response__created', 'Quarter')
I've created this model:
class TitleDescriptionLazyModel(models.Model):
class Meta:
abstract = True
title = models.CharField(max_length=255)
description = models.TextField(blank=True)
def __str__(self):
return self.title
class Jobsite(TitleDescriptionLazyModel):
pass
Which is used in this autocomplete view as described in the documentation (views.py):
class JobsiteAutocomplete(LoginRequiredMixin, autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated():
return Jobsite.objects.none()
qs = Jobsite.objects.all()
if self.q:
qs = qs.filter(title__istartswith=self.q)
return qs
and my urls.py have the title field set as the "create_field":
urlpatterns = [
JobsiteAutocomplete.as_view(create_field='title'), name='jobsite_autocomplete'),
]
But when I run it I get the autocomplete view passing the get requests until I click on the create button at which point it POSTs 4 times creating 4 new items in the database when I expect it to create 1:
> [22/Aug/2016 20:44:04] "GET /worklogs/jobsite-autocomplete/ HTTP/1.1" 200 356
[22/Aug/2016 20:44:10] "GET /worklogs/jobsite-autocomplete/?q=som HTTP/1.1" 200 252
[22/Aug/2016 20:44:11] "GET /worklogs/jobsite-autocomplete/?q=some HTTP/1.1" 200 254
[22/Aug/2016 20:44:12] "GET /worklogs/jobsite-autocomplete/?q=somewhere HTTP/1.1" 200 116
[22/Aug/2016 20:44:13] "POST /worklogs/jobsite-autocomplete/ HTTP/1.1" 200 31
[22/Aug/2016 20:44:13] "POST /worklogs/jobsite-autocomplete/ HTTP/1.1" 200 31
[22/Aug/2016 20:44:13] "POST /worklogs/jobsite-autocomplete/ HTTP/1.1" 200 31
[22/Aug/2016 20:44:13] "POST /worklogs/jobsite-autocomplete/ HTTP/1.1" 200 31
django = 1.9
python = 3.4
django-autocomplete-light (3.1.8)
I was using jQuery v1.11.3
I upgraded to jQuery 2.2.4 and it worked as expected.
This problem is also answered in the issues.
https://github.com/yourlabs/django-autocomplete-light/issues/758#issuecomment-329814124
It happens when you have more than one select2.js in your page.
In my case, i was using crispy forms and i also had {{ form.media }} on the page i removed the variable {{ form.media }} it worked good