Django CBV ModelForm hx-post not working with HTMX - python

I have a partial form rendered with HTMX rendered in my page upload.html:
{% extends 'base.html' %}
<p>Veuillez choisir ci-dessous entre l'upload d'un fichier de commandes ou l'upload d'un fichier fournisseur :</p>
<h2>Upload fichier <u>transporteur</u></h2>
<button hx-get="{% url 'tool:upload-form' %}" hx-swap="afterend" hxtarget="#transporterforms">Add transporter</button>
<div class="transporterforms">
</div>
{% block content %}
And my upload-form.html:
<div hx-target="this" hx-swap="outerHTML">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit" hx-post=".">Submit</button>
</form>
</form>
</div>
Here is how I manage my form in views.py:
class TransporterFileFormPartialView(FormView):
form_class = TransporterFileForm
template_name = 'tool/upload-form.html'
success_url = '.'
def form_valid(self, form):
transporter_file = TransporterFile.objects.create(
file=form.cleaned_data['file'],
transporter=form.cleaned_data['transporter']
)
transporter_file_pk = transporter_file.pk
return super().form_valid(form)
class CompareFormView(CustomLoginRequiredMixin, RequestFormMixin, TemplateView):
""" View to show results of comparison between two files. """
template_name = 'tool/upload.html'
# success_url = '.'
def post(self, *args, **kwargs):
form = TransporterFileForm(self.request.POST)
if form.is_valid():
obj = form.save(commit=False)
# transporter_file = get_object_or_404(TransporterFile, pk=form.pk)
obj.save()
transporter_file = TransporterFile.objects.get(pk=obj.pk)
transporter_file_pk = transporter_file.pk
return redirect(reverse_lazy('tool:upload'))
And in my forms.py:
class TransporterFileForm(forms.ModelForm):
class Meta:
model = TransporterFile
fields = ('file', 'transporter')
My urls.py are as follows:
urlpatterns = [
path('', TemplateView.as_view(template_name="tool/home.html"), name="home"),
path('upload-form/', TransporterFileFormPartialView.as_view(), name="upload-form"),
path('upload-detail/<int:pk>', TransporterFileFormDetailView.as_view(), name="upload-detail"),
path('upload-detail/<int:pk>/delete/', TransporterFileFormDeleteView.as_view(), name="upload-delete"),
path('report/add-report', UserAddReportView.as_view(), name='add-report'),
path('report/add-report/2', CompareFormView.as_view(), name='upload'),
path('reports/', UserReportsView.as_view(), name='reports'),
]
My main issue is with upload-form.html. When I try
<button type="submit" hx-post=".">Submit</button>
It is not working. I have the following message:
[19/May/2022 15:00:05] "GET /upload-form/ HTTP/1.1" 200 896
Not Found: /report/add-report/
But when I try without hx-post, it is working
<button type="submit">Submit</button>
I cannot figure out why?

As the error message indicates, the /report/add-report/ path with a trailing slash does not exist, because you have defined it without trailing slash: path('report/add-report', UserAddReportView.as_view(), name='add-report'),. So you can just add the missing slash, or use the url function in the template to obtain the correct path of the endpoint:
<button type="submit" hx-post="{% url 'tool:add-report' %}">Submit</button>

Related

django form validation error not showing in DetailView

What am i trying to do is show comment form in Detailview.
it can add comment, but when user write noting in the form it doesn't show error message.
I think i need to return error form somehow, i can not find how
this is my code
forms.py
class CommentForm(forms.ModelForm):
comment_text = forms.CharField(max_length=300,
error_messages={'required':'need comment!!!'},
)
class Meta:
model = Comment
fields= ('comment_text',)
views.py
#login_required
def add_comment(request, pk):
parent_photo = get_object_or_404(Photo, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.parent_photo = parent_photo
comment.user = request.user
comment.save()
return redirect(parent_photo.get_absolute_url())
else:
######## this part??? ########
return redirect(parent_photo.get_absolute_url(), {'comment_form': form })
return redirect(parent_photo.get_absolute_url())
class PhotoDetailView(DetailView):
model = Photo
template_name = 'photo_detail.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data()
object = self.get_object()
total_likes = object.total_likes()
context['comment_form'] = CommentForm
context['total_likes'] = total_likes
return context
urls.py
urlpatterns = [
path('<int:pk>/', views.PhotoDetailView.as_view(), name = 'detail'),
path('<int:pk>/add_comment/', views.add_comment, name='add_comment'),
]
templates
{% if user.is_authenticated%}
<div class=" my-3">
<p class='mb-0 ml-2'>Leave a comment ! </p>
<form class="input-group" id='comment_form' method="POST"
action="{{ photo.get_absolute_url }}add_comment/">
{% csrf_token %}
{% for field in comment_form %}
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}"
name="{{ field.name }}">
{% if field.errors %}
<small class='text-danger'>{{ field.errors }}</samll>
{% endif %}
<div class="input-group-append">
<button type="submit" class="btn btn-primary btn-sm">ADD</button>
</div>
{%endfor%}
</form>
</div>
{% endif %}
i put 'required' in input
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}"
name="{{ field.name }}">
and in add_comment view, only consider is_valid() case.
#login_required
def add_comment(request, pk):
parent_photo = get_object_or_404(Photo, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.parent_photo = parent_photo
comment.user = request.user
comment.save()
return redirect(parent_photo.get_absolute_url())
return redirect(parent_photo.get_absolute_url())
it is not the answer for my question,
but works as i intended.

Django 'Model matching query does not exist.' error

I have a three simple models. User, Restaurant, Menu. A single user can have many restaurants, and each restaurant can have many Menus. I am using the generic Django CreateView for the Posting of the Restaurants and Menus to their respective models. This works for The restaurants, But fails for the Menus and I get a "Restaurant matching query does not exist" ERROR. I feel that it is a URL issue because I can reach the template if I input it manually, but fails when i use the button.
VIEWS.py
#login_required
def profile(request, pk):
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'user': user,
'rests': Restaurant.objects.filter(account=request.user).order_by('-date'),
'countRests': Restaurant.objects.filter(account=request.user).count(),
}
return render(request, 'restaurants/profile.html',context)
class RestCreateView(LoginRequiredMixin, CreateView):
template_name = 'restaurants/makeRestaurant.html'
form_class = RestCreateForm
def form_valid(self, form):
form.instance.account = self.request.user
return super().form_valid(form)
def RestMenus(request, pk, name):
rest = Restaurant.objects.get(name=name)
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'rest': rest,
'user': user,
'menus': Menu.objects.filter(restaurant=rest).order_by('-uploadDate'),
'countMenus': Menu.objects.filter(restaurant=rest).count(),
}
return render(request, 'restaurants/menus.html',context)
class MenuCreateView(LoginRequiredMixin, CreateView):
template_name = 'restaurants/makeMenu.html'
form_class = MenuCreateForm
def form_valid(self, form):
form.instance.restaurant = self.request.restaurant
return super().form_valid(form)
URLS.py
urlpatterns = [
path('', home, name='home'),
path('profile/<int:pk>/',profile, name='profile'),
path('profile/<int:pk>/createRest/', RestCreateView.as_view(), name='createRest'),
path('profile/<int:pk>/restaurant/<str:name>',RestMenus, name='RestDetail'),
path('profile/<int:pk>/restaurant/<str:name>/createMenu/', MenuCreateView.as_view(), name='createMenu'),
]
FORMS.py
class RestCreateForm(forms.ModelForm):
class Meta:
model = Restaurant
fields = [
'name'
]
class MenuCreateForm(forms.ModelForm):
class Meta:
model = Menu
fields = [
'name',
'menuFile'
]
Template (Menus.html)
<section id="menusdash">
<div class="container">
<br>
<h3>{{ rest.name }}'s Menus</h3>
<br>
<div class="row">
<div class="col-md-10">
{% if countMenus == 0 %}
<p>You have no Menus</p>
{% else %}
{% for menu in menus %}
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Menu Name: {{ menu.name }}</h5>
View Menu
View QR Code
Edit
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div class="col-md-2">
<button>Make a Menu</button>
</div>
</div>
</div>
</section>
The URL seems to drop the str:name/ for the menu create template. Is it possible to pass a second argument using a CreateView, SO that i can have the PK and String:name in the url?

How return image url and prepopulate a form at the same time? Error in image url inside the template

I am having a problem to prepopulate a form and also return the image url of the account:
My view:
class DadosProfissionaisViewUpdate(LoginRequiredMixin, FormView):
template_name = 'accounts/udadosprofissionais.html'
form_class = DadosProfissionaisForm
model = DadosProfissionais
def get_initial(self):
obj = DadosProfissionais.objects.get(user = self.request.user)
initial = super(DadosProfissionaisViewUpdate, self).get_initial()
initial = model_to_dict(obj)
return initial
def form_valid(self, form):
obj = DadosProfissionais.objects.get(user = self.request.user)
obj.user = self.request.user
obj.nome_publico = form.cleaned_data['nome_publico']
obj.nome_consult = form.cleaned_data['nome_consult']
obj.cep_atend = form.cleaned_data['cep_atend']
obj.endereco_atend = form.cleaned_data['endereco_atend']
obj.bairro_atend = form.cleaned_data['bairro_atend']
obj.save()
messages.success(self.request, _('Seus dados foram atualizados com sucesso.'))
return redirect('home')
My template:
{% block content %}
<div class="text-center">
<img src="{{ profile_pic.url }}" class="rounded" alt="img">
</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
<button class="btn btn-primary">Enviar</button>
</form>
{% endblock %}
My urls - added MEDIA_URL:
urlpatterns = [
path('admin/', admin.site.urls),
........
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}),
path('accounts/', include('accounts.urls')), ]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
My form:
class DadosProfissionaisForm(forms.ModelForm):
nome_publico = forms.CharField(label='Nome Público')
nome_consult = forms.CharField(label='Nome do Consultório')
cep_atend = forms.CharField(label='CEP')
endereco_atend = forms.CharField(label='Rua')
bairro_atend = forms.CharField(label='Bairro')
profile_pic = forms.ImageField(label='Foto')
class Meta:
model = DadosProfissionais
fields = ['nome_publico', 'nome_consult', 'cep_atend', 'endereco_satend',
'bairro_atend', 'profile_pic']
I do not know how the correct way to prepolute the form and also load this image profile url in this template. Can anybody give a hand!? Thanks.
i have some news...
Looking for a way to display the image in a prepopulate form, i read it is not possible because a question of security in django. Well, i will try something else, maybe another template just to change the image without prepopulate it.
Thanks

View with more than one button redirecting to different pages

I have a View (I use FormView) that will render a dropdown option. When I select an option, an Ajax function populate the rest of the Form. After the datas are shown, the user can press different buttons to redirect to other pages. For now, I want just 2 buttons. But I don't know how to do this, I've tried some codes and got nothing, not even got redirect to other page. The first page are "Teste" and the buttons need to redirect to "identificacao", or "mapa". Here are my following code
urls.py:
path('teste', views.TesteView.as_view(), name="teste"),
path('identificacao', TemplateView.as_view(template_name = 'solid/identificacao.html'), name="identificacao"),
path('mapa', views.MapaView.as_view(), name="mapa")
view.py:
class DutosView(generic.FormView):
# FormView precisa ser relacionada a um Model. Mesmo que não use ao longo do
# programa a variável "model", como é o caso presente.
template_name = 'solid/teste.html'
form_class = Teste
# success_url = 'solid/mapa.html'
# success_url = reverse_lazy('mapa')
success_url = '/mapa/'
def form_valid(self, form):
nomeDuto = form.cleaned_data['nomeDuto']
codigoDuto = DUTO.objects.values_list('DU_CD_ID_Duto',flat = True).filter(DU_DS_Nome_Do_Duto = nomeDuto)
self.request.session['nomeDuto'] = nomeDuto
latlongs = PIG.objects.values_list("PI_VL_Latitude","PI_VL_Longitude").filter(PI_CD_ID_Duto = codigoDuto)
latlongs = [[float(x[0]),float(x[1])] for x in latlongs]
latitudeIni = latlongs[0][0]
longIni = latlongs[0][1]
self.request.session['latlongs'] = latlongs
self.request.session['latitudeIni'] = latitudeIni
self.request.session['longIni'] = longIni
return super().form_valid(form)
# I've tried the code above to redirect when I click on the button and didn't work.
# But, even the super().form_valid isn't redirecting to succes_url.
#if 'Mapa' in self.request.POST:
# redirect('mapa')
#if 'Confirmar' in self.request.POST:
# I've thought to assign a new value do success_url here to "identificacao".
# redirect('identificacao')
teste.html:
<form method="post" action="" id="testeForm" data-nome-teste-url="{% url 'ajax_load_nome_teste' %}" novalidate>
{% csrf_token %}
<div>
<table id = "formTable">
<h3>Selecione um Nome:</h1>
<br>
<div class="fieldWrapper">
{{ form.nomeTeste.errors }}
<label for="nomeTeste"> Nome: </label>
{{ form.nomeTeste }}
</div>
<br>
<div id="id_campos">
</div>
</table>
<br>
<input type="submit" value="Confirmar">
<input type="submit" value="Mapa" name="mapa">
</div>
</form>
In id_campo, I put a python function to render the rest of the form with the selection of nomeTeste. These fields are from the Database and will have some function later.
The name and value of the submit input clicked will be passed in the POST data
<input type="submit" value="Button 1" name="button_1">
<input type="submit" value="Button 2" name="button_2">
Then in your view you can look for the name of the submit. I would suggest putting this logic in the get_success_url method
def get_success_url(self):
if 'button_1' in self.request.POST:
return redirect('url_for_button_1')
elif 'button_2' in self.request.POST:
return redirect('url_for_button_2')
# etc

Django Website - TemplateDoesNotExist at /edit/117/

I'm using UpdateView to edit data using forms.
After cliking the Edit button a modal is being popped up with a few forms that can be edited and then after I edit and click confirm I get an error:
TemplateDoesNotExist at /edit/117/ (or other pk...)
DevOpsWeb/serverlist_form.html
Request Method: POST
Request URL: http://devopsweb:8000/edit/117/
Django Version: 1.11.6
Exception Type: TemplateDoesNotExist
Exception Value:
DevOpsWeb/serverlist_form.html
Why do I get this error?
Why when I get the modal the information of the PK is blank...?
Does anyone know any of these questions? I'm really stuck :(
Thank you!
view.py-
from django.shortcuts import render_to_response
from django.shortcuts import get_object_or_404
from django.shortcuts import render, redirect
from django.template import RequestContext
from django.views.generic import TemplateView, UpdateView, DeleteView, CreateView
from DevOpsWeb.forms import HomeForm
from DevOpsWeb.models import serverlist
from django.core.urlresolvers import reverse_lazy
from simple_search import search_filter
from django.db.models import Q
class HomeView(TemplateView):
template_name = 'serverlist.html'
def get(self, request):
form = HomeForm()
query = request.GET.get("q")
posts = serverlist.objects.all()
if query:
posts = serverlist.objects.filter(Q(ServerName__icontains=query) | Q(Owner__icontains=query) | Q(Project__icontains=query) | Q(Description__icontains=query) | Q(IP__icontains=query) | Q(ILO__icontains=query) | Q(Rack__icontains=query))
else:
posts = serverlist.objects.all()
args = {'form' : form, 'posts' : posts}
return render(request, self.template_name, args)
def post(self,request):
form = HomeForm(request.POST)
posts = serverlist.objects.all()
if form.is_valid(): # Checks if validation of the forms passed
post = form.save(commit=False)
#if not form.cleaned_data['ServerName']:
#post.servername = " "
post.save()
#text = form.cleaned_data['ServerName']
form = HomeForm()
return redirect('serverlist')
args = {'form': form, 'text' : text}
return render(request, self.template_name,args)
class PostDelete(DeleteView):
model = serverlist
success_url = reverse_lazy('serverlist')
class PostEdit(UpdateView):
model = serverlist
#post = serverlist.objetcs.get(server_id=server_id)
fields = ['ServerName','Owner','Project','Description','IP','ILO','Rack','Status']
success_url=reverse_lazy('serverlist')
urls.py -
from django.conf.urls import url, include
from DevOpsWeb.views import HomeView
from DevOpsWeb.views import PostDelete
from DevOpsWeb.views import PostEdit
from django.contrib import admin
admin.autodiscover()
urlpatterns = [
# Examples:
url(r'^$', HomeView.as_view(), name='serverlist'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
#DevOpsWeb:8000/Delete/
url(r'^delete/(?P<pk>\d+)/$', PostDelete.as_view(), name="delete_post"),
url(r'^django_popup_view_field/', include('django_popup_view_field.urls', namespace="django_popup_view_field")),
url(r'^admin/', include(admin.site.urls)),
#DevOpsWeb:8000/edit/
url(r'^edit/(?P<pk>\d+)/$', PostEdit.as_view(), name="edit_post"),
]
forms.py -
from django import forms
from DevOpsWeb.models import serverlist
class HomeForm(forms.ModelForm):
ServerName = forms.CharField(widget=forms.TextInput,max_length = 30,required=False)
Owner = forms.CharField(max_length = 50,required=False)
Project = forms.CharField(max_length = 30,required=False)
Description = forms.CharField(max_length = 255,required=False)
IP = forms.CharField(max_length = 30,required=False)
ILO = forms.CharField(max_length = 30,required=False)
Rack = forms.CharField(max_length = 30,required=False)
Status = forms.CharField(max_length = 30,required=False)
class Meta:
model = serverlist
fields = ('ServerName' ,'Owner','Project','Description','IP','ILO','Rack','Status',)
class AutoCompleteModelChoiceField(forms.ModelChoiceField):
widget = forms.TextInput
def clean(self, value):
value = super(AutoCompleteModelChoiceField, self).clean(value)
return value
class serverForm(forms.ModelForm):
hotel = AutoCompleteModelChoiceField(queryset=serverlist.objects.all())
index.html (The part with the edit button)-
<div class="modal fade bd-example-modal-sm" id="Edit{{server.id}}" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Server <b>{{ server.ServerName }}</b> </h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form action="{% url 'edit_post' server.id %}" method="post"> {% csrf_token %}
<!--<center> {{ form.as_p }} </center> -->
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
<!-- {{ field.label_tag }} -->
<small><b>{{ field.html_name }}<p align="left"></b> {{ field }}</small> </p>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</div>
<div class="wrapper">
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
<h2><button type="submit" class="save btn btn-success btn-lg">Confirm</button></h2>&nbsp&nbsp&nbsp
<h2><button type="submit" class="btn btn-secondary btn-lg" data-dismiss="modal">Cancel</button></h2>
</div>
</form>
</td>
</div>
</tr>
{% endfor %}
Since you are not overriding one of UpdateView attributes, template_name_suffix, template_name or get_templates_names(), default template name that your view would be looking is <model_name>_form.html. And you don't have that template

Categories

Resources