Remove created object if user doesn't confirmed it in current session - django

I have a form on web page where an authenticated user can create an order. When they create the order, they are redirected to order_review page. On the order_review page, there is a confirm button and cancel button.
If cancel button is clicked, order is removed. But I can't rely on that user either clicks on confirm or cancel so I would like to handle situations when user leaves this page.
There are two ways in my opinion. Either the order would be deleted when users session expired or when it wasn't confirmed for for example 5 minutes.
def reviewOrder(request, id):
order = get_object_or_404(models.Order, id=id)
if order.type == 'retail':
total = models.Price.calculate_price(order.dry_wood, order.wet_wood, order.briquette, order.stelinka)
context = {'order': order}
context.update(total)
return render(request, 'reviewOrder.html', context=context)
return render(request, 'reviewOrder.html', context={'order': order})
def delete_order(request, id):
order = get_object_or_404(models.Order, id=id)
order.delete()
return HttpResponseRedirect('/')
def confirm_order(request, id):
order = get_object_or_404(models.Order, id=id)
order.confirmed = True
order.save()
if not order.backuped:
models.OrderBackup.objects.create(original_id=order.id,**model_to_dict(order, exclude=['id','customer','backuped' ]))
order.backuped = True
notifications.AdminNotifications.new_order(order)
notifications.CustomerNotifications.orderHasBeenCreated(order)
return HttpResponseRedirect('/')
What would you do?

So one way I've handled this before is to use onbeforeunload (in conjunction with other methods). The idea is to fire off an ajax call to some url in your website that will handle things as the user leaves the current page.
window.onbeforeunload = function(e) {
$.ajax({
url: "/remove_order/",
type: "post",
async: false,
data:{
'orer_id':order_id
}
});
return undefined;
};
So when the user leaves the page by clicking a link or typing a new url it will fire off this ajax call to remove the order or it can check the current state of the order and then do what you need etc.
I last used this to decrement some inventory in a system when it was temporarily taken this helped to free up inventory immediately in most cases but i also had a periodic task that would cleanup unused inventory after some time.
I've had things clean up on session end or another way I've done this before is to use http://www.celeryproject.org/celery task queues and fire off an async task after a period of time
cleanup_stuff.apply_async((somemodel.id,), countdown=timedelta(minutes=15).seconds)
#classmethod
def cleanup_stuff(cls, id=None):
# blah blah create conditions for deletion
cls.objects.filter(*conditions).delete()

Related

How can I called a view within another view django

Currently, I have a view that essentially closes a lead, meaning that it simply copies the information from one table (leads) to another (deals), now what I really would like to do is that after clicking close, the user is redirected to another page where the user can update some entries (sales forecast), I have a view that updates the lead, so I thought that I can do something like below:
#login_required
def close_lead(request):
id = request.GET.get('project_id', '')
keys = Leads.objects.select_related().get(project_id=id)
form_dict = {'project_id': keys.project_id,
'agent': keys.agent,
'client': keys.point_of_contact,
'company': keys.company,
'service': keys.services,
'licenses': keys.expected_licenses,
'country_d': keys.country
}
deal_form = NewDealForm(request.POST or None,initial=form_dict)
if request.method == 'POST':
if deal_form.is_valid():
deal_form.save()
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
## Changing the Forecast Table Entry
forecast = LeadEntry.objects.filter(lead_id=id)
for i in forecast:
m = i
m.stage = "Deal"
m.save(update_fields=['stage'])
messages.success(request, 'You have successfully updated the status from open to Close')
update_forecast(request,id)
else:
messages.error(request, 'Error updating your Form')
return render(request,
"account/close_lead.html",
{'form': deal_form})
This view provides the formset that I want to update after closing the lead
#login_required
def update_forecast(request,lead_id):
# Gets the lead queryset
lead = get_object_or_404(Leads,pk=lead_id)
#Create an inline formset using Leads the parent model and LeadEntry the child model
FormSet = inlineformset_factory(Leads,LeadEntry,form=LeadUpdateForm,extra=0)
if request.method == "POST":
formset = FormSet(request.POST,instance=lead)
if formset.is_valid():
formset.save()
return redirect('forecast_lead_update',lead_id=lead.project_id)
else:
formset = FormSet(instance=lead)
context = {
'formset':formset
}
return render(request,"account/leadentry_update.html",context)
As you can see I’m calling this function update_forecast(request,id) after validating the data in the form, and I would have expected to be somehow redirected to the HTML page specified on that function, however, after clicking submit, the form from the first view is validated but then nothing happens, so I'm the function doesn't render the HTML page
My question how can I leverage existing functions in my views?, obviously, I will imagine that following the DRY principles you can do that in Django, so what am I doing wrong ?, how can I call an existing function within another function in views?
A view returns a response object. In your current code, you're calling a second view but not doing anything with its response. If you just wanted to display static content (not a form that might lead to an action that cares about the current URL) you could return the response object from the second view - return update_forecast(request, id).
But since your second view is displaying a form, you care about what the action for the view from the second form is. The typical Django idiom is to have forms submit to the current page's URL - that wouldn't work if you just call it and return its response object. You could customize the action in the second view, say adding an optional parameter to the view, but the usual idiom for form processing is to redirect to the view you want to show on success. Just as you do in the update_forecast view. Something like this:
messages.success(request, 'You have successfully updated the status from open to Close')
return redirect('update_forecast', lead_id=id)

Prompt to activate user's account and redirect him to another page

I write a control function activate to confirm the User's email and his activating code.
def activate(request, a_code):
"""
Activate User's Account by code from his email.
"""
try:
user = User.objects.get(activatecode__code=a_code)
user.is_active = True
context = {}
return render(request, "user/success.html", context)
time.sleep(5)
return redirect("/")
except DoesNotExist:
context = {}
return render(request, "user/failure.html", context)
After the User successfully activate his account, he will be redirected to the homepage.
Nevertheless, double returns did not work properly as I intended.
How to deal with such a context?
Instead of double return which will not work since second return never reached, you can add javascript redirect to the success template, check this question:
<script type="text/javascript">
setTimeout(function() {
window.location.href = "/";
}, 5000);
</script>
Also you probably can try to use messages framework for messages rendering.
user = User.objects.get(activatecode__code=a_code)
user.is_active = True
context = {}
return render(request, "user/success.html", context) # First
time.sleep(5)
return redirect("/") # Second
Your codes after the first return statement is unreachable. Once you have returned from a function, the execution cursor returns to the caller, any code after that will not be executed.
Thus in your case sleep and second return is never executed.
If you want to redirect the user then you can simply use redirect()
Reference : https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#redirect
your problem is that when the method runs and evaluates the first return, this ends thread execution of this method that is the instructions are after the first return never will be evaluated why don't you can redirection def activate(request, a_code): """ Activate User's Account by code from his email. """ try: user = User.objects.get(activatecode__code=a_code) user.is_active = True context = {} return render(request, "user/success.html", context)
Your code ends here

How can I ignore a field validation in flask-wtf?

I have a form to add an item to my database, which includes two buttons: Cancel and Submit. The problem I have is that when I press the Cancel button with an empty form, I get a Please fill out this field. error instead of returning to my home page (see views.py for logic). So how can I get my app to ignore the DataRequired validators when I press the Cancel button?
forms.py:
class ItemForm(FlaskForm):
id = StringField('id', validators=[DataRequired()]
name = StringField('Name', validators=[DataRequired()]
cancel = SubmitField('Cancel')
submit = SubmitField('Submit')
views.py:
def add_item()
form = ItemForm()
if form.validate_on_submit():
if form.submit.data:
# Code to add item to db, removed for brevity.
elif form.cancel.data:
flash('Add operation cancelled')
return redirect(url_for('home.homepage'))
Your cancel button doesn't really need to be a submit button. You can simply have a normal button which takes the user back to the home page (using a href or capturing the onclick event).
If you still want the cancel button to be a WTForms field, one option would be to override the validate method in the form and remove the DataRequired validators on id and name. The below is untested but may give you a starting point to work from.
class ItemForm(FlaskForm):
id = StringField('id')
name = StringField('Name')
cancel = SubmitField('Cancel')
submit = SubmitField('Submit')
def validate(self):
rv = Form.validate(self)
if not rv:
return False
if self.cancel.data
return True
if self.id.data is None or self.name.data is None:
return False
return True

django-activity-stream actions not displaying

I've just set django-activity-stream up but can't get it to display my actions when I goto the built in template mysite.com/activity/. Yet if I check the admin site I can see the actions have been saved as expected. I am using django-allauth for authentication/authorization
myapp/Settings.py
ACTSTREAM_SETTINGS = {
'MODELS': ('auth.user', 'auth.group'),
'MANAGER': 'actstream.managers.ActionManager',
'FETCH_RELATIONS': True,
'USE_PREFETCH': True,
'USE_JSONFIELD': True,
'GFK_FETCH_DEPTH': 0,
}
myapp/receivers.py
from actstream import action
#receiver(user_logged_in)
def handle_user_logged_in(sender, **kwargs):
request = kwargs.get("request")
user = kwargs['user']
action.send(user, verb='logged in')
In the django-activity-stream views.py it seems models.user_stream(request.user) is returning empty. But I have no idea why.
actstream/views.py
#login_required
def stream(request):
"""
Index page for authenticated user's activity stream. (Eg: Your feed at
github.com)
"""
return render_to_response(('actstream/actor.html', 'activity/actor.html'), {
'ctype': ContentType.objects.get_for_model(User),
'actor': request.user, 'action_list': models.user_stream(request.user)
}, context_instance=RequestContext(request))
Debugging from models.userstream(request.user) it seems I've found where it's returning no results:
actstream/managers.py
#stream
def user(self, object, **kwargs):
"""
Stream of most recent actions by objects that the passed User object is
following.
"""
q = Q()
qs = self.filter(public=True)
actors_by_content_type = defaultdict(lambda: [])
others_by_content_type = defaultdict(lambda: [])
follow_gfks = get_model('actstream', 'follow').objects.filter(
user=object).values_list('content_type_id',
'object_id', 'actor_only')
if not follow_gfks:
return qs.none()
When I check the value at q = self.filter I can actually see all the correct "logged in" activities for the user I passed, however when it gets to follow_gfks = get_model because the user in question isn't following anyone else follow_gfks ends up being None and the query set qs gets deleted on the last line.
Why this works this way when im just trying to view my own users activity feed I have no idea.
Here's what a row from my actstream_action table looks like:
id 1
actor_content_type_id [fk]3
actor_object_id 2
verb logged in
description NULL
target_content_type_id NULL
target_object_id NULL
action_object_content_type_id NULL
action_object_object_id NULL
timestamp 2013-09-28 12:58:41.499694+00
public TRUE
data NULL
I've managed to get the action/activity list of the current logged in user by passing user to actor_stream() instead of user_stream(). But I have no idea why user_stream doesn't work as intended
If it's your user that you want to show the actions for, you need to pass with_user_activity=True to user_stream; if it's for another user, you need to follow them first.

Refresh template in Django

I have a view like this:
def form1(request):
if request.method == 'POST':
form = SyncJobForm(request.POST)
if form.is_valid():
# do something
in_progress = True
return render_to_response('form1.html', {'in_progress': in_progress})
I would like to know how to set it to refresh the template after is done with the view process. Like rendering the page after its done:
in_progress = True
return render_to_response('form1.html', {'in_progress': in_progress})
# after its finished
finished = True
return render_to_response('form1.html', {'finished': finished})
How can I implement something like this? Thanks in advance.
You can't maintain state between page calls on a global basis, so you'll need to store your data in the database. In addition, a view can't negotiate anything with the browser after it has returned a page, so you need to split this into multiple views and spawn a separate thread for the job. Here's a general outline that might help:
def do_something():
my_job = Jobs.get(id=blah)
my_job.in_progress = True
my_job.save()
# Do some stuff here....
my_job.in_progress = False
my_job.save()
def step1(request):
in_progress = Jobs.get(id=blah).in_progress
if not in_progress:
if request.method == 'POST':
form = SyncJobForm(request.POST)
if form.is_valid():
thread.start_new_thread(do_something)
return HttpResponseRedirect(step2)
else:
return render_to_response('form.html', 'form': form)
else:
form = SyncJobForm()
return render_to_response('form.html', 'form': form)
else:
return HttpResponseRedirect(step2)
def step2(request):
in_progress = Jobs.get(id=blah).in_progress
if in_progress:
return render_to_response('in_progress.html')
else:
return HttpResponseRedirect(finished)
def finished(request):
return render_to_response('finished.html')
Then have your page in_progress.html periodically refresh the page. When the job is completed, you can display a status message in finished.html.
There are more sophisticated ways to do this (write Javascript to poll the server periodically), but you're still going to need to write separate views to respond with the appropriate information. In addition, you could use a job management framework like Celery to create and execute jobs, but again you'll still have to create separate views to handle status information.
I am not able to think of doing this without some sort of call back from the client (unless you use some asynchronous server mechanism, something I am not familiar with). One way would be to have the client poll the server periodically after receiving the "in_progress" notification to see if the processing has finished. The server side can be split into two calls, first to handle the POST as shown in your question and another one to find out and report if a given task is finished.