Change CSS stles from view in Django - python

Sorry if this is an obvious question, I am new to django and still learning.
I am creating a website that contains 6 images in total. The images in the website should remain invisible until its image id is passed from views.py.
I have a template index.html page and view that loads when this url is accessed localhost/imageid
What I need now is to make the image visible whenever its url is access. So for instance if a user goes to localhost/1. QR code 1 should be made visible. I am also storing the state of all access images. So if the user accesses the website again and goes to localhost/2 it should make image 1 and 2 visible. I am using sessions to store the state. I just need a way of making the images visible.
Thankyouuuu

Depends so a basic view would be:
from django.views.generic import TemplateView
class MyView(TemplateView):
template_name = 'my_html.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['img_id'] = self.kwargs.get('pk') # this is whatever the variable is named in the URL.
return context
html would be something like this.:
<body>
{%if img_id == 1 %}
<img src="image1path">
{%elif img_id == 2 %}
<img src="image2path">
{% endif %}
</body>
A better way would be to store the images in a database and get the image paths from a model, then you would get that in the context and reference it in the template instead of having if statements.

Related

Display a picture via Django saved on mysql database

I want to display a picture with Django, which is already saved on a mysql database. In all Methods I found people used models.Imagefield(upload_to='path'), but I think this will save the file into this directory and people from other computers won´t have access later.
So the question is, how do I access the database directly and display the picture without saving it in between?
I already managed to do this in python, but I am not quite sure how to implement the code into the models.py.
Something like this was my approach :
class mysqlpicture(models.Model):
#mysqlpic=something?
def openpic():
connection = pymysql.connect(user='root', passwd='***',
host='localhost',
database='db')
cursor = connection.cursor()
sql1='select * from Pictures'
cursor.execute(sql1)
data=cursor.fetchall()
mysqlpic=io.BytesIO(data[1][0])#one means second element of column zero
#img=Image.open(mysqlpic)
#img.show()
cursor.close()
return mysqlpic
and then I tried in the views.py to give mysqlpicdirectly to the httpresponse like this:
def MysqlView(request):
query_results = mysqlpicture.objects.all()
template = loader.get_template('polls/pic.html')
context = {
'query_results': query_results,
}
return HttpResponse(template.render(context, request))
using a template pic.htmlto insert a picture like:
{% for n in query_results %}
<mysqlpic src="{{ n.mysqlpic.url }}" />
{% endfor %}
Has someone an idea how to to this in the right way?
Yes, using ImageField does allow people from other computers to access it later. It inherits all attributes and methods from FileField which uploads the file into the server in the path specified in upload_to and also saves this path into your database to keep its reference. All of that happens when you call the save() method in your model instance.
Then, you can create the url to build a link by calling your_instance.image_field.url in your template. Also remember to have a look at MEDIA_ROOT and MEDIA_URL which respectively tells Django the server root path for saving your files and the url that handles the media served from MEDIA_ROOT.
You can use BinaryField for this purposes.
But as stated in the django documentation:
Although you might think about storing files in the database, consider that it is bad design in 99% of the cases.
from django.db import models
class MysqlPicture(models.Model):
mysqlpic = models.BinaryField()
# ...
And then to display in the template you can convert binary data to base64:
from base64 import b64encode
def mysql_view(request):
query_results = MysqlPicture.objects.all()
template = loader.get_template('polls/pic.html')
context = {
'images': [b64encode(obj.mysqlpic) for obj in query_results],
}
return HttpResponse(template.render(context, request))
Template:
{% for image in images %}
<img src="data:;base64,{{ image }}">
{% endfor %}

how to specify a page title in a django views.py file using a context variable?

I am trying to specify a page title that shows up in the browser tab within a views.py file for a class based view. I am working with a file that uses a base template html page for many different pages where I am trying specify the title using something such as:
{% block title %}{{ view.build_page_title }}{% endblock %}
in the views.py file I am trying something like this:
class ExampleReportView(BaseReportView):
def build_page_title(self):
return 'Example Page Title'
This does not seem to be working. I am an absolute beginner in Django Python. Thanks for any help!
You don't pass values to the template by defining arbitrary methods on your view class; the template has no access to the view at all.
Instead, the view class will call its own get_context_data to determine the values to pass to the template; you can override that and add your own value.
class ExampleReportView(BaseReportView):
def get_context_data(self, *args, **kwargs):
data = super(ExampleReportView, self).get_context_data(*args, **kwargs)
data['build_page_title'] = 'Example Page Title'
return data
Of course, you can add as many values as you like inside that method.

How to split django apps if shared view

There is a common case I encounter, where I can't find a way to split apps.
The case is when a info of two models is related and needs to be in the same template
An example speaks 1000 words: (2 models - pages + comments).
# models.py
class Page(models.Model):
title = models.CharField()
content = models.TextField()
class Comment(models.Model):
page = models.ForeignKey('Page')
content = models.TextField()
# url.py
...
url(r'^page/(?P<page_pk>\d+)/$', views.ViewPage, name='page-view-no-comments'),
url(r'^comment/(?P<comment_pk>\d+)/$', views.ViewComment, name='comment-view'),
url(r'^page-with-comments/(?P<page_pk>\d+)/$', views.ViewPageWithComments, name='page-view-with-comments'),
...
# views.py
def ViewPage(request, page_pk):
page = get_object_or_404(Page, pk=page_pk)
return render(request, 'view_page.html', {'page':page,})
def ViewComment(request, comment_pk):
comment = get_object_or_404(Comment, pk=comment_pk)
return render(request, 'view_comment.html', {'comment':comment})
def ViewPageWithComments(request, page_pk):
page = get_object_or_404(Page, pk=page_pk)
page_comments = Comment.objects.filter(page=page)
return render(request, 'view_page.html', {'page':page,'page_comments':page_comments'})
In this situation, splitting to Page app and Comment app is problematic, because they share a view (ViewPageWithComments) and url.
My options are:
1) Create an Ajax call to comments, which has crawling problems although Google might have fixed it lately.
2) Create a method of page that calls a method in the comments app that returns html with the comments content. If the method needs more arguments I also need to write a custom filter tag.
3) Decide not to split...
Am I missing something and there's another option? When would you prefer (1) vs (2) ?
Note - I created a very simple example to keep the problem general.
You don't need to split anything, you have the pages, and comments have a foreign key to that so you can just iterate over the pages comments
{% for page in pages %}
{% for comment in page.comment_set.all %}
{% endfor}
{% endfor %}
If you want to be able to use the same template for a version of this page without comments you can just wrap the comment for loop in an {% if show_comments %} statement

Django pass render_to_response template in other template

this is probably a question for absolute beginners since i'm fairly new to progrmaming. I've searched for couple of hours for an adequate solution, i don't know what else to do.
Following problem. I want to have a view that displays. e.g. the 5 latest entries & 5 newest to my database (just an example)
#views.py
import core.models as coremodels
class LandingView(TemplateView):
template_name = "base/index.html"
def index_filtered(request):
last_ones = coremodels.Startup.objects.all().order_by('-id')[:5]
first_ones = coremodels.Startup.objects.all().order_by('id')[:5]
return render_to_response("base/index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
Index.html shows the HTML content but not the content of the loop
#index.html
<div class="col-md-6">
<p> Chosen Items negative:</p>
{% for startup in last_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
</div>
<div class="col-md-6">
<p> Chosen Items positive:</p>
{% for startup in first_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
Here my problem:
How can I get the for loop to render the specific content?
I think Django show render_to_response in template comes very close to my problem, but i don't see a valid solution there.
Thank you for your help.
Chris
--
I edited my code and problem description based on the solutions provided in this thread
the call render_to_response("base/showlatest.html"... renders base/showlatest.html, not index.html.
The view responsible for rendering index.html should pass all data (last_ones and first_ones) to it.
Once you have included the template into index.html
{% include /base/showlatest.html %}
Change the view above (or create a new one or modify the existing, changing urls.py accordingly) to pass the data to it
return render_to_response("index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
The concept is that the view renders a certain template (index.html), which becomes the html page returned to the client browser.
That one is the template that should receive a certain context (data), so that it can include other reusable pieces (e.g. showlatest.html) and render them correctly.
The include command just copies the content of the specified template (showlatest.html) within the present one (index.html), as if it were typed in and part of it.
So you need to call render_to_response and pass it your data (last_ones and first_ones) in every view that is responsible for rendering a template that includes showlatest.html
Sorry for the twisted wording, some things are easier done than explained.
:)
UPDATE
Your last edit clarified you are using CBV's (Class Based Views).
Then your view should be something along the line:
class LandingView(TemplateView):
template_name = "base/index.html"
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
context['last_ones'] = coremodels.Startup.objects.all().order_by('-id')[:5]
context['first_ones'] = coremodels.Startup.objects.all().order_by('id')[:5]
return context
Note: personally I would avoid relying on the id set by the DB to order the records.
Instead, if you can alter the model, add a field to mark when it was created. For example
class Startup(models.Model):
...
created_on = models.DateTimeField(auto_now_add=True, editable=False)
then in your view the query can become
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
qs = coremodels.Startup.objects.all().order_by('created_on')
context['first_ones'] = qs[:5]
context['last_ones'] = qs[-5:]
return context

Dynamic navigation in Flask

I have a pretty simple site working in Flask that's all powered from an sqlite db. Each page is stored as a row in the page table, which holds stuff like the path, title, content.
The structure is hierarchical where a page can have a parent. So while for example, 'about' may be a page, there could also be 'about/something' and 'about/cakes'. So I want to create a navigation bar with links to all links that have a parent of '/' (/ is the root page). In addition, I'd like it to also show the page that is open and all parents of that page.
So for example if we were at 'about/cakes/muffins', in addition to the links that always show, we'd also see the link to 'about/cakes', in some manner like so:
- About/
- Cakes/
- Muffins
- Genoise
- Pies/
- Stuff/
- Contact
- Legal
- Etc.[/]
with trailing slashes for those pages with children, and without for those that don't.
Code:
#app.route('/')
def index():
page = query_db('select * from page where path = "/"', one=True)
return render_template('page.html', page=page, bread=[''])
#app.route('/<path>')
def page(path=None):
page = query_db('select * from page where path = "%s"' % path, one=True)
bread = Bread(path)
return render_template('page.html', page=page, crumbs=bread.links)
I already feel like I'm violating DRY for having two functions there. But doing navigation will violate it further, since I also want the navigation on things like error pages.
But I can't seem to find a particularly Flasky way to do this. Any ideas?
The "flasky" and pythonic way will be to use class-based view and templates hierarchy
First of all read documentation on both, then you can refactor your code based on this approach:
class MainPage(MethodView):
navigation=False
context={}
def prepare(self,*args,**kwargs):
if self.navigation:
self.context['navigation']={
#building navigation
#in your case based on request.args.get('page')
}
else:
self.context['navigation']=None
def dispatch_request(self, *args, **kwargs):
self.context=dict() #should nullify context on request, since Views classes objects are shared between requests
self.prepare(self,*args,**kwargs)
return super(MainPage,self).dispatch_request(*args,**kwargs)
class PageWithNavigation(MainPage):
navigation = True
class ContentPage(PageWithNavigation):
def get(self):
page={} #here you do your magic to get page data
self.context['page']=page
#self.context['bread']=bread
#self.context['something_Else']=something_Else
return render_template('page.html',**self.context)
Then you can do following:
create separate pages, for main_page.html and page_with_navigation.html
Then your every page "error.html, page.html, somethingelse.html" based on one of them.
The key is to do this dynamically:
Will modify prepare method a bit:
def prepare(self):
if self.navigation:
self.context['navigation']={
#building navigation
#in your case based on request.args.get('page')
}
else:
self.context['navigation']=None
#added another if to point on changes, but you can combine with previous one
if self.navigation:
self.context['extends_with']="templates/page_with_navigation.html"
else:
self.context['extends_with']="templates/main_page.html"
And your templates:
main_page.html
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
{% block navigation %}
{% endblock %}
{% block main_content %}
{% endblock %}
</body>
</html>
page_with_navigation.html
{% extends "/templates/main_page.html" %}
{% block navigation %}
here you build your navigation based on navigation context variable, which already passed in here
{% endblock %}
page.html or any other some_page.html. Keep it simple!
Pay attention to first line. Your view sets up which page should go in there and you can easily adjust it by setting navigation= of view-class.
{% extends extends_with %}
{% block main_content %}
So this is your end-game page.
Yo do not worry here about navigation, all this things must be set in view class and template should not worry about them
But in case you need them they still available in navigation context variable
{% endblock %}
You can do it in one function by just having multiple decorators :)
#app.route('/', defaults={'path': '/'})
#app.route('/<path>')
def page(path):
page = query_db('select * from page where path = "%s"' % path, one=True)
if path == '/':
bread = Bread(path)
crumbs = bread.links
else:
bread = ['']
crumbs = None
return render_template('page.html', page=page, bread=bread, crumbs=crumbs)
Personally I would modify the bread function to also work for the path / though.
If it's simply about adding variables to your context, than I would recommend looking at the context processors: http://flask.pocoo.org/docs/templating/#context-processors

Categories