Overriding the href img src value in an ImageField in Django admin - django

I'm uploading certain media to a particular directory to secure it. The images are uploaded using an inlineformset_factory object.
The problem I have is that where viewing the uploaded record in the admin site it appears to prepend my settings.MEDIA_URL (/media/) to the path of the uploaded image.
ie.
http://localhost:8000/media/<relative image path>
What I would like it to use instead is a custom setting, settings.PROTECTED_MEDIA_URL ('src') to return the following path instead:
http://localhost:8000/scr/<relative image path>
Included below are what I believe are the relevant parts of the code.
Any insight is appreciated!
settings.py
...
MEDIA_URL = '/media/'
PROTECTED_MEDIA_URL = '/scr/'
...
model.py
...
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location = '/home/user/nginx_restricted')
def orig_car_id_folder(instance, filename):
return 'uploads/images/orig/{0}/{1}'.format(instance.car_id, filename)
class OwnersCar(models.Model):
brand = models.CharField(max_length=64)
...
class OwnersCarImages(models.Model):
car = models.ForeignKey(OwnersCar)
orig_image = models.ImageField(
upload_to=orig_car_id_folder,
verbose_name='Upload Image',
storage=fs
)
...
...
admin.py
from django.contrib import admin
from vehicle_admin_ac.models import OwnersCar, OwnersCarImages
class CarImageInline(admin.TabularInline):
model = OwnersCarImages
exclude = ('thumbnail',)
class OwnersCarAdmin(admin.ModelAdmin):
list_display = ('owner','brand',)
ordering = ('owner',)
search_fields = ('owner',)
inlines = [
CarImageInline,
]
admin.site.register(OwnersCar, OwnersCarAdmin)
urls.py
...
urlpatterns = patterns('',
url(r'^scr/(?P<protected_image_path>/uploads/images/(thumb|orig)/.*)$',
'vehicle_admin_ac.views.protected_view',
name='protected_view'),
...
)
...
views.py
...
#login_required
def protected_view(request, protected_image_path):
response = HttpResponse()
url = protected_image_path
response['Content-Type']=""
response['X-Accel-Redirect'] = "/protected/{0}".format(url)
return response
#login_required
def add_vehicle(request):
ImageFormSet = inlineformset_factory(OwnersCar, OwnersCarImages, form=InitialCarImageForm, extra=3)
owners_car = OwnersCar()
if request.method == 'POST':
form = forms.OwnersCarForm(request.POST, instance=owners_car)
formset = ImageFormSet(request.POST, request.FILES, instance=owners_car)
if formset.is_valid() and form.is_valid():
new_car = form.save(commit=False)
new_car.owner = request.user
new_car.save()
formset.save() # save() method works fine with 'inlineformset_factory'
return HttpResponseRedirect(new_car.get_absolute_url())
else:
form = forms.OwnersCarForm()
formset = ImageFormSet()
return render_to_response('add_new.html',
{'form': form, 'formset': formset},
context_instance=RequestContext(request))
...

Here's a link the relevant part of the docs that I'd missed, explaining the base_url argument.

Related

ValueError - The view didn't return an HttpResponse object. It returned None instead

My view currently returns an error of
The view viajecenter.views.receive_payment didn't return an
HttpResponse object. It returned None instead.
I tried some of the solutions from other related posts here but of no luck.
Here is my function in my views.py file:
def receive_payment(request, account_code):
template_name = 'receive-payment.html'
user = request.user
account = get_object_or_404(Account, account_code=account_code)
if user.is_assigned:
puv = Puv.objects.get(assignment_id=user.assignment_id)
locations = puv.route.locations.all().order_by('distance_from_base')
context = {
'account': account,
'puv': puv,
'locations': locations,
}
return render(request, template_name, context)
else:
return user
and the corresponding url in urls.py file:
from django.urls import path
from . views import ..., receive_payment
urlpatterns = [
...
path('receive-payment/<str:account_code>', receive_payment, name="receive-payment"),
]
and my Account model:
class Account(AbstractBaseUser, PermissionsMixin):
...
account_code = models.UUIDField(default=uuid.uuid4, editable=False)
is_assigned = models.BooleanField(default=False)
Thank you for lending me your time and answering my question :)
It seems you're trying to mix and match function-based views and class-based views.
You can rewrite your view as a DetailView class-based view like so:
from django.views.generic import DetailView
class ReceivePaymentView(DetailView):
template_name = "receive-payment.html"
model = Account
slug_url_kwarg = "account_code"
slug_field = "account_code"
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
account = context["object"]
user = self.request.user
if user.is_assigned:
puv = Puv.objects.get(assignment_id=user.assignment_id)
locations = puv.route.locations.all().order_by("distance_from_base")
context["account"] = account
context["puv"] = puv
context["locations"] = locations
return context
urlpatterns = [
path('receive-payment/<account_code>', ReceivePaymentView.as_view(), name="receive-payment"),
]

Django Multiple Image Upload Using form

This can upload single image. But i want to upload multiple image like insta do. In instagram multiple images are stored in a slider. I don't understand files = request.FILES.getlist('image') how can i iterate this this list
Views.py file
#login_required
def index(request):
images = Image.objects.all()
users = User.objects.filter(is_superuser=False)
prof = Profile.objects.get(user=request.user)
actions = Action.objects.exclude(user=request.user)
following_ids = request.user.following.values_list('id', flat=True)
if request.method == "POST":
form = ImageCreateForm(request.POST, request.FILES)
files = request.FILES.getlist('image')
if form.is_valid():
description = form.cleaned_data["description"]
image = form.cleaned_data["image"]
new_item = form.save(commit=False)
new_item.user = request.user
new_item.save()
create_action(request.user, 'Uploaded Image', new_item)
messages.success(request, "Image Added Successfully")
return redirect(new_item.get_absolute_url())
else:
form = ImageCreateForm(data=request.GET)
if following_ids:
# If user is following others, retrieve only their actions
actions = actions.filter(user_id__in=following_ids)
actions = actions.select_related('user', 'user__profile').prefetch_related('target')[:10]
return render(request, "account/index.html", {
'section': 'index',
'images': images,
'prof': prof,
'actions': actions,
'users': users,
'form': form,
})
forms.py file
from django import forms
from urllib import request
from django.core.files.base import ContentFile
from django.utils.text import slugify
from .models import Image
class ImageCreateForm(forms.ModelForm):
image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = Image
fields = ('description',)
def clean_url(self):
image = self.cleaned_data['image']
valid_extensions = ['jpg', 'jpeg']
extension = image.rsplit('.', 1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The Given URL does not match valid image extensions.')
return image
def save(self, force_insert=False, force_update=False, commit=True):
image = super().save(commit=False)
url = self.cleaned_data['image']
name = slugify(image.description)
image_name = f'{name}'
image.image.save(image_name, ContentFile(url.read()), save=False)
if commit:
image.save()
return image
admin.py file
#admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
list_display = ['slug', 'image', 'description', 'created']
list_filter = ['created']
You can just loop throught it:
for afile in request.FILES.getlist('image'):
mymodel = MyModel()
mymodel .pic = afile
mymodel .save()
Of course you need to make sure you can save the images in your model.

How to save url of the image in database with Django

i am new in Django, how to save url of the image in db using django. Thank you very much, sorry my english, i am learning too.
views.py
from django.shortcuts import render
from django.views.decorators.http import require_POST
from .models import Cad_component
from django import forms
from django.views.decorators.http import require_http_methods
class register_data(forms.ModelForm):
class Meta:
model = Cad_component
fields = ('title','slug','description','start_date','imagviewe')
def home(request):
imagesData = Cad_component.objects.all()
template_name = 'index.html'
context = {
'imagesData': imagesData
}
return render(request, template_name, context)
def register(request):
if request.method == "POST":
form = register_data(request.POST)
print (form)
if form.is_valid():
datas = form.save(commit=True)
#datas.image.save(request.read['title'],request.read['image'])
datas.save()
else:
form = register_data()
return render(request, 'register.html', {'form': form})
models.py
from django.db import models
import datetime
class ComponentManager(models.Manager):
def search(self, query):
return self.get_queryset().filter(
models.Q(name__icontains=query) | \
models.Q(description__icontains=query)
)
class Cad_component(models.Model):
title = models.CharField('Title', max_length=100)
slug = models.SlugField('Link')
description = models.TextField('Description', blank=True)
start_date = models.DateField('Data: ', null=True, blank=True)
image = models.ImageField(upload_to='img', verbose_name='Imagem', null=True, blank=True)
created_at = models.DateTimeField('Criado em ', auto_now_add=True)
updated_at = models.DateTimeField('Atualizado em', auto_now=True)
objects = ComponentManager()
def __str__(self):
return self.title
I was able to solve this problem, with a configuration that Django does in the HTML file. Just add: enctype = "multipart / form-data" in the FORM tag.
Follow:
<form class="needs-validation" method="post" enctype="multipart/form-data">
Any doubts I am available.
from django.core.files.storage import FileSystemStorage
//inside the view function
myfile = request.FILES['files']
f = FileSystemStorage()
filename = f.save(myfile.name, myfile)
url = f.url(filename)
Now you can store this url.
Give an up if it worked... I am new to stackoverflow.

Django Uploaded images not displayed in development

I have defined a model with a 'pic' image field:
class Photo(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
teaser = models.TextField('teaser', blank=True)
pic = models.ImageField(upload_to = 'pic_folder/', default = 'pic_folder/None/default.jpg')
created=models.DateTimeField(default=datetime.datetime.now)
pub_date=models.DateTimeField(default=datetime.datetime.now)
categories = models.ManyToManyField(Category, blank=True)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
visits = models.IntegerField(default=0)
slug = models.CharField(max_length=100, unique=True, blank=True)
And here is the upload form:
class PhotoForm(forms.ModelForm):
class Meta:
model= Photo
fields = ( 'title', 'pic','body', 'categories')
Wich post to this view:
#staff_member_required
def add_photo(request):
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.info(request, "photo was added")
return render(request, 'home.html')
else:
messages.info(request, 'form not valid')
return render(request, 'home.html')
if request.method == 'GET':
form = PhotoForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render(request, 'photo/add_photo.html', args)
The problem is that while photo objects are being saved and the file uploaded but the images are not displayed.
<div class="photo_body"><img src="pic_folder/someimage.jpg" ></div>
I also set
MEDIA_ROOT = '/path/to/my_project/pic_folder'
and run manage.py collectstatic, but they did not solve the problem.
I really got confused about this. So appreciate your hints.
First of all make a folder called media in your project's directory.
Django will store all your uploaded images inside media/pic_folder/ automatically.
In your settings.py file, add this:
MEDIA_URL = '/media/'
MEDIA_ROOT = '/path_to/media/' # write the path to the media folder you just created.
In your urls.py file, add the following lines at the top:
from django.conf import settings
from django.conf.urls.static import static
and add the following line at the end:
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
something like below:
urlpatterns = patterns('',
# Your urls here
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And, finally, in your templates:
<img src="{{MEDIA_URL}}pic_folder/someimage.jpg" />

Extending Django Admin for data import

I'm trying to build an import feature/form in the django admin interface for a specific model.
I have already found the following question on Stackoverflow, however as I am new to django, I have not been able to wire it all up. Import csv data into database in Django Admin
I guess I understand how to work with Django objects and how to use the CSV reader module, but I have a heck of a time putting it all together in Django.
what i tried so far is this:
models.py
class RfidTag(models.Model):
"""
Available RFID-Tags from Importfile
"""
system = models.DecimalField(
_('system'),
max_digits=4,
decimal_places=0,
)
tagId = models.DecimalField(
_('tag ID'),
max_digits=4,
decimal_places=0,
)
serial = models.CharField(
_('serial'),
max_length=10,
)
# forms.py #
class RfidImport(forms.ModelForm):
file_to_import = forms.FileField()
class Meta:
model = RfidTag
fields = ("file_to_import",)
def save(self, commit=False, *args, **kwargs):
form_input = RfidImport()
file_csv = self.cleaned_data['file_to_import']
csv.register_dialect('excel-new', delimiter=';', quoting=csv.QUOTE_NONE)
records = csv.reader(file_csv, dialect='excel-new')
for line in records:
self.system = line[0]
self.tagId = line[1]
self.serial = line[2]
form_input.save()
datafile.close()
admin.py
class RfidTagAdmin(admin.ModelAdmin):
list_display = ('system','tagId','serial')
actions = ['import_tags']
def get_urls(self):
urls = super(RfidTagAdmin, self).get_urls()
my_urls = patterns('',
(r'^import/$', self.admin_site.admin_view(import_tags))
)
return my_urls + urls
def import_tags(self, request, queryset):
return HttpResponseRedirect("./import")
import_tags.short_description = "Import new RFID tags"
pass
admin.site.register(RfidTag, RfidTagAdmin)
views.py
#staff_member_required
def import_tags(request):
if request.method == "POST":
form = RfidImport(request.POST, request.FILES)
if form.is_valid():
form.save()
success = True
context = {"form": form, "success": success}
return HttpResponseRedirect("../")
else:
form = RfidImport()
context = {"form": form}
return HttpResponseRedirect("../")
My question is, is admin action actually the right way? Is there a better way to achieve what I am trying? And how do I wire this up? I have yet to see the form, after I select the import action and click "go".
The admin is the right way, however i wouldn't be using an action for this, those are designed to function over a list of objects and you don't need that. For this case simply extend the admin/index.html template and add an href to your view. After that you create a normal form in which you do your processing