I'm new to Django and trying to implement a voting system between two images. However, it looks like the page is being cached or something because when I refresh it, some values are wrong. I have no cache setup in my Settings.
Here is the View:
def rate(request, type):
photos = Photo.objects.order_by('?')[:2]
c = Context({"photos": photos, "type": type})
return render_to_response("base_rate.html", c)
and the template:
{% extends "base.html" %}
{% block body %}
<div class="photo">
<img src="{{photos.0.photo.url}}" alt="Photo" />
Vote
Flag
</div>
<div class="photo">
<img src="{{photos.1.photo.url}}" alt="Photo" />
Vote
Flag
</div>
{% endblock %}
Some pages will contain wrong info for the objects. Here is an example source that I am getting:
<div class="photo">
<img src="/img/rate/16photo1.jpg" alt="Photo" />
Vote
Flag
</div>
<div class="photo">
<img src="/img/rate/17photo2.jpg" alt="Photo" />
Vote
Flag
</div>
The second Vote href should be "/rate/vote/17/16" and the flag href should be "/rate/flag/17" but something is going wrong and I am getting inconsistent data.
Any ideas?
Taking a look at this in some of my code, I have this in my template:
{{ mytable.0.pk }}
{{ mytable.1.pk }}
{{ mytable.0.pk }}
{{ mytable.3.pk }}
And I get this output:
91596
54774
156800
23593
Odd, until you consider that django executes database queries very lazily. This is what shows up in my mysql log for one page load:
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1 OFFSET 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1 OFFSET 3
Each time you use the dot notation, it is executing an entire new query. I'd suggest modifying your code like so:
def rate(request, type):
photos = list(Photo.objects.order_by('?')[:2])
c = Context({"photos": photos, "type": type})
return render_to_response("base_rate.html", c)
Because the list() is forcing an evaluation, it will execute the query right then and there. In addition, the data for both of those items is already cached, so there is no reason to hit the database again. You should be good to go.
order_by('?') means that the list is ordered in random order, so {{ photos.0 }} will be different each time you load the page.
Also:
Vote
^^^ ^^^
Looks like that's probably not correct.
Django doesn't cache these sorts of things by default. Make sure that your browser/isp/etc. isn't caching it.
It looks like your database query isn't returning what you're expecting. Check that directly via your debugger or with print statement debugging if you have to.
That said, you really need to think long and hard about your app design. Using a GET request to make stateful changes to your app is an incredibly bad idea. Especially the way you are doing it. You need to change those links to POST requests to a single form. Otherwise, you'll find that random web spiders destroy your application.
Related
I have a form I'm working with in Django.
I have a built in error message I'm trying to get to render on the form.
My first step is to get the error message to render on the form and then I will go into the function and tweak when it shows up.
My problem emerges when it comes to doing it in python.
Normally, my preferred way would be to JQuery for the footer and use JavaScript to append/prepend the HTML. Then set it to show/hide based on conditionals.
However, for this I am wanting to do it in Python to make it easier for the people working w/ me.
Here's an example of the error message HTML I would like to use for appending to something else in JS.
error_field.append('<em for="name" class="form-error-message text-danger">');
Here is an example of the Django Code Block I would like to add it within
{% block form-footer %}
{{ block.super }}
{% endblock %}
What is the easiest way to accomplish this within Python/Django? To be clear, I can figure out the conditional stuff myself. Just the rendering of the specific HTML/CSS error class I have already created. I should be able to do the conditional/function part of this myself.
I can just show you an example, this is a part of my project
views.py
try:
user=User.objects.get(username=username)
except:
messages.info(request,'username does not exist')
return redirect('login')
return render(request,'users/login-register.html')
html
{% if messages %}
{% for i in messages %}
<div class="alert alert--{{i.tags}}">
<p class="alert__message">{{i}}</p>
<button class="alert__close">x</button>
</div>
{% endfor %}
{% endif %}
You can use this anywhere in your html page. This is a common page, and everything in here is extended. And of course this is an example similar to your problem. Check it out if you want
I am trying to hide a content when a user is visiting his own profile. I tried the code below but it didn't work. What could be wrong.
{% if request.path == "/account/users/{{ request.user.username }}/" %}
{% else %}
<img src="https://tyllplus.com/static/arrow-orange-down-vector-1.png" width="30" height="30">
{% endif %}
(Advanced) string processing should not be done in the template. Especially not with URLs, since you might later want to change the view. Even if you manage to get it work, if you later have a prefixed path, it can start failing. This method would also heavily depend on the format of the URL: if you later specify a URL where you use the id instead of the username, then you will need to look for all all URL processing that depends on this format. This is not elegant design.
Of course simple processing is no problem. For example adding comma separators to a number, etc. is typically handled by template tags. But URLs - in my opinion - do not really fit in that category.
You better encode this logic in the view (or make sure that you easily can detect it with elements from the view).
For example for a DetailView:
from django.views.generic.detail import DetailView
from django.contrib.auth.models import User
class UserDetailView(DetailView):
model = User
context_object_name = 'my_user'
template = 'user_detail.html'
We know that the my_user variable will carry the User object ot display, so then we can verify with:
{% if my_user != request.user %}
<!-- show something -->
{% else %}
<!-- show something else -->
{% endif %}
I'm trying to add one more action to flask-admin forms.
It has to increment rating (+1) and it works with batch action, but not with single. Please help me find the bug, I've spent a lot of time trying to make this thing work properly.
Here's the code:
I made an html template in templates folder - custom_lists.html
{% extends 'admin/model/list.html' %}
{% block list_row_actions %}
{{ super() }}
<form class="icon" method="POST" action="/admin/user/action/">
<input id="action" name="action" value="approve" type="hidden">
<input name="rowid" value="{{ get_pk_value(row) }}" type="hidden">
<button onclick="return confirm('Are you sure you want to approve selected items?');" title="Approve">
<span class="fa fa-ok glyphicon glyphicon-ok"></span>
</button>
</form>
{% endblock %}
this succeeded with an icon on the list, but if i click to it - it says
Not Found
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
added to templates folder and added to AdidasView class this:
list_template = 'custom_list.html'
#action('approve', 'Approve', 'Are you sure you want to approve selected items?')
def action_approve(self, ids):
try:
query = Adidas.query.filter(Adidas.id.in_(ids))
count = 0
for image in query.all():
image.rating += 1
count += 1
db.session.commit()
flash(ngettext('Item was successfully approved.',
'%s items were successfully approved.'%count,count))
except Exception as ex:
if not self.handle_view_exception(ex):
raise
flash(gettext('Failed to approve items. %(error)s', error=str(ex)), 'error')
I have not changed the template but I have done it differently as following by setting the column_extra_row_actions variable and defining the action_play function
column_extra_row_actions = [
EndpointLinkRowAction('glyphicon glyphicon-play', 'event.action_play')
]
#expose('/action/play', methods=('GET',))
def action_play(self, *args, **kwargs):
return self.handle_action()
This solution does not seem to apply to this example, but I also struggled with a case where I received a 404 when I using an action on one item via the button, while the batch action worked as expected.
After taking a look at the JS for the batch action I realized that the two HTML forms for individual actions and batch actions are practically identical. The only difference is that when using batch actions there may be more input fields in the form. That implies that if you get a 404 on one, but not the other, there must be an error in your HTML.
In my case I was not aware that Flask-Admin addresses models_with_underscores_in_their_name as modelswithunderscoresintheirname. Therefore instead of
<form class="icon" method="POST" action="/admin/mymodel/action/">
my erroneous code was
<form class="icon" method="POST" action="/admin/my_model/action/">
Note the difference in the action field.
With this change I was able to use the #action API as explained in the Flask-Admin docs.
I'm trying to find an elegant solution without recourse to using JQuery or JS. Is there anyway that one can perform a select all on fields that are options in a model?
I'm not so keen to use: django checkbox select all
I've seen it hinted at: https://groups.google.com/forum/#!topic/django-users/dzdiZ9TLR5g
But never been able to find anything that would easily allow me to provide a select all directly from Django. Does anyone know if this is possible to switch on? Or is JS the only way to perform this?
I note this answer earlier: select all rows in django_tables2
But is there a way to avoid this approach because I may not know what why fields are - hence, if I have more than one field on each page - i.e. multiple names.
Here is my easy solution with multiple Forms and multiple Fields :
{% for form in formset %}
<div>
{% for field in form %}
{{ field }}
{% for check in field|slice:":1" %}
<input type="checkbox" onClick="toggle(this,'{{ check.name }}')"/>
Select All
{% endfor %}
{% endfor %}
</div>
{% endfor %}
Each checkbox of one Field has the same name - so js can work with it.
Note that all the fields of this example form are checkboxes.
JS Code :
<script type="text/javascript" >
function toggle(source,name) {
checkboxes = document.getElementsByName(name);
for (var i = 0,
n = checkboxes.length; i < n; i++) {
checkboxes[i].checked = source.checked;
}
}
</script>
I extended this solution for django :
How to implement "select all" check box in HTML?
Any solution you write within Django would involve overriding widget renders to output html that included javascript/jquery anyway. I don't think there is any getting round it.
Edit: to answer your comment, the way I would personally do it is create a SlaveCheckboxWidget that could do something as simple inherit from the standard checkbox widget but change the css class name to "slave-checkbox" or similar, then have a MasterCheckboxWidget that includes a bit of jquery to select all (".slave-checkbox") and toggle them.
More on customising django widgets here
I am using Tornado and I have the following code:
class UserHandler(RequestHandler):
def get(self):
user = self.get_argument("username")
self.set_cookie("user", user)
out = tableize(user)
self.render('chat.html',table=out)
now, chatter.html looks like this:
<iframe src="{{ static_url('mess.html') }}" width="500" height="400"></iframe>
where mess.html is:
<div id="chat">
{% for x in table %}
<b> x </b>
{% end %}
</div>
My question is, how do I pass the 'table' argument to mess.html? I can't figure out how to make it display properly.
Have a look at {% include %} in the Tornado docs, it might do what you are trying to achieve. Instead of using an iframe, directly do {% include "mess.html" %}.
If you want to keep the independent frame so you can refresh individually, you have to consider the iframe being a separate request. As such, you also have to provide its own RequestHandler where you get your cookie and then generate the table for your user. You then set the iframe src to be the URL you chose for this RequestHandler.