I need to make a dynamic path for a file that I want to open. I need to retrieve the .tif file from within a path.
this path is formed by a combination of a "STATICFILES_DIRS" from my settings.py and a field ccalled docId from my models.py that get filled from the views.py
now, I'm very new to django so I really don't understand what I dont know (if this makes sense)
my views.py has the following:
from django.shortcuts import render
import pyodbc
# Create your views here.
def home(request): conn=pyodbc.connect('Driver={sql server};'
'Server=server.domain.com;' 'Database=database;' 'Trusted_Connection=yes;')
cursor = conn.cursor() cursor.execute("select top 100 docId, supplierName,
invoiceNumber, reference from table") result = cursor.fetchall() return
render(request, 'azolve/home.html', {'Azolve': result})
and my models.py has this:
from django.db import models
import os import fnmatch
class Azolve(models.Model):
docId = models.IntegerField
supplierName = models.CharField(max_length=100)
invoiceNumber = models.IntegerField
reference = models.CharField(max_length=100)
# for file_name in os.listdir(str(filePath)):
# if fnmatch.fnmatch(file_name, '*.tif'):
# docIdFileName = file_name
and in my settings.py I have this part:
STATIC_URL = '/static/'
STATICFILES_DIRS = [ "//server1/Shared1/folder/ Migration Images/", ]
so, to give an idea, each docId that gets retrieved is the name of a folder contained in the path "STATICFILES_DIRS " what I was trying to do is to navigate for each folder and get the .tif file inside the folder, so I can concatenate and make the complete filename with the format:
//server1/Shared1/folder/ Migration Images/--docIDFOLDER--/FILENAME.TIF
this would later be shown in a table in my html file doing something like:
<tbody>
{% for datarow in Azolve %}
<tr>
<td>{{datarow.supplierName}}</td>
<td>{{datarow.invoiceNumber}}</td>
<td>{{datarow.reference}}</td> <td><a href= ' {% static "" %}{{ datarow.docId }}/{{ datarow.docIdFileName }}'>Open Invoice</a></td> </tr>
{% endfor %}
</tbody>
Does this makes sense? I've been checking different django tutorials, but I couldn't find an example of something similar to what I need to do :(
I don't know how should I get this data so I can concatenate and then pass it to the "datarow"
I've tried adding this in the models but I think is not correct to add it on the class, should be then in the views inside the function? as a new function?
Note: I'm not having the user upload files, these are stored in a network drive and I only need to have users look for them and download them, my problem is generating the complete path from the folder where the .tif file is stored (I get to "//Server/Folder/Folder2/docIdFolder/XXXX.tif" but I can't assign the value of the XXXX.tif part.
I would suggest adding a field to the model to store the file name, and look it up once from the file system, storing it in the db after that.
class Azolve(models.Model):
docId = models.IntegerField
supplierName = models.CharField(max_length=100)
invoiceNumber = models.IntegerField
reference = models.CharField(max_length=100)
img_filename = models.CharField(max_length=255, blank=True, null=True)
but also add a def to the Azolve model class which attempts to populate that img_filename if it doesn't exist. Something along the lines of the following which tries to locate the .tif using pathlib's glob (https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob):
# put this at the top of your models.py
from pathlib import Path
# and this right in your class
def tif_file(self):
if self.img_filename:
return self.img_filename:
else:
search_path = Path(r'//server1/Shared1/folder/Migration Images')
# the filter likely not needed, was using this in where I copied from
files_in_path = list(filter(Path.is_file, search_path.glob('*.tif')))
if files_in_path:
# may have to wrap the files_in_path with str()
# untested, writing in the s/o answer box
self.img_filename = files_in_path[0]
return files_in_path[0]
else:
return None
Then in your template you should be able to use {{datarow.tif_file}}. From a performance standpoint, I'm not certain if this would get run everytime you reference this record or not or if it would only fire when called upon. Might be worth tracing through the debugger.
Related
I am trying to make a portal where I take landing page template from different users and check manually that template is working file or not.
If everything looks good then I want to upload that theme from my django admin panel which create a new folder for every template like in this case its template1, template/theme/template1/index.html folder and also same with static files I want to upload zip file for all folders of static file and what will happen in backend is it go to folder static/template1/(unzipped static files) where unzipped static files is the location where all the static file will unzip itself so that my index.html and static files can communicate with each other.
I am not able to find any solution for this.
How can we make a model for uploading file like this to make a new folder every time?
from django.db import models
from django.contrib.auth.models import User
from django.db import models
class themes(models.Model):
index_file = models.filefield(upload_to=???????)
static_files = models.filefield(upload_to =?????)
Also I don't want to do collect static every time i upload a new template design.
Edit 2 here >>
In my models.py I tried doing this but I am getting errors in it. , where I am doing wrong ?
def index_path_upload(instance, filename):
if not instance.pk:
# get count of all object, so is will be unique
number = instance.__class__.objects.count() + 1
else:
number = instance.pk
# replace filename to all object have the same
filename = "index.html"
return f"templates/theme/template{number}/{filename}"
def static_path_upload(instance, filename):
if not instance.pk:
# get count of all object, so is will be unique
number = instance.__class__.objects.count() + 1
else:
number = instance.pk
# replace filename to all object have the same
return f"static/template{number}/+.zip"
class themes(models.Model):
index_file = models.FileField(upload_to=index_path_upload)
static_file = models.FileField(upload_to=static_path_upload)
do I need to add other things in my setings file , currently this is what I have.
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
STATIC_ROOT = os.path.join(BASE_DIR, 'assets')
MEDIA_URL = 'static/'
MEDIA_ROOT = (os.path.join(BASE_DIR,'static/'))
why not like this ?
the upload_to key in FileField accept a function like this
def index_path_upload(instance, filename):
if not instance.pk:
# get count of all object, so is will be unique
number = instance.__class__.objects.count() + 1
else:
number = instance.pk
# replace filename to all object have the same
filename = "index.html"
return f"template/theme/template{number}/{filename}"
the instance params is your object ( themes models )
,the filename params is original filename of uploaded files
so your models like
def index_path_upload(instance, filename):
...
class themes(models.Model):
index_file = models.filefield(upload_to=index_path_upload)
...
edit:
from django.conf import settings
import os
def index_path_upload(instance, filename):
if not instance.pk:
# get count of all object, so is will be unique
number = instance.__class__.objects.count() + 1
else:
number = instance.pk
# replace filename to all object have the same
filename = "index.html"
path = f"templates/theme/template{number}/{filename}"
return os.path.join(settings.BASE_DIR, path)
is will uploaded on your root directory ( where is manage.py ) + path
be warning with that , is a big security flaw !
I installed the webp_converter package at documented Here
{% load webp_converter %}
This is not working which I want to add static_webp
<img src="{% static_webp 'modelImage.url' %}">
This is working fine
<img src="{{ modelImage.url }}">
From Official Doc says
<img src="{% static_webp 'img/hello.jpg' %}">
I could not customize the output to the template using {% static_webp 'modelImage.url' %}. But I was able to convert the file when uploading and store the files immediately in the desired format (webp). My solution may be useful for those who are developing a new project because my method does not assume previously saved files in the model.
So let's start in order.
models.py
In my model (Catalog) I have overridden the path to where the images are stored by calling the function (rename_file). The function (rename_file) renames the expansion of our file to .webp, creating the correct obj.url . This must be done immediately. Because the obj.url has the attribute read only.
from django.db import models
from datetime import date
image_path = os.path.abspath(settings.MEDIA_ROOT + '/photos/asics/' + date.today().strftime('%Y/%m/%d/'))
def rename_file(instance, filename):
if filename.find('.') >= 0:
dot_index = (len(filename) - filename.rfind('.', 1)) * (-1)
filename = filename[0:dot_index]
filename = '{}.{}'.format(filename, 'webp')
return os.path.join(image_path, filename)
class Catalog(models.Model):
photo = models.ImageField(upload_to=rename_file, blank=True)
admin.py
Images are added to my application through the admin panel. So I decided to convert the images in this file, but it doesn't matter. Here I use signals (post_save) to call the function (convert_image), which converts the image to the desired format (.webp) and replace the Origanal file with a new file.
from django.contrib import admin
from .models import Catalog
from PIL import Image
from django.db.models.signals import post_save
#receiver(post_save, sender=Catalog)
def convert_image(instance, **kwargs):
if image_name:
im = Image.open(image_name).convert('RGB')
output_path = str(image_name)
im.save(output_path, 'webp')
class CatalogAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
global image_name
image_name = obj.photo
super().save_model(request, obj, form, change)
ERROR MSG:
The web page throws another view when I am trying to create another view and see the contents I have saved in the DB.
In models.py:
from django.db import models
# Create your models here.
class pichuur(models.Model):
def __str__(self):
return self.name + '-' + self.language
name=models.CharField(max_length=100)
language= models.CharField(max_length=100)
Genre= models.CharField(max_length=100)
Year= models.CharField
Category= models.CharField(max_length=100)
Cast= models.CharField(max_length=500)`
from django.shortcuts import render
in views.py:
# Create your views here.
from django.http import HttpResponse
from .models import pichuur
def index(request):
Sab_movies = pichuur.objects.all()
html=''
for pichuur in Sab_movies:
url= '/Movies/' + str(pichuur.id) + '/'
html+= '' + '<br>'
return HttpResponse("<h> Welcome to Movies </h>")
def detail(request, pichuur_id):
return HttpResponse("<h2> Details for Movie Id:" + str(pichuur_id) + "</h2>")
You are using pichuur as a local variable in the for loop:
for pichuur in Sab_movies:
This means Python expects to be able to assign to it, and before the for loop starts, the name is unbound, has no value assigned to it.
That that name is also the name of your model doesn't matter any more. So the statement Sab_movies = pichuur.objects.all() fails, because pichuur is not yet set by the for loop.
The solution is to use a different names for your model and the loop target variable. Don't reuse model names as local variable names. And in the Python style guide, classes (such as Django models) should use CamelCase names, precisely to avoid mistakes like these.
So here specifically, I'd rename the model to use an uppercase P:
class Pichuur(models.Model):
then in views.py use that new name:
from .models import Pichuur
and
Sab_movies = Pichuur.objects.all()
I'm working with Flask/Mongoengine-MongoDB for my latest web application.
I'm familiar with Pymongo, but I'm new to object-document mappers like Mongoengine.
I have a database and collection set up already, and I basically just want to query it and return the corresponding object. Here's a look at my models.py...
from app import db
# ----------------------------------------
# Taking steps towards a working backend.
# ----------------------------------------
class Property(db.Document):
# Document variables.
total_annual_rates = db.IntField()
land_value = db.IntField()
land_area = db.IntField()
assessment_number = db.StringField(max_length=255, required=True)
address = db.StringField(max_length=255, required=True)
current_capital_value = db.IntField
valuation_as_at_date = db.StringField(max_length=255, required=True)
legal_description = db.StringField(max_length=255, required=True)
capital_value = db.IntField()
annual_value = db.StringField(max_length=255, required=True)
certificate_of_title_number = db.StringField(max_length=255, required=True)
def __repr__(self):
return address
def get_property_from_db(self, query_string):
if not query_string:
raise ValueError()
# Ultra-simple search for the moment.
properties_found = Property.objects(address=query_string)
return properties_found[0]
The error I get is as follows: IndexError: no such item for Cursor instance
This makes complete sense, since the object isn't pointing at any collection. Despite trolling through the docs for a while, I still have no idea how to do this.
Do any of you know how I could appropriately link up my Property class to my already extant database and collection?
The way to link a class to an existing collection can be accomplished as such, using meta:
class Person(db.DynamicDocument):
# Meta variables.
meta = {
'collection': 'properties'
}
# Document variables.
name = db.StringField()
age = db.IntField()
Then, when using the class object, one can actually make use of this functionality as might be expected with MongoEngine:
desired_documents = Person.objects(name="John Smith")
john = desired_documents[0]
Or something similar :) Hope this helps!
I was googling this same question and i noticed the answer has changed since the previous answer:
According to the latest Mongoengine guide:
If you need to change the name of the collection (e.g. to use MongoEngine with an existing
database), then create a class dictionary attribute called meta on your document, and set collection to the
name of the collection that you want your document class to use:
class Page(Document):
meta = {'collection': 'cmsPage'}
The code on the grey did the trick and i could use my data instantly.
I have Python 3.2 set up with Apache via mod_wsgi. I have CherryPy 3.2 serving a simple "Hello World" web page. I'd like to start templating using Jinja2 as I build out the site. I'm new to Python and therefore don't know much about Python, CherryPy, or Jinja.
Using the code below, I can load the site root (/) and the products page (/products) with their basic text. That at least lets me know I've got Python, mod_wsgi, and CherryPy set up somewhat properly.
Because the site will have many pages, I'd like to implement the Jinja template in a way that prevents me from having to declare and render the template in each page handler class. As far as I can tell, the best way to do that is by wrapping the PageHandler, similar to these examples:
http://docs.cherrypy.org/dev/concepts/dispatching.html#replacing-page-handlers
http://docs.cherrypy.org/stable/refman/_cptools.html#cherrypy._cptools.HandlerWrapperTool
I've implemented the code in the second example, but it doesn't change anything.
[more details after code]
wsgi_handler.py - A mash-up of a few tutorials and examples
import sys, os
abspath = os.path.dirname(__file__)
sys.path.append(abspath)
sys.path.append(abspath + '/libs')
sys.path.append(abspath + '/app')
sys.stdout = sys.stderr
import atexit
import threading
import cherrypy
from cherrypy._cptools import HandlerWrapperTool
from libs.jinja2 import Environment, PackageLoader
# Import from custom module
from core import Page, Products
cherrypy.config.update({'environment': 'embedded'})
env = Environment(loader=PackageLoader('app', 'templates'))
# This should wrap the PageHandler
def interpolator(next_handler, *args, **kwargs):
template = env.get_template('base.html')
response_dict = next_handler(*args, **kwargs)
return template.render(**response_dict)
# Put the wrapper in place(?)
cherrypy.tools.jinja = HandlerWrapperTool(interpolator)
# Configure site routing
root = Page()
root.products = Products()
# Load the application
application = cherrypy.Application(root, '', abspath + '/app/config')
/app/config
[/]
request.dispatch: cherrypy.dispatch.MethodDispatcher()
core module classes
class Page:
exposed = True
def GET(self):
return "got Page"
def POST(self, name, password):
return "created"
class Products:
exposed = True
def GET(self):
return "got Products"
def POST(self, name, password):
return "created"
Based on what I read on a Google Group I figured I might need to "turn on" the Jinja tool, so I updated my config to this:
/app/config
[/]
tools.jinja.on = True
request.dispatch: cherrypy.dispatch.MethodDispatcher()
After updating the config, the site root and products pages display an CherryPy generated error page "500 Internal Server Error". No detailed error messages are found in the logs (at least not in the logs I'm aware of).
Unless it came pre-installed, I know I probably need the Jinja Tool that's out there, but I don't know where to put it or how to enable it. How do I do that?
Am I going about this the right way, or is there some better way?
Edit (21-May-2012):
Here is the Jinja2 template I'm working with:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
I figured it out.
In the interpolator function, the next_handler function call the original PageHandler (Page.GET or Products.GET in this case). Those original PageHandlers return strings while the interpolator function is treating the response like a python dict (dictionary), hence the double asterisk when it's passed to template.render as **response_dict.
The Jinja template has a placeholder for title, so it needs a title to be defined. Passing a plain string to the render function doesn't define what title should be. We need to pass an actual dict to the render function (or nothing at all, but what good is that?).
Note: For either of these fixes, the jinja tool does need to be enabled, as shown in the question by setting tools.jinja.on to True in the config.
Quick Fix
Define the title as the render function is called. To do this I need to change this line:
return template.render(**response_dict) # passing the string as dict - bad
to this:
return template.render(title=response_dict) # pass as string and assign to title
Like this, the template renders with my PageHandler text as the page title.
Better Fix
Because the template will grow to be more complex, one render function probably won't always be able to correctly assign the necessary placeholders. It's probably a good idea to let the original page handler return an actual dict with the template's many placeholders assigned.
Leave the interpolator function as it was:
def interpolator(next_handler, *args, **kwargs):
template = env.get_template('base.html')
response_dict = next_handler(*args, **kwargs)
return template.render(**response_dict)
Update Page and Products to return actual dicts that define the value's for the template's placeholders:
class Page:
exposed = True
def GET(self):
dict = {'title' : "got Page"}
return dict
def POST(self, name, password):
# This should be updated too
# I just haven't used it yet
return "created"
class Products:
exposed = True
def GET(self):
dict = {'title' : "got Products"}
return dict
def POST(self, name, password):
# This should be updated too
# I just haven't used it yet
return "created"
Like this, the template renders with my PageHandler title text as the page title.
There's also an updated Jinja2 tool found on a repository of various recipes the community has contributed to.