I am working on a reverse blog project where users can like and comment.
Although I successfully implement the like button to work, But it refreshes the page.
My problem is I am trying to convert it to rather use Ajax to power the button.
And to as well uses a flag to decide which button to be shown, like or unlike.
Please I need help or the logic to guide me on converting the button to work on using Ajax
Please Note: I use pagination and the like button is on the list view and detail view (CBV).
Thank you in advance.
here is my view for the button
here is my model
here is my template rendering
Set a unique id for each like button if you have multiple like buttons. Bind the click event to JS function in which you will create an ajax call. Pass the ID of your model object (to increment likes count) to your JS function which will be passed in your ajax call to your view. Specify the URL of your view at which your like increment function resides.
Below is the implementation of ajax call on button click in django
https://stackoverflow.com/a/13733855/11979793
UPDATE: Class based view changes for the ajax
In your class-based view function:
Accept the parameters:
model_id = json.loads(request.POST.get('param_name')) # model_id could be your post ID to increase the likes
instead of render return JSON response for ajax:
return JsonResponse({
'like_count': model_to_dict(total_likes), # if you want to display total likes
'success': True
})
You can use total likes in success function of ajax to display it in your template.
P.S. import json at start of the file
UPDATE: example class-based view to handle ajax POST request
class myClassView(View):
template_name='index.html'
def post(self,request): # overriding the post method
myparam = json.loads(request.POST.get('paramFromAjax'))
# perform your actions here
# make a dictionary/context say mydic and pass parameters in that
return JsonResponse({
'paramToAjax': mydic,
'success': True
})
Related
So I'm designing a website with Django that does some heavy scraping based on user input.
This can take up to 5-6 secs and while I am working on cutting that down I would like for some kind of a loader to show up while the backend is scraping.
I have put a loader as you normally would using CSS and JavaScript inside the template but that only pops up when the template is actually loading and not when the view is scraping to gather data for the template.
Tried this in Django:
def scrape(request):
render(request,'loader.html')
*do scraping*
return render(request,'results.html',scraped_data)
The method I would use to solve this is to fire an async function within the scrape view.
#shared_task
def do_the_needful():
return "hello I am doing the needful"
def scrape_result(request, scrape_id):
result = AsyncResult(scrape_id).get()
# convert result to json or some other web format
return result_as_json
def scrape(request):
scrape_request_id = do_the_needful.submit()
return render(request, "scrape.html", context={"scrape_request_id": scrape_request_id}
Then within the HTML you'll need to create some Javascript which will perform Ajax requests to the scrape_result view using the scrape_request_id in the context.
In my base template I want to have a search text box with a submit button on the top of every template. My button name is 'searchbutton'
I put it in a form with get method
I want to use this for all views in my application
I have a view with 2 more forms , one of theese has pagination with page buttons
I tried:
if ('searchbutton') in request.GET:
but this is true even user change pages on pagination.
How can I know when user clicked the search button to filter rows as I want?
Thanks in advance
Kostas
If you are defining all your forms as django.forms.Form and not just as pure HTML, you should be able to handle it in your view.
E.g.
class FooView(generic.FormView):
def post(self, request):
search_form = SearchForm(request.POST)
other_form = OtherForm(request.POST)
if search_form.is_valid() and search_form.has_changed():
# Handle Search Form here.
elif other_form.is_valid() and other_form.has_changed():
# Handle Other Form here.
HOWEVER! If this is a Search Function I suggest that instead of handling the logic on every view, you instead make the form submit to a specific view/url each time.
E.g. you create a form that submit to /search?q= where q is your query. And then you only create a single SearchView that handles this logic.
I was wondering if someone could help me.
I want to be able to click on customer and locations be based off of the certain customer, being a dependent dropdown. This information is coming from a database, hence the queries in the following code.
This is my form function for both customer and location
class CustomerPick(SubForm):
customer = QuerySelectField(u'Customer',
get_label=u'sCustomer',
query_factory=lambda :
(TCustomer.query.order_by(TCustomer.sCustomer)),
validators=[DataRequired(),])
location = QuerySelectField(u'Location',
get_label=u'sLocation',
query_factory=lambda :
(TLocation.query.order_by(TLocation.sLocation)),
validators=[DataRequired(),])
Here is the view portion
#route('new/', methods=['GET', 'POST'])
def new(self):
form = CustomerPick()
if form.validate_on_submit():
This is a picture of the dropdown also for reference, if there is anything else needed for you guys to have a go please let me know. Thanks in advance!
Photo
I don't quite get your question but you want to be able to click a user and populate the dropdown based on the location?
This involves some Ajax sending data back and forth.
I'll give you a minimized version of code snippet (not tested).
// front-end - this handles user behavior in dropdown. When a user changes a value
// in a user drop down, it will send a request to your Flask view function.
$("#user_drop_down").change(function () {
let user_identifier = this.value;
$.ajax({
type: "GET",
url:/url_to_flask_view_function/,
data: {user_identifier: user_identifier},
success: function (resp) {
$('#your_designated_div_for_both_dropdowns_div').html(resp.data)
}
});
});
# back-end - this receives the request sent from front-end and process the Flask-WTF
# form options so that it can render different options in the dropdowns. In this view
# function, we will return jsonified template with newly processed form_object
# instead of rendering the option data. You can return the json with only the data
# but it involves more javascript parsing and may be difficult for you.
#app.route('/url_to_flask_view_function/')
def form_processing():
user_identifier = request.args.get('user_identifier)
# now we've gotten the user_identifier, you will need to query. Below query is totally made up.
query_to_where_location = Location.query.filter(Location.user_identifier= user_identifier).first()
# your query result will not be in a tuple format
# if your query result is like this "locA, locB, locC, locD", you need to process
# it so that you make [('locA', 'locA'), ('locB', 'locB').......]
form_object = MyForm()
form_object.location.choices = processed_list
return jsonify({"data":render_template('template_that_contains_your_drodpdowns.html',
form_obj=form_obj)})
<!-- HTML piece, you should've had this already but make sure to specify your fields in HTML following Jinja2 synthax.-->
<form>
{{form_object.user}}
{{form_object.dropdown}}
</form>
In conclusion, the idea here is that you catch user behavior using .change, then based on the change, you will send request with user_identifier to server side. Once it reaches server-side, you will make a query into the DB and render the same template again with differently processed forms.
The best way to go about doing this is that, once you get the user_identifier into your view, you make query and return jsonified location object, then in your success block, you would alter the of that dropdown input element.
Let me know if you have more questions.
I will try to describe problem:
In HTML i have some AJAX call to, lets say, URL getMetaData (this is function in views.py). I that function I check POST dictionary to check is all values there. If not i want to redirect to main page ("main.html"). This main.html is rendered in function main(request) in same views.py file.
When i do this:
def main(request):
return render(request,'main.html')
def getMetaData(request):
if dictionary not valid:
return main(request)
This not working... main function is called but page stays the same.
A redirect in an ajax call will not necessary change the page, and in any case it's not a good idea to mix POST and GET like that. I suggest that you handle it all in the ajax call and redirect there instead, so your django view would be something like:
def getMetaData(request):
if is_invalid(request.POST):
return redirect_url
else:
return None
And the jquery:
$.post(post_url, data, function(new_url) {
if (new_url== null)
do_stuff();
else
window.location.replace(new_url);
});
The problem is that you do this with an AJAX call. Your Python code should work (at least, with this little example I don't see why it wouldn't), but the HTML of your home page will be the data returned to your AJAX call. There is no reason why your browser would then show it as the current page.
If you want to do something different depending on the result of the AJAX call, you should do it in Javascript. Can you show us that?
I'm trying to integrate Mozilla Persona (browserid) into a Pyramid application. The login process is:
user can login on any page by clicking on the login button
a popup then shows a login form
when the users enters correct login/password, an ajax call is made by the popup to a Pyramid view that checks users credentials, and calls Pyramid remember function if the check succeeded
the browserid javascript code then reloads the current page
Now I want to handle the case of a new user subscribing to the web app and present a new view asking for a few more details (desired username, etc).
Since the "remember" function is called by an ajax call from the popup, I cannot redirect the user the the "/newuser" page.
So every view needs to redirect new users to the "/newuser" url whenever the remembered browserid has no corresponding user in the database.
Is there a way to intercept user requests before calling a view to call the "new_user" view instead? Or maybe my authentication approach is fundamentally incorrect and I should rely on another approach?
One way to do this would be to create an exception that should be raised when the user is created, and use this exception as the context of a view that would redirect to the new page.
class NewUser(Exception):
pass
#view_config(context=NewUser)
def new_user_exception(request):
return HTTPFound(request.route_path('new_user'))
Make sure the exception is raised during the first request after the first login (after having created the user object, for example), and the user will be redirected to the right page.
You could also put the code for the welcome page directly in new_user_exception, but without redirection, this page would have the url asked by the user, whatever it was.
Another solution would be to tweak how the persona part is done. For that, I'm going to guess you are using pyramid_persona (I'm the writer :) ). If not, what I'm saying will still apply, and will be even simpler to do.
What you could do is :
Change the login view so that it includes in the response a boolean saying whether this is the first login or not.
Change the javascript to check this boolean, reload the page if it's not the first time, and redirect to the welcome page if it.
The code for the login view can use pyramid_persona's login view like this :
from pyramid_persona.views import login
#view_config(route_name='login')
def new_login(request):
response = login(request)
if response.status == 200: #the login worked
# tweak the response
return response
EDIT : There's now a part about this in pyramid_persona's documentation : Do extra work or verification at login.