I have a generic ListView which displays all objects from a model and I would like users to be able to choose one object for further processing by storing in session or in another model. What would be the best way to go about this?
views.py
class TranscriptListView(generic.ListView):
model = Transcript
template_name = 'transcript_list.html'
template
{% block content %}
<ul>
{% for transcript in transcript_list %}
<li>
{{transcript.name}}
<p>{{transcript.text}}</p>
</li>
{% endfor %}
</ul>
For selecting something to store in a session, I'd just do a
class SelectTranscriptView(SingleObjectMixin, View):
model = Transcript
def post(self, request, *args, **kwargs):
object = self.get_object()
request.session['selected_transcript'] = object.id
return redirect(...)
This view only accepts POST, since GET requests should be idempotent, i.e. they should not modify any state. Setting a session value is definitely modifying state. This means you'll need to use a form (or a JavaScript function) to POST data to the URL you hook this up to.
More importantly, though: Setting something in the session is not necessarily a good idea at all. Consider an advanced user deciding to open multiple tabs to your site, and trying to select one transcript for one tab, and another in the other tab. This won't be possible if you store the selected thing in the session! Instead, I'd design things so the ID of the object being edited or viewed is always in the URL (as happens with DetailViews and the ilk anyway).
Related
I want to display the contents of a table called recommendation in the interface Django of the user in the morning of each day because I'm collecting recommendations and saving them in a table (each user have his own recommendations of course ) and I want to delete them after he check them.
So I'm doing this but that is going to display the recommendations directly if I refreshed the page.
HTML interface :
<li class="word-bot-sent"><p>Do you want some recommendations today? </p></li>
{% for obj in Recommendation %}
{% if obj.user == request.user %}
<li class="word-bot-sent"><p>{{ obj.title }}</p></li>
<li class="word-bot-sent"><p>{{ obj.text }}</p></li>
{%endif%}
{% empty %}
{% endfor %}
How can I tackle this?
You'll probably want to take a look at Django's time zones docs. You could do something like:
from django.utils import timezone
from django.views.generic import ListView
from .models import Recommendation
class RecommendationListView(ListView):
model = Recommendation
template_name = 'mytemplate.html'
context_object_name = 'recommendations'
def get_queryset(self):
current_hour = timezone.now().hour
if current_hour > 8 and current_hour < 11:
queryset = Recommendation.objects.filter(user=self.request.user)
# force the queryset to be evaluated
eval_query = list(queryset)
# delete the data from the database now that you have them in a list
queryset.delete()
return eval_query
else:
return Recommendation.objects.none()
... but you will have to take into account if your users are in the same time zone as you, and if not, how you can set things up so that they work properly. You'll also have to consider that it's likely that users might try to abuse the system if you make the site timezone-aware/adjusted based on the users' timezones. e. g. they might try to pose as being in a different time zone to get the recommendations earlier.
Also, the above method of deletion isn't really appropriate because if for whatever reason (say if the user's internet connection is finicky) the user doesn't receive the server's response and tries to access the page again, the data have already been removed. I'm sure there is a better solution which avoids this issue. What you would need is some confirmation from the user that they've actually seen the page, or use AJAX to collect an indication of the user viewing the page. You can see some additional discussion on a similar topic in this SO thread.
Around one year ago I started to write my first application in PyQt5, where there are many fields:
I know it's not good-looking, but the main point was to learn PyQt5.
Now I want to make it useable on mobile. Since there are many people after IT studies knowing Java, I think I have a better chance to get the first job knowing Django + Javascript/jQuery. Here is the question:
Each "F1, F2, F3" is a separate widget. The screen on a phone is small, so I think about displaying them one by one. Easiest approach is probably this way (.html), but maybe there is a better one:
{% for field in GoldArrays %}
<p>{{field.text}} <input type="number" name="textfield"> {{field.number}}</p>
{% endfor %}
It's for F3/F4 widget. 'text' will return 200zl, 100zl, etc, number is just a DecimalField.
The thing is I'm very fresh to web development and Django. As I understand I should create a separate template for each widget. I want to collect data from a widget after pressing "next" button and then store it to SQLite database, so the progress will be saved. Should I put sql queries in views.py? What should be in forms.py and models.py? An example of two user inputs is highly appreaciated.
Here is the next question... There is a decent chance, that I'll want to set some rules for many fields, like highlighting value so the user doesn't need to delete the value, or to automatically set 0 in case there is None as input. I know I can do that with JS later, but can I do it with Django? I hope to write a code, that is easy to maintain.
Help please :)
Using views (controllers in Django) you can add context data.
It has next structure:
{% for item in form_set %}
{{ item }}
{% endfor %}
Jinja2 is templating language, so all vars from backend you must write in brackets
{{ each_var_from_django }}
View will be next:
class CreateOrderView(LoginRequiredMixin, CreateView):
template_name = 'dashboard/index.html'
success_url = reverse_lazy('namespace:url')
def get_context_data(self, *args, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form_set'] = Model.objects.filter()
return ctx
I have a django app and implemented payment gateway functionality.
Now what i was trying is
After successful transation, need to do redirect user to another page that shows the response details so i am using HttpresponseRedirect to redirect the page, but i have the variable response in the view that contains reponse details, so i need to send this variable as the context to the redirecting url that renders template, so that i can use that response variable to display the results.
so for the above functionality, i got three methods
Sending the variable as the query parameter(which is not safe in this method because it is sensitive credit card transaction details)
Using session framework, which is not working in my case, the code is below
Django messaging framework(which is not so useful in this case)
views.py
def payment(request):
amount = 1
if request.method == 'POST':
form = CreditCardForm(request.POST)
if form.is_valid():
data = form.cleaned_data
...........
...........
response = stripe.payment_purchase(amount,data)
request.session['response'] = response
return HttpResponseRedirect(reverse('paygate:payment_success'))
else:
form = CreditCardForm(initial={'number':'4242424242424242'})
return render_to_response('payment/stripe_payment_form.html',{'form': form,
'response':response,},
context_instance=RequestContext(request))
payment_success url view
class PaymentSuccess(TemplateView):
template_name = 'payment/payment_success.html'
I tried to access response variable in the template, but displaying nothing
payment_success.html
{% extends "base.html" %}
{% block main_title %}Payment{% endblock %}
{% block title %}Success{% endblock %}
{% block content %}
<h1>Response Details</h1>
<p>Your status is <span>{{ request.session.response }}</span></p>
{% endblock %}
So can anyone please let me know the various different safe and secure ways to send context variables(in this case credit card payment details) to redirecting url using HttpResponseRedirect method
I think there is a 4. possible item in your list, that I suggest to use.
The safest and most pragmatic way of accomplish what you want is to have a successful view showing the actual results stored in your database.
The idea behind this is:
payment view is an action that a user performs on your database.
payment_success view is a way of telling the user that the action was performed successfully and with the the input the user desired.
Likewise, the best way of showing that the action is correct is to show its result on the database, i.e. what it is now stored on the database regarding that action.
I have this models in Django:
News
Comments
Reactions
Relations are:
a News has various Comments
a Comment has various Reactions
The problem is the user (in request / session): the user may subscribe to a reaction, or a comment; he may be logged in or not. (it's a foo example, it doesn't have much sense)
I can't do in template:
{% for reaction in this_news.comments.reactions %}
{{ reaction.name }}
{% if reaction.user_subscribed %} #reaction.user_subscribed(request.user)...
You have subscribed this reaction!
{% endif %}
{% endfor %}
Problems are:
I can't call the method in the template with a parameter (see the comment above)
Models don't have access to request
Now i'm calling an init_user method in News Model, passing the request. Then i have the same method in Comment and Reaction model, and i have to set the user_subscribed property cycling the children of each model.
Isn't there a smarter way to do this?
EDIT: thanks to the Ignacio's hint about using custom tag i'm trying to do a generic mode to pass the user (avoiding the use of closures because i don't know how to use them atm):
def inject_user(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, method_injected, user = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r tag requires exactly three arguments" % token.contents.split()[0])
return InjectUserNode(method_injected, user)
class InjectUserNode(template.Node):
def __init__(self, method_injected, user):
self.method_injected = template.Variable(method_injected)
self.user = template.Variable(user)
def render(self, context):
try:
method_injected = self.method_injected.resolve(context)
user = self.user.resolve(context)
return method_injected(user)
except template.VariableDoesNotExist:
return ''
When i use it {% inject_user object.method_that_receives_a_user request.user %} i come to this error 'str' object is not callable in method_injected(user); how i can fix that?
Write custom template tags that take the user and set a context variable to indicate presence or absence of the criterion.
I've resolved it in a less elegant way, but it worked for me.
I've created a sort of singleton in my User defined class, with a property that i set in every view i need it.
The property is User.current.
Then, inside the models, where i need that i get the current user looking in User.current.
For one of my models, I want to show extra content in the change_form. Basically, my model looks like this:
class News(models.Model):
...
class NewsFromSource(models.Model):
news = models.ForeignKey(News)
...
I want to add a 'search' button that, when clicked, triggers a web service request to an external news source, pulls down the available content, and lists all the news pieces contained. The user can then select one of the pieces to "attach" to the News currently edited in the admin interface (i.e. create a new NewsFromSource based on the content downloaded through the web service).
I am done with the web service. What is the best approach to implementing the search-button, list display for the results (I have a view and template that work, need to get those into the form somehow) and the saving part?
What I ended up doing is the following:
1)
I created a view for fetching search results, which boils down to this:
#/myproject/admin/views.py
#never_cache
def news_search(request):
#...query web service
if 'q' in request.POST:
search_term = request.POST['q']
else:
search_term = ''
news = NewsSearch()
news.search(search_term)
return render_to_response( 'news_search_results.html',
{ 'q': search_term,
'news': news.result_list,
'page': page,
'page_left': news.page_left,
'page_right': news.page_right}
)
2) I mapped the view:
#/myapp/urls.py
...
url(r'^myapp/news/search/$', views.news_search),
3) I extended change_form.html for the news model with the following code:
#/myproject/templates/admin/myapp/news/change_form.html
{% extends "admin/change_form.html" %}
{% block after_field_sets %}
...
{% csrf_token %}
<input type="text" name="q" id="news-search-term">
<div id="news-search-results"></div>
...
function submitSearchForm() {
$.post("/myapp/news/search/",
{ 'q': $('#news-search-term').val(),
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val() },
function(data){
$('#news-search-results').html(data);
}
);
}
{{ block.super }}
{% endblock %}
4) I created an html template for displaying the results (news_search_results.html, see 1)
So basically I am sending an AJAX request from the admin page to a custom view to retrieve results from the webservice which then are displayed in a div.
Each element in the results list has a button that sends another request that stores the element with the news id as a ForeignKey.
I have no idea whether this is particularly against Django principles. But it seems to work alright.
Suggestions on doing this in a more "Djangonian" way are welcome.
We'll assume you have a related News model. Add that field to raw_id_fields of the modeladmin we're going to hack, then:
Overload the change_form template for this model, extend admin/change_form.html in admin/yourapp/yourmodel/change_form.html
Add javascript in that template to:
Hide the input and magnifier icon from the news raw id field form raw, you can do that in css too
Add something like a span with a button style in that form row that will open a popup when it is clicked
The popup it should open should be your working view/template with a form to select the news
When the user selects a news, the popup should do an ajax post request to get the news id, and close itself
the value is set to the raw id field input that is hidden, this is pretty tough but fear not someone (disclamer: I) published an article with the whole technical details, also found another one but I didn't test it
It's going to be quite some work. Patience and perseverance will be your best qualities for this mission B)