Using HTMX, hx-push-url - python

just looking for some detailed pointers on how to hx-push-url as I have come across some problems and looking for some direction. I am a relative beginner at Django and just started using HTMX.
The aim. I'm building a simple image gallery and have a grid of thumbnails, I am using HTMX to load the list of images within that gallery when a uses click a thumbnail.
This works well, I am using Django-HTMX and a if conditional in the View to deal with the HTMX request which serves the partial HTML into the thumbnail page.
The problem was that my URL did not change. My thumbnail is http://127.0.0.1:8000/gallery/ and when I click on a gallery to view images within, the url remains the same, so, I used htmx-push-url so that URL would appear something like http://127.0.0.1:8000/gallery/news. This works and the URL changes.
Anyway, onward.
I have a button on my images list page that take you back to the thumbnail page, but when using this I get a 404 error, and also when I refresh my image list page I get a 404. Obviously there is no URL and view for http://127.0.0.1:8000/gallery/news. I Just have little idea how to solve this.
When I look in the console I get a HTMX-target error when clicked the back button, and nothing happens. And, as I say, a refresh gets a 404.
Code below should explain things better.
Models
name = models.CharField(max_length=200, null=True)
description = models.CharField(max_length=200, null=True, blank=True,
help_text="Gallery description on gallery page")
slug = AutoSlugField(populate_from='name')
created = models.DateTimeField()
visable = models.BooleanField(default=False)
type = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
image = models.ForeignKey('Media', on_delete=models.CASCADE)
album_images = models.ManyToManyField('Media', related_name="album_pictures")
class Media(models.Model):
timestamp = models.DateTimeField()
image = models.ImageField(upload_to="media")
order = models.IntegerField(default=0)
visable = models.BooleanField(default=True)
categories = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
URLS (relevant)
path("gallery/", views.GalleryView, name="gallery"),
Views
def GalleryView(request):
if request.htmx:
slug = request.GET.get('slug')
pics = get_object_or_404(Albums, slug=slug)
context = {'pictures': Media.objects.filter(album_pictures=pics),
'description': Albums.objects.filter(slug=slug)}
return render(request, 'main/gallery-detail.html', context=context)
context = {'objects_list': Albums.objects.all()}
return render(request, 'main/gallery.html', context=context)
Gallery HTML {relevant code)
<div class="gallery-body">
{% for img in objects_list %}
<div class="item col-xs-6 col-sm-6 col-md-4">
<figure class="overlay"> <a hx-post="{{ request.path }}?slug={{ img.slug }}"
hx-target=".gallery-body"
hx-swap="outerHTML"
hx-push-url="/gallery/{{ img.slug }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% endfor %}
The partial that gets called showing the images within the galleries.
<button class="btn btn-primary"
hx-get="{% url 'main:gallery' %}"
hx-target=".gallery-body"
hx-push-url="/gallery"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
<h6>Back to Gallery page</h6></button></div>

Related

Django dynamic ListView filtering problem

I am working on my first solo project with Django and I have hit a problem that no amount of searching and reading similar post on SO have solved.
I am trying to filter a gallery of images by their category, so that when the user clicks on a picture it will result in a page showing all the images with the same category. This will use HTMX hopefully in the final product, but I'm trying and failing to implement it using regular Django views initially.
As I said, this is my first solo project, so I'm very much a beginner, I know this isn't a debug service but just wanted some pointers on where I could be going wrong. Another set of eyes as you will.
I followed the docs on dynamic filtering CBV. I have overwritten get_queryset passing the Category slug into the kwargs and I have overwritten the get_context_dataso I can pass slug into the template.
I am getting a Reverse for 'select' with arguments '('',)' not found. 1 pattern(s) tried: ['select/(?P<slug>[-a-zA-Z0-9_]+)\\Z'] error, so I belive the problem is in my template/URLconf.
Models. Media with a FK to it's Category
class Category(models.Model):
title = models.CharField(max_length=200, null=True)
slug = AutoSlugField(populate_from='title')`
class Media(models.Model):
timestamp = models.DateTimeField()
image = models.ImageField(upload_to="media")
url = models.URLField()
order = models.IntegerField(default=0)
visable = models.BooleanField(default=True)
categories = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
Views, IndexView is entire gallery and SelectView is image by category
class IndexView(ListView):
template_name = "main/index.html"
model = Media
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context ['main_images'] = Media.objects.filter(visable=True)
return context
class SelectView(ListView):
template_name = "main/select.html"
model = Media
def get_queryset(self):
self.category = get_object_or_404(Category, title=self.kwargs['slug'])
return Media.objects.filter(categories__title=self.category)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['slug'] = self.category
return context
URLconf with select being the relevant pattern.
app_name = "main"
urlpatterns = [
path("", views.IndexView.as_view(), name="home"),
path("about", views.AboutView.as_view(), name="about"),
path("contact", views.ContactView.as_view(), name="contact"),
path("select/<slug:slug>", views.SelectView.as_view(), name="select"),
]
Gallery template I have a for loop to display the IndexView. I think the problem is with the Href (which I want to take my to SelectView). I am passing slug in the {% url %} but think it should be image.categories__slug? I have tried this but it still doesn't work. I am stumped.
{% for image in main_images %}
<div class="cbp-item web-design print">
<a href="{% url "main:select" slug %}" class="cbp-caption cbp-singlePageInline">
<div class="cbp-caption-defaultWrap"> <img src="{{ MEDIA_URL }} {{ image.image.url }}"alt=""> </div>
{% endfor %}
Many thanks.
I think what you want is to access the slug field on the image.categories field for each iteration.
{% for image in main_images %}
...
<a href="{% url 'main:select' image.cateogries.slug %}" class="cbp-caption cbp-singlePageInline">
...
{% endfor %}
In addition to that, I'd recommend that you do a lookup for the receiving slug instead of the title on the Category model. For example, if you should save I love this day as the title, the slug field would have I-love-this-day.
What you have:
def get_queryset(self):
self.category = get_object_or_404(Category, title=self.kwargs['slug'])
return Media.objects.filter(categories__title=self.category)
title=self.kwargs['slug'] won't find a title if your passing I-love-this-day as the slug. I'd suggest using slug=self.kwargs['slug']. See the below updates:
def get_queryset(self):
# Also, the self keyword is not needed here either -> self.category
category = get_object_or_404(Category, slug=self.kwargs['slug']) # updated
return Media.objects.filter(categories__title=category.title) # updated
Additionally, I see where you're passing slug as a value via the context variable within the SelectView... I suggest you pass the category object explicitly via the context variable to the template where you can access the fields from your template if necessary.
Within the get_context_data():
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# context['slug'] = self.category
context['category'] = get_object_or_404(Category, slug=self.kwargs['slug'])
return context

Django, just showing once when I use multiple forms with rich editor

I am creating comment area and reply to comment area for users. And I using django-ckeditor for this but there is a problem. When I add "reply form" just showing once in the page. Not showing other forms. The reply system its works just its not showing ckeditor(Rich editor).
I am add some photos for better understanding:
second form in same page:
inspect of first form:
my Models:
class UserMessages(models.Model):
postMessages = RichTextUploadingField(null=True, verbose_name="Message")
post = models.ForeignKey(
UserPosts, on_delete=models.CASCADE, verbose_name="Linked Post", null=True)
username = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="Username", null=True)
replies = models.ForeignKey("self", blank=True, null=True, on_delete=models.CASCADE)
my Forms:
class MessageForm(forms.ModelForm):
class Meta:
model = UserMessages
fields = ("postMessages",)
widgets = {
"postMessages": forms.TextInput(attrs={"class":"form-control"}),
#And I tried this but not works..
class ReplyFormMessage(forms.ModelForm):
class Meta:
model = UserMessages
fields = ("replies",)
my HTML:
<form method="POST" >
{% csrf_token %}
{{form.media}}
{{ form }}
<input type="hidden" name="replies_id" value="{{ message.id }}">
<input type="submit" value="Reply" class="btn btn-default">
</form>
as for me, ckeditor just using one id for all form in page. So, do you have an idea?
First of all, you cannot use one id for multiple elements in HTML. The purpose of id is to uniquely identify your HTML tags, you can use classes if you want to generalize the tags.
Secondly, make use of Django inline formsets to achieve what you want.

Django - URL template tag with 2 arguments

I'm new to Django and sorry if the question is silly. I have a URL with two slugs, one for the category which is a manytomany field and one for the posts:
path('<slug:slug_staticpage>/<slug:slug>/', views.post, name='post_detail')
views.py
def post(request, slug, slug_staticpage):
category = get_object_or_404(StaticPage, slug_staticpage=slug_staticpage)
blogpost = get_object_or_404(Post, slug=slug)
post = Post.objects.filter(slug=slug)
page_id = category.pk
related_posts = Post.objects.filter(static_page__pk=page_id)[:6]
return render(request, "blog/blog-post-final.html", {'slug': slug, 'slug_staticpage': category.slug_staticpage, 'post':post, 'related_posts':related_posts})
models.py
class Post(models.Model):
title = models.CharField(max_length=300)
content = RichTextField()
slug = models.SlugField(max_length=200, unique=True)
published = models.DateTimeField(verbose_name="Published", default=now())
image = models.ImageField(verbose_name="Image", upload_to="blog", null=True, blank=True)
author = models.ForeignKey(User, verbose_name="Author", on_delete=models.PROTECT)
categories = models.ManyToManyField(Category, verbose_name="Categories", related_name="get_post")
static_page = models.ManyToManyField(StaticPage, verbose_name="Página estática", related_name="get_post")
created = models.DateField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.IntegerField(choices=STATUS, default=0)
I want to display those URLs in my homepage via the template tag, but I don't know how to retrieve the slug_staticpage slug:
<a href="{% url 'blog:post_detail' slug_staticpage=post.slug_staticpage slug=post.slug %}">
The above syntax is not working, I can only retrieve the slug of the post.
Can someone help me sort this out? Thanks a lot for your precious help :)
Askew
As you have a Many-to-Many relationship, you should have a single url for each of those static_page objects.
You can achieve that via iterating over the static_page objects:
{% for slug_url in post.slug_staticpage.all %}
<a href="{% url 'blog:post_detail' slug_staticpage=slug_url slug=post.slug %}">
{% endfor %}
although I'm not sure whether you really need such relationship or not.
I solved it myself by adding the following to models.py
def get_absolute_url(self):
return reverse('blog:post_detail', kwargs={'slug_staticpage':self.static_page.slug_staticpage, 'slug':self.slug})
Cheers!

Rendering blank ImageFields in Django template

I am trying to render an instance of this model in my template:
class Candidate(models.Model):
UserID = models.ForeignKey(User, on_delete=models.CASCADE)
ElectionID = models.ForeignKey(Election, on_delete=models.CASCADE)
Bio = models.CharField(max_length=500, blank=True)
Poster = models.ImageField(upload_to="profilepics/", null=True, blank=True)
I am having trouble with rendering the Poster attribute which, as you can see, has the option of being blank.
When I try to render the following html in the template:
<h1>{{candidate.UserID.first_name}} {{candidate.UserID.last_name}} ({{candidate.UserID.username}})</h1>
<h2>{{candidate.ElectionID}}</h2>
<img src="{{candidate.Poster.url}}" width=240><br>
I get an error if Poster is blank.
ValueError: The 'Poster' attribute has no file associated with it.
How do I prevent this error? I want to show nothing if Poster is blank and obviously show the image if it isn't.
Use an if condition.
<h1>{{candidate.UserID.first_name}} {{candidate.UserID.last_name}} ({{candidate.UserID.username}})</h1>
<h2>{{candidate.ElectionID}}</h2>
{% if candidate.Poster %}
<img src="{{candidate.Poster.url}}" width=240>
{% endif %}
<br>

Show images on Django Non Rel Templates using Google App Engine

I'm doing an app with Django Non Rel on GAE, and i want to show the Profile Image of the user in the template but i can't here is the model:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class userProfile(models.Model):
def url(self, filename):
url = "MultimediaData/Users/%s/%s"%(self.user.username, filename)
return url
user = models.OneToOneField(User)
email_public_user = models.EmailField(blank=True, null=True)
url_user = models.CharField(max_length=200, blank=True, null=True)
company_user = models.CharField(max_length=200, blank=True, null=True)
position_user = models.CharField(max_length=200, blank=True, null=True)
photo_user = models.ImageField(upload_to=url)
def __unicode__(self):
return self.user.username
For now i'm adding the photo via admin to see if i can show the image, here is the template
<div class="navbar-header nav-img">
{% if user.get_profile.photo_user %}
<img class="navbar-brand" src="{{user.get_profile.photo_user}}">
<p class="navbar-brand">{{user.get_username}}</p>
{% else %}
<img class="navbar-brand" src="/media/img/principal_html/img1.png">
<p class="navbar-brand">{{user.get_username}}</p>
{% endif %}
It shows the username, but not the image, i put the user.get_profile.photo_user in a and i got this
ahRkZXZ-c29mdHN5c3RlbWFuYWdlcnIiCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGICAgICAzKYKDA/MultimediaData/Users/[username]/img.jpg
There's no view yet because im uploading the image using the django admin and when i save the user with his photo shows the same url
How can i solve this? I need to show the image...plz help

Categories

Resources