I am making a django site where users can upload images and I want to use sorl-thumbnail for thumbnail generation and caching. I am using a container based workflow using podman on a fedora silverblue host.
I have setup a memcached cache engine (using the memcached docker image), and can set and get values to and from the cache in django-shell with no issues. I have run the migrate command with sorl-thumbnail added to my installed-apps. I have run the ./manage.py createcachetable command and no errors. I am using pylibmc with:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
I have created a model which has the sorl.thumbnail ImageField, although I hope to use a standard imagefield eventually, which I believe is possible.
I have the following model, view, and template:
model...
class Image(models.Model):
image_file = ImageField(upload_to=user_directory_path)
#thumbnail = models.ImageField(upload_to=str(user_directory_path) + '_thumb', null=True)
userprofile = models.ForeignKey(ForumProfile, on_delete=models.CASCADE, related_name="images")
view...(the get function is added during debugging this issue)...
class ForumProfileUploadView(LoginRequiredMixin, FormView):
form_class = ImageForm
template_name = 'list.html'
success_url = reverse_lazy('my-view')
def get(self, request, *args, **kwargs):
form = self.form_class()
message = 'Hi!'
images = Image.objects.all()
context = {'images': images, 'form': form, 'message': message}
return render(self.request, 'list.html', context)
def form_valid(self, form):
obj = form.save(commit=False)
obj.userprofile = self.request.user.profile.forumprofile
# img = PillowImage.open(obj.image_file.file)
# obj.thumbnail = MakeThumbnail(self.request.FILES['image_file'])
# breakpoint()
obj.save()
message = 'Success!'
images = Image.objects.all()
breakpoint()
context = {'images': images, 'form': form, 'message': message}
return render(self.request, 'list.html', context)
def form_invalid(self, form):
message = 'The form is not valid. Fix the following error:'
images = Image.objects.all()
context = {'images': images, 'form': form, 'message': message}
return render(self.request, 'list.html', context)
template...
<!DOCTYPE html>
<html lang='en'>
<head>
</head>
<body>
<!-- List of uploaded documents -->
{% block content %}
{% load thumbnail %}
{% if images %}
All images in the database:
{% for image in images %}
{% thumbnail image.image_file.url "100x100" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}
{% endfor %}
{% else %}
<p>No images.</p>
{% endif %}
<!-- Upload form. Note enctype attribute! -->
<form action="{% url 'my-view' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ message }}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.image_file.label_tag }} {{ form.image_file.help_text }}</p>
<p>
{{ form.image_file.errors }}
{{ form.image_file }}
</p>
<p><input type="submit" value="Upload"/></p>
</form>
{% endblock content %}
</body>
I have managed to get it working. I am fairly certain that the necessary thing was for me to set the cache to work for the entire site, although I could have used it for a specific view, and this allowed sorl.thumbnail to start working.
https://docs.djangoproject.com/en/3.1/topics/cache/#the-per-site-cache
Related
models.py
class PostModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_time = models.DateTimeField(auto_now_add=True)
title = models.TextField(null=True)
body = models.TextField(null=True)
def __str__(self):
return str(self.user)
class ImagesPostModel(models.Model):
post = models.ForeignKey(PostModel, on_delete=models.CASCADE)
images = models.I
views.py
def show_posts(request):
posts = PostModel.objects.filter(user=request.user)
images = []
for post in posts:
images.append(ImagesPostModel.objects.filter(post=post))
context = {
'posts': posts,
'images': images,
}
return render(request, 'show_posts.html', context)
show_posts.html
{% extends 'base.html' %}
{% block content %}
{% for post in posts %}
{{post.title}}
<br>
{{post.body}}
<br>
{{post.data_time}}
<br>
{% for imgs in images %}
{% for image in imgs %}
{{image.post_id}}
<img src="{{image.images.url}}" alt="postimage" style="width: 300px;">
<br>
{% endfor %}
{% endfor %}
<hr>
<hr>
{% endfor %}
{% endblock %}
I want the images of a post to be displayed which are related to that post only. But here all the images combined for all posts of a particular user are being displayed each time in every post. How to resolve it?
You put yourself in that dilemma, you can fix the view code to fix that easily
def show_posts(request):
posts = PostModel.objects.filter(user=request.user)
for post in posts:
post.images = ImagesPostModel.objects.filter(post=post))
context = {
'posts': posts,
}
return render(request, 'show_posts.html', context)
and then you iterate over post.images in the template
OR you use post.images_set.all() to access the post images.
I would suggest you to use related_name for the post in your ImagePostModel. In your models.py you can do this.
class ImagesPostModel(models.Model):
post = models.ForeignKey(PostModel, on_delete=models.CASCADE, related_name="imagePost")
images = models.ImageField()
And then in your template use {{ post.imagePost.all }}
You can prefetch the images in bulk with:
def show_posts(request):
posts = PostModel.objects.filter(
user=request.user
).prefetch_related('imagespostmodel_set')
context = {
'posts': posts
}
return render(request, 'show_posts.html', context)
then in the template, you can access the .imagespostmodel_set of the post:
{% for post in posts %}
…
{% for image in post.imagespostmodel_set.all %}
{{image.post_id}}
<img src="{{image.images.url}}" alt="postimage" style="width: 300px;">
<br>
{% endfor %}
…
{% endfor %}
Note: Models normally have no Model suffix. Therefore it might be better to rename PostModel to Post.
I'm using this app to register the user of my website https://github.com/egorsmkv/simple-django-login-and-register. The problem is that no metter what I do my form are not visible (they were when I did not use this registration app and the code worked just fine). This is my code:
model
class UserBio(models.Model):
name = models.CharField(max_length=120)
age = models.CharField(max_length=2)
phone = models.CharField(max_length=10)
height = models.CharField(max_length=3)
weight = models.CharField(max_length=3)
form
class UserBio(forms.ModelForm):
class Meta:
model = UserBio
fields = (name', 'age', 'phone', 'height', 'weight')
views
def add_bio(request):
submitted = False
if request.method == "POST":
info_form = UserBio(request.POST)
if info_form.is_valid():
info_form.save()
return HttpResponseRedirect('add_information?submitted=True')
else:
info_form = UserBio()
if 'submitted' in request.GET:
submitted = True
return render(request, 'accounts/profile/add_information.html', {'form': info_form, 'submitted':submitted})
urls
urlpatterns = [
path('add/information', views.add_information, name='add_information'),
]
html
{% extends 'layouts/default/base.html' %}
{% block title %} Add info {% endblock %}
{% load i18n %}
{% block content %}
<h4>{% trans 'Add Info' %}</h4>
{% if submitted %}
Sumitted correctly
{% else %}
<form method="post">
{% csrf_token %}
{{ info_form.as_p }}
</form>
</div>
<br/>
</body>
{% endif %}
{% endblock %}
Any help would be very apprecieted!
because in your views def add_bio change your url acc to your function views
path('add/information', views.add_bio, name='add_information'),
and in you template
{{ form.as_p }}
You passed the info_form variable to the template with variable name form. Indeed:
# name of the variable for the template ↓
return render(request, 'accounts/profile/add_information.html', {'form': info_form, 'submitted':submitted})
This thus means that you render this with:
{{ form.as_p }}
You should also trigger the correct view:
urlpatterns = [
path('add/information/', views.add_bio, name='add_information'),
]
The path does not point to the template: a path points to a view, and the view can (this is not required) render zero, one or multiple templates to create a HTTP response.
So the goal is to get the user to upload images inside the application, and for the images to be displayed on the screen.
The problem is that the forms will not save to the models I made. I am following Django Central https://djangocentral.com/uploading-images-with-django/ for guidance for uploading my images.
What I have at the moment is where the user can type inside the form for their caption and where the user can select a file for their image, but nothing happens when they click the upload button. All that happens, is that it redirects me to the homepage for some reason, but I can fix that later. The only way for the images to be displayed on the website is if I manually go into the admin panel and upload the image there. If anyone could help I would much appreciate it.
view.py
def profile(request):
if request.method == "POST":
form = User_Profile_Form(data = request.POST, files = request.FILES)
if form.is_valid():
form.save()
obj = form.instance
return render(request, "main/profile.html", {"obj":obj})
else:
form = User_Profile_Form()
img = User_Profile.objects.all()
return render(request,"main/profile.html", {"img":img, "form":form})
models.py
class User_Profile(models.Model):
caption = models.CharField(max_length = 100)
image = models.ImageField(upload_to = "img/%y", blank=True)
def __str__(self):
return self.caption
forms.py
from django import forms
from .models import User_Profile
class User_Profile_Form(forms.ModelForm):
class Meta:
model = User_Profile
fields = ("caption", "image")
profile.html
<div class="container">
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-lg btn-success">Upload</button>
</form>
{% if obj %}
<h3>Succesfully uploaded : {{img_obj.caption}}</h3>
<img src="{{ obj.image.url}}" alt="image" class="img-thumbnail" >
{% endif %}
<hr>
{% for x in img %}
{% if forloop.first %}<div class="row ">{% endif %}
<div class="col-lg-4 col-md-4 col-12" >
<div class="text-center mt-2">
<img src="{{x.image.url}}" height="70%" width="70%" class="img-thumbnail" alt="...">
<h2 class="text-center" >{{x.caption}}</h2></div>
</div>
{% if forloop.counter|divisibleby:3 %}
</div>
<div class=row>{% endif %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}
</div>
In the template change the action:
from:
<form action="." method="post" enctype="multipart/form-data">
To:
<form action="" method="post" enctype="multipart/form-data">
. redirects you to the home page.
in views.py
def profile(request):
if request.method == "POST":
form = User_Profile_Form(data = request.POST, files = request.FILES)
if form.is_valid():
form.save()
obj = form.instance
return render(request, "main/profile.html", {"obj":obj, "form":form})
else:
form = User_Profile_Form()
img = User_Profile.objects.all()
return render(request,"main/profile.html", {"img":img, "form":form})
i know what you want to do, i did it on my project, here is my code, edited for your self
views.py
pimageupdate = ProfileImageUpdate(request.POST,request.FILES, instance=request.user.userprofile)
if pimageupdate.is_valid():
pimageupdate.save()
should i note that pimageupdate is getting the form from forms.py
and you should add user in your {{}} code like this
{{user.userprofile.default_profile_picture}}
change "post" in your form tag to "POST"
hope this work, let me know if you tried them
I'm trying to make my dashboard show a list of users in your area. This so far works but I can not get the user's fist image to show. The current error message I am getting is "'QuerySet' object has no attribute 'id'"
models.py
class Images(models.Model):
image = models.ImageField(upload_to='profile_image', null=True, default='profile_image/none/no-img.png')
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
views.py
class DashboardView(TemplateView):
template_name = 've/cp/dashboard.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(DashboardView, self).dispatch(*args, **kwargs)
def get(self, request, pk=None):
users = User.objects.exclude(id=request.user.id)
user = User.objects.filter(pk=pk)
try:
favorite = Favorite.objects.get(current_user=request.user)
favorites = favorite.users.all()
except Favorite.DoesNotExist:
favorites = None
args = {
'users': users, 'favorites':favorites, 'images': Images.objects.filter(user_id=user.id)
}
return render(request, self.template_name, args)
dashboard.html
<h2>People near you</h2>
{% for user in users %}
<a href="{% url 've:view_profile_with_pk' pk=user.pk %}">
<h4>{{ user.username }}</h4>
<p>{{ user.images }}</p>
{% if images %}
{% for img in images %}
<a href="{{ img.image.url }}" target="_blank">
<img src="{{ img.image.url }}" class="" style="max-width: 300px">
</a>
{% endfor %}
{% else %}
<p>No images</p>
{% endif %}
</a>
{% if not user in favorites %}
<a href="{% url 've:change_favorites' operation='add' pk=user.pk %}">
<button type="button" class="btn btn-success">Add Favorite</button>
</a>
{% endif %}
{% endfor %}
user = User.objects.filter(pk=pk) return queryset. When yoy try later Images.objects.filter(user_id=user.id) it raise error. You need to get first object in queryset with first() method:
user = User.objects.filter(pk=pk).first()
Or use get instead:
user = User.objects.get(pk=pk)
but second option will raise DoesNotExist error if user with provided id does not exist. To handle this error you can use get_object_or_404, which return page not found in case of wrong id:
from django.shortcuts import get_object_or_404
user = get_object_or_404(User, pk=1)
I have a simple form in my template, index.html:
{% if stripped_thumbnail_file_list %}
{% for thumbnail_name in stripped_thumbnail_file_list %}
<div class="">
<div class="">
This is my form
<form class="" action="{% url 'index' %}" method="post">
{% csrf_token %}
<input type="image" value="{{ thumbnail_name }}" src="{{ MEDIA_URL}}thumbnails/{{ thumbnail_name }}.jpg">
</form>
</div>
</div>
{% endfor %}
{% else %}
<p>No videos are available.</p>
{% endif %}
I want the index view to pull the {{ thumbnail_name }} value from this form and use it as a variable when the index view redirects to a different view that will use that name to play a matching video.
I have been unsuccessful in trying to pull that value from the form as I have it. I suspect this may because I'm not creating a Django form object. I tried to create that object, but I can't find any examples of a Django form object as an image like I have in my form.
What should that look like? Or, can someone make a recommendation on how to pull the value from the form as is?
EDIT: adding views.py snippet:
def index(request):
# if this is a POST request we need to process the form data
if request.POST:
# get thumbnail_name from form
# redirect to a new URL (hardcode thumbnail name for now):
return HttpResponseRedirect('2017-02-01_04-29-10/video/')
thumbnail_file_list = get_file_list(target_directory, ".jpg")
stripped_thumbnail_file_list = strip_file_extension(thumbnail_file_list)
template = loader.get_template('dash/index.html')
context = {
'stripped_thumbnail_file_list': stripped_thumbnail_file_list,
}
return HttpResponse(template.render(context, request))
def video(request, file_name):
print("this is the file name passed: " + file_name)
template = loader.get_template('dash/video.html')
context = {
'file_name': file_name,
}
return HttpResponse(template.render(context, request))
First: you need to declare the 'name' attribute on your form imput.
<input name="thumbnail_name" type="image" value="{{ thumbnail_name }}" src="{{ MEDIA_URL}}thumbnails/{{ thumbnail_name }}.jpg">
Second: Why don't you just set the 'action' of the form to your 'video' function (when you perform a redirect, you are losing all your POST data).Then, from there you could retrieve the value: something like that
def video(request):
file_name = request.POST.get('thumbnail_name')
print("this is the file name passed: " + file_name)
template = loader.get_template('dash/video.html')
context = {
'file_name': file_name,
}
return HttpResponse(template.render(context, request))
Hope it helps