I have one django project. It has one function in view.py to process the data from the inputs to give the output for other function. However the processing time for the function is kind of long. I want to fulfill the instant demonstration of the processed output. How could I achieved that? The following processing() function is for the processing purpose. And the output 'user_entries' is for the demonstration in results() as followed.
def processing(request):
import sys
n = []
for topic in Topic.objects.filter(owner=request.user).order_by("date_added"):
entries = topic.entries.all()
m = []
for p in entries:
q = p.text
m.append(q)
n.append(m)
list = []
start(list, n)
request.session['user_entries'] = list
return request.session['user_entries']
def results(request):
data = processing(request)
return render(request, "project/results.html", {"datas": data})
In the start() function of the processing() function. There is one part list.append() to add new output into list. But it seems that the new appended list cannot be transferred and show the instant results in project/results.html?
What you're doing could likely be done a lot more simply.
def results(request):
return render(
request,
"project/results.html",
{
"user_entries": Entry.objects.filter(topic__owner=request.user),
"start_values": "...", # Whatever start is appending...
},
)
Since you have a foreign key from entry to User, you could also use request.user.topic_set.all() to get the current user's topics.
Or, if you actually do need those lists nested...
# ...
"user_entries": (
topic.entries.all() for topic in
Topic.objects.filter(owner=request.user)
),
# ...
Just based on what you're showing us, it seems like your ordering -- for both Topic and Entry -- should probably have a sensible default set in, e.g., Topic.Meta.ordering, which in this case would probably look like this:
class Topic(models.Model):
# ...
class Meta:
ordering = ("date_added",)
# ...
That way, in this and most other cases, you would not have to apply .ordering(...) manually.
Related
I am currently trying to change the name of the "Delete Selected" admin action. I have already effectively override the default (so I can store some data before completely deleting it), but now I want to change the option from the vague "Deleted selected" to something more specific like "Deleted all selected registrations." Or, at least, for it to say, "Deleted selected registrations" like it did before I overwrote the function.
I have so far tried this:
delete_selected.short_description = 'Delete all selected registrations'
But the option is still "Deleted selected." Is there a way to fix this?
Here's my code:
def delete_selected(modeladmin, request, queryset):
"""
This overrides the defult deleted_selected because we want to gather the data from the registration and create a
DeletedRegistration object before we delete it.
"""
for registration in queryset:
reg = registration.get_registrant()
if registration.payment_delegation:
delegate_name = registration.payment_delegation.name
delegate_email = registration.payment_delegation.email
else:
delegate_name = None
delegate_email = None
registration_to_delete = DeletedRegistration.objects.create(
registrant_name = reg.full_name(),
registrant_email = reg.email,
registrant_phone_num = reg.phone,
delegate_name = delegate_name,
delegate_email = delegate_email,
# Filtering out people (with True) who couldn't participate in events because we are only interested in the people
# we had to reserve space and prepare materials for.
num_of_participants = registration.get_num_party_members(True),
special_event = registration.sibs_event,
)
registration.delete()
delete_selected.short_description = 'Delete all selected registrations'
edit: just tried delete_selected.list_display that didn't work either
You can't have it in the function, so I just had to tab it back one space and it worked.
example:
def delete_selected(modeladmin, request, queryset)
code
delete_selected.short_description = "preferred name"
thanks.
My Django project need to acquire one list after processing in one function of views.py.
def acquire(request):
import sys
n = []
for topic in Topic.objects.filter(owner=request.user).order_by("date_added"):
entries = topic.entries.all()
q = entries.text
n.append(q)
return render(request, "projects/topics.html", n)
The list "n" above need to be transferred to another function of views.py for the information in another "results.html" page.
def results(request):
data = XXXX
return render(request, "projects/results.html", {"datas": data})
How could I edit "XXX" in results function to transfer the "n" list?
You can write a utility function that can be used by both views and stores the data for the current session:
def acquire(request):
data = _get_data(request)
return render(request, "projects/topics.html", {'data': data})
def results(request):
data = _get_data(request)
return render(request, "projects/results.html", {'data': data})
# this is not a view, but a utility function
def _get_data(request)
# this will try to use the data generated in a previous request of
# the same session. So the data might be stale by now
if not 'user_entries' in request.session:
n = []
for topic in Topic.objects\
.filter(owner=request.user)\
.order_by('date_added')\
.prefetch_related('entries'): # prefetch avoids the nested queries
for entry in topic.entries.all():
n.append(entry.text)
request.session['user_entries'] = n
return request.session['user_entries']
You can declare the list n outside of the function so you can use it wherever you want, like:
n = []
def acquire(request):
import sys
for topic in Topic.objects.filter(owner=request.user).order_by("date_added"):
entries = topic.entries.all()
q = entries.text
n.append(q)
return render(request, "projects/topics.html", n)
def results(request):
data = n
return render(request, "projects/results.html", {"datas": data})
You have to remember that whatever variable you set, it only lives within the view/function as Django is stateless. That's why you have a database and cookies.
This is how you do it. Unless that list has thousands and thousands of entries, this will be fast.
def results(request):
data = []
for topic in Topic.objects.filter(owner=request.user).order_by("date_added"):
entries = topic.entries.all()
q = entries.text
data.append(q)
return render(request, "projects/results.html", {"datas": data})
If you want to be really fast, you could change the request and work on the database level and create a join. Something along the lines of this (I'm a bit rusty)
data = Entries.objects.filter(topic__owner=request.user).order_by("topic__date_added").values("text")
In my website, I have a model Experiment that contains many Activities. I have a view where people can add or remove Activities from an Experiment.
I show a table with Activities that are a part of this Experiment, and a table of Activities not a part of this Experiment. Users can check which Activities they want to add or remove and use a submit button under the table.
However, when I update the list of choices on one form, the list of choices on the other form reflects this. Am I doing something wrong?
For both adding and removing the Activities to/from the Experiment, I use the same form.
class MultiCheckboxField(SelectMultipleField):
widget = ListWidget(prefix_label=False)
option_widget = CheckboxInput()
class ActivityListForm(Form):
activities = MultiCheckboxField(validators=[DataRequired()], choices=[])
submit = SubmitField("Submit")
def populate_activities(self, activities_set):
activities_mapping = {}
for activity in activities_set:
activities_mapping[str(activity.id)] = activity
choice_tuple = (str(activity.id), activity.question)
self.activities.choices.append(choice_tuple)
return activities_mapping
Here is my view:
def settings_experiment(exp_id):
experiment = Experiment.query.get(exp_id)
remove_activities_form = ActivityListForm(prefix="remove")
add_activities_form = ActivityListForm(prefix="add")
remove_activities_mapping = remove_activities_form.populate_activities(
experiment.activities)
add_activities_mapping = add_activities_form.populate_activities(
Activity.query.\
filter(not_(Activity.experiments.any(id=experiment.id))).all())
return render_template("experiments/settings_experiment.html",
experiment=experiment,
update_experiment_form=update_experiment_form,
remove_activities_form=remove_activities_form,
add_activities_form=add_activities_form,
add_activities_mapping=add_activities_mapping,
remove_activities_mapping=remove_activities_mapping)
Although remove_activities_form and add_activities_form have their options set separately to different lists, they both end up containing a union of their two option lists, which messes up my template rendering. Is there a way to keep them separate or am I screwed?
https://github.com/wtforms/wtforms/issues/284
Solution in the above discussion.
I've got a Django SessionWizardView in which I want to add extra data for the user to take advantage of during the steps. Essentially I want to build a list, and a dict which stores information about the steps once they are complete.
The first step in the wizard allows a user to add information about themselves and at the end allows the option to add another person's details. If this option is selected another, conditional, form is rendered & I'd like to provide them with the option to use the data entered previously.
So during the process_step() method I'm creating a list, and then a corresponding dictionary of data for each step in the process. Initially I had these as class attributes, but feel they would be better suited in a user's session so I've attempted to add them like so;
def process_step(self, form):
form_data = self.get_form_step_data(form)
current_step = self.storage.current_step or ''
data_dict = self.request.session.get('data_dict', dict())
data_list = self.request.session.get('data_list', list())
if current_step in data_dict:
# Always replace the existing data for a step.
data_dict.pop(current_step)
if not isinstance(form, TermsForm):
entrant_data = dict()
for k, v in form_data.iteritems():
entrant_data[k] = v
for k in entrant_data.iterkeys():
new_key = re.sub('{}-'.format(current_step), u'', k)
entrant_data[new_key] = entrant_data.pop(k)
data_dict[current_step] = entrant_data
done = False
for i, data in enumerate(data_list):
if data[0] == current_step:
data_list[i] = (
current_step, u'{} {}'.format(
entrant_data['first_name'],
entrant_data['last_name']
)
)
done = True
if not done:
data_list.append(
(
current_step, u'{} {}'.format(
entrant_data['first_name'],
entrant_data['last_name']
)
)
)
self.request.session['data_dict'] = data_dict
self.request.session['data_list'] = data_list
self.request.session.modified = True
return form_data
After this method is ran my new session keys aren't part of the session. From what I've been reading, this is a valid way of setting session data, but have I made a mistake somewhere?
Of the top of my head, your process_step function call misses the explicit request parm. It's mostly called like this:
process_step(self, request, form, step):
update 0
My def post() code has changed dramatically because originally it was base on a digital form which included both checkboxes and text entry fields, not just text entry fields, which is the current design to be more paper-like. However, as a result I have other problems which may be solved by one of the proposed solutions, but I cannot exactly follow that proposed solution, so let me try to explain new design and the problems.
The smaller problem is the inefficiency of my implementation because in the def post() I create a distinct name for each input timeslot which is a long string <courtname><timeslotstarthour><timeslotstartminute>. In my code this name is read in a nested for loop with the following snippet [very inefficient, I imagine].
tempreservation=courtname+str(time[0])+str(time[1])
name = self.request.get('tempreservation',None)
The more serious immediate problem is that my def post() code is never read and I cannot figure out why (and maybe it wasn't being read before, either, but I had not tested that far). I wonder if the problem is that for now I want both the post and the get to "finish" the same way. The first line below is for the post() and the second is for the get().
return webapp2.redirect("/read/%s" % location_id)
self.render_template('read.html', {'courts': courts,'location': location, ... etc ...}
My new post() is as follows. Notice I have left in the code the logging.info to see if I ever get there.
class MainPageCourt(BaseHandler):
def post(self, location_id):
logging.info("in MainPageCourt post ")
startTime = self.request.get('startTime')
endTime = self.request.get('endTime')
day = self.request.get('day')
weekday = self.request.get('weekday')
nowweekday = self.request.get('nowweekday')
year = self.request.get('year')
month = self.request.get('month')
nowmonth = self.request.get('nowmonth')
courtnames = self.request.get_all('court')
for c in courtnames:
logging.info("courtname: %s " % c)
times=intervals(startTime,endTime)
for courtname in courtnames:
for time in times:
tempreservation=courtname+str(time[0])+str(time[1])
name = self.request.get('tempreservation',None)
if name:
iden = courtname
court = db.Key.from_path('Locations',location_id,'Courts', iden)
reservation = Reservations(parent=court)
reservation.name = name
reservation.starttime = time
reservation.year = year
reservation.nowmonth = int(nowmonth)
reservation.day = int(day)
reservation.nowweekday = int(nowweekday)
reservation.put()
return webapp2.redirect("/read/%s" % location_id)
Eventually I want to add checking/validating to the above get() code by comparing the existing Reservations data in the datastore with the implied new reservations, and kick out to an alert which tells the user of any potential problems which she can address.
I would also appreciate any comments on these two problems.
end of update 0
My app is for a community tennis court. I want to replace the paper sign up sheet with an online digital sheet that mimics a paper sheet. As unlikely as it seems there may be "transactional" conflicts where two tennis appointments collide. So how do I give the second appointment maker a heads up to the conflict but also give the successful party the opportunity to alter her appointment like she would on paper (with an eraser).
Each half hour is a time slot on the form. People normally sign up for multiple half hours at one time before "submitting".
So in my code within a loop I do a get_all. If any get succeeds I want to give the user control over whether to accept the put() or not. I am still thinking the put() would be an all or nothing, not selective.
So my question is, do I need to make part of the code use an explicit "transaction"?
class MainPageCourt(BaseHandler):
def post(self, location_id):
reservations = self.request.get_all('reservations')
day = self.request.get('day')
weekday = self.request.get('weekday')
nowweekday = self.request.get('nowweekday')
year = self.request.get('year')
month = self.request.get('month')
nowmonth = self.request.get('nowmonth')
if not reservations:
for r in reservations:
r=r.split()
iden = r[0]
temp = iden+' '+r[1]+' '+r[2]
court = db.Key.from_path('Locations',location_id,'Courts', iden)
reservation = Reservations(parent=court)
reservation.starttime = [int(r[1]),int(r[2])]
reservation.year = int(r[3])
reservation.nowmonth = int(r[4])
reservation.day = int(r[5])
reservation.nowweekday = int(nowweekday)
reservation.name = self.request.get(temp)
reservation.put()
return webapp2.redirect("/read/%s" % location_id)
else:
... this important code is not written, pending ...
return webapp2.redirect("/adjust/%s" % location_id)
Have a look at optimistic concurrency control:
http://en.wikipedia.org/wiki/Optimistic_concurrency_control
You can check for the availability of the time slots in a given Court, and write the corresponding Reservations child entities only if their stat_time don't conflict.
Here is how you would do it for 1 single reservation using a ancestor Query:
#ndb.transactional
def make_reservation(court_id, start_time):
court = Court(id=court_id)
existing = Reservation.query(Reservation.start_time == start_time,
ancestor=court.key).fetch(2, keys_only=True)
if len(existing):
return False, existing[0]
return True, Reservation(start_time=start_time, parent=court.key).put()
Alternativly, if you make the slot part of the Reservation id, you can remove the query and construct the Reservation entity keys to check if they already exists:
#ndb.transactional
def make_reservations(court_id, slots):
court = Court(id=court_id)
rs = [Reservation(id=s, parent=court.key) for s in slots]
existing = ndb.get_multi(r.key for r in rs)
if any(existing):
return False, existing
return True, ndb.put_multi(rs)
I think you should always use transactions, but I don't think your concerns are best addressed by transactions.
I think you should implement a two-stage reservation system - which is what you see on most shopping bags and ticketing companies.
Posting the form creates a "reservation request" , which blocks out the time(s) as "in someone else's shopping bag" for 5-15 minutes
Users must submit again on an approval screen to confirm the times. You can give them the ability to update the conflicts on that screen too, and reset the 'reservation lock' on the timeslots as long as possible.
A cronjob - or a faked one that is triggered by a request coming in at a certain window - clears out expired reservation locks and returns the times back to the pool of available slots.