im trying to add to my html a button that appears only on certain events, that works for me but i want to add a onclick script/function that will invoke a backend view.py function that deletes the specific room on click, the room model is : owner(fk), name, slug.
and the user model is : username password1 password2.
i just need to know how to invoke an onclick event that will call the backend function in my views.
rooms.html
{% extends 'core/base.html' %}
{% block title %} Rooms | {% endblock %}
{% block content %}
<div class="main">
<h1>Rooms</h1>
</div>
<div class="rooms-container">
{% for room in rooms %}
<div class="room">
<div class="room-info">
<h1 class="room-title">{{ room.name }}</h1>
Join Room
{% if request.user == room.owner %}
<button class="room-delete" id="roomDelete">Delete Room</button>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block scripts %}
<!-- todo: add delete room button functionality. -->
{% endblock %} ```
views.py
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
from django.contrib import messages
from .models import Room, Message
#login_required
def rooms(request):
if request.method == 'POST':
room_owner = request.user
room_name = request.POST['room-name']
if not Room.objects.filter(slug = room_name).exists():
if room_name == '' or room_name.isspace() or room_name.startswith(' '):
messages.info(request, 'Invalid room name, spaces-only or string that starts with spaces is invalid.')
else:
new_room = Room(owner = room_owner,name = room_name,slug = room_name)
new_room.save()
else:
messages.info(request, 'That room already exists!, try a different name.')
rooms = Room.objects.all()
return render(request, 'room/rooms.html', {'rooms': rooms})
#login_required
def room(request, slug):
room = Room.objects.get(slug=slug)
messages = Message.objects.filter(room=room)[0:25]
return render(request, 'room/room.html', {'room': room, 'messages': messages})
#csrf_exempt
def delete_room(request): ## <<------ invoke this from html call.
print("hey")
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.rooms, name='rooms'),
path('<slug:slug>/', views.room, name='room'),
path('', views.delete_room, name='delete_room'),
]
now i have more 2 urls.py, the project has 3 folders, 1 main (livechatapp) with settings and all, one for core htmls (core) and one for rooms html (room)
core/urls
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path('', views.frontpage, name='frontpage'),
path('signup/', views.signup, name='signup'),
path('login/', auth_views.LoginView.as_view(template_name='core/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
and finally
livechatapp/urls
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('core.urls')),
path('rooms/', include('room.urls')),
path('admin/', admin.site.urls),
]
and this is the projects overview folders and files :
this is the project
IF you want do it in standard html:
% extends 'core/base.html' %}
{% block title %} Rooms | {% endblock %}
{% block content %}
<div class="main">
<h1>Rooms</h1>
</div>
<div class="rooms-container">
{% for room in rooms %}
<div class="room">
<div class="room-info">
<h1 class="room-title">{{ room.name }}</h1>
Join Room
{% if request.user == room.owner %}
<form method="POST" action="{% url 'delete_room' room.slug %}>
<button type="submit" class="room-delete">Delete Room</button></form>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block scripts %}
<!-- todo: add delete room button functionality. -->
{% endblock %} ```
urls:
urlpatterns = [
path('', views.rooms, name='rooms'),
path('<slug:slug>/', views.room, name='room'),
path('delete/<slug:slug>/', views.delete_room, name='delete_room'),
]
views:
#csrf_exempt
def delete_room(request,slug):
if request.method == 'POST':
try:
room = Room.objects.get(slug=slug, owner=request.user)
room.delete()
except ObjectDoesNotExist:
print('there is no room with this slug or you are not owner')
return redirect('rooms')
i advice to use csrf. allways try to use POST when manipulatind data in db.
If you want to work it without redirect you need to think of ajax call or maby htmx
Related
I am trying to display 2 forms in my contact.html page in a Django project. Each form needs to display a success message when being successfully submitted by users. The problem is that both forms in the page show the same success message when either of them being submitted.
How can I tie the success message to the submitted form on my HTML page?
forms.py
from dataclasses import field, fields
from logging import PlaceHolder
from socket import fromshare
from django import forms
from .models import ServiceRequest, Contact, Newsletter
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name','email','phone','message']
class NewsletterForm(forms.ModelForm):
class Meta:
model = Newsletter
fields = ['name','email']
views.py
from http.client import HTTPResponse
from multiprocessing import context
from django.shortcuts import render
from django.views.generic import TemplateView
from .forms import ContactForm, NewsletterForm, ServiceRequest, ServiceRequestForm
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.urls import reverse
def Contact(request):
contact_form = ContactForm(request.POST or None)
newsletter_form = NewsletterForm(request.POST or None)
if request.method == 'POST' and contact_form.is_valid():
contact_form.save()
messages.success(request, "Thanks for contacting us!")
return HttpResponseRedirect(request.path_info)
elif request.method == 'POST' and newsletter_form.is_valid():
newsletter_form.save()
messages.success(request, "Thanks for joining our newsletter!")
return HttpResponseRedirect(request.path_info)
context = {
"contact_form":contact_form,
"newsletter_form":newsletter_form,
}
return render(request, "main/contact.html", context)
contact.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div>
<!-- Message from backend -->
{% for message in messages %}
{% if message.tags == 'success' %}
<div>{{message}}
</div>
{% endif %}
{% endfor %}
<form method="POST">
{% csrf_token %}
<div class="row">
{{ contact_form.name|as_crispy_field }}
{{ contact_form.email|as_crispy_field }}
{{ contact_form.phone|as_crispy_field }}
{{ contact_form.message|as_crispy_field }}
</div>
</div>
<button type="submit">Submit</button>
</form>
</div>
<div>
<!-- Message from backend -->
{% for message in messages %}
{% if message.tags == 'success' %}
<div>{{message}}
</div>
{% endif %}
{% endfor %}
<form method="POST">
{% csrf_token %}
<div class="row">
{{ newsletter_form.name|as_crispy_field }}
{{ newsletter_form.email|as_crispy_field }}
</div>
<button type="submit">Submit</button>
</form>
</div>
{% endblock %}
After submitting one form on this page, both forms show the success message:
You can use extra_tags of messages framework Django docs:
So in view:
messages.success(request, "Thanks for contacting us!", extra_tags='form1')
And in template:
{% for message in messages %}
{% if message.tags == 'success' and message.extra_tags == 'form1' %}
<div>{{message}}
</div>
{% endif %}
{% endfor %}
I have a list of items and I am trying to add a link to the item's title to direct the user to the item's own page. However, I am getting Reverse for 'listing' with arguments '('',)' not found. 1 pattern(s) tried: ['listing/(?P<listing_id>[0-9]+)\\Z'] error and I couldn't figure out what I did wrong.
The error is in line<h2>{{auction.title}}</h2> of index.html
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("create", views.create_listing, name="create"),
path("listing/<int:listing_id>", views.listing, name = "listing"),
]
views.py:
def listing(request,listing_id):
listing = AuctionItem.objects.get(id = listing_id)
return render(request, "auctions/listing.html",{
"listing":listing
})
index.html:
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
{% for auction in auctions %}
<div class = "frame">
<img src="{{auction.image}}" style= "width: 30vw;">
<h2>{{auction.title}}</h2>
<div id="text"><strong>Price:</strong> ${{auction.price}}</div>
<div id="text"><strong>Description:</strong> {{auction.description}}</div>
<div id="text"><strong>Category:</strong> {{auction.category}}</div><br>
<div id="date">Created {{auction.date}}</div>
</div>
{% empty %}
<li>No item.</li>
{% endfor %}
{% endblock %}
The object is named auction in the context when rendering, so:
<h2>{{auction.title}}</h2>
or perhaps better to use the .pk:
<h2>{{auction.title}}</h2>
I have a problem while using Django. I was trying to create a learning_log web application from my book and came across this error: NoReverseMatch at /edit_entry/8/
Reverse for 'topic' with arguments '('',)' not found. 1 pattern(s) tried: ['topics/(?P<topic_id>[0-9]+)/\Z']. It said it was because of this line in my edit_entry.html file: p>{{ topic }}</p> but I checked my entire project and couldn't find the reason,
Here is my urls.py:
from django.urls import path
from . import views
app_name = 'learning_logs'
urlpatterns = [
path('', views.index, name='index'),
path('topics/', views.topics, name='topics'),
path('topics/<int:topic_id>/', views.topic, name='topic'),
path('new_topic/', views.new_topic, name='new_topic'),
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
]
views.py:
from django.shortcuts import render, redirect
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
def index(request):
"""The home page for Learning Log."""
return render(request, 'learning_logs/index.html')
def topics(request):
"""Show all topics."""
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
"""Show a single topic and all its entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries':entries}
return render(request, 'learning_logs/topic.html', context)
def new_topic(request):
"""Add a new topic."""
if request.method !='POST':
form = TopicForm()
else:
form = TopicForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topics')
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
def edit_entry(request, entry_id):
"""Edit and existing entry."""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method !='POST':
form = EntryForm(instance=entry)
else:
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html')
models.py:
from django.db import models
class Topic(models.Model):
"""A topic the user is learning about."""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string representation of the model."""
return self.text
class Entry(models.Model):
"""Something specific about a learned topic."""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""Return a string representation of the model."""
return f"{self.text[:50]}..."
forms.py:
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
base.html:
<p>
Learning Log
Topics
</p>
{% block content %}{% endblock content %}
topics.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
{{ topic }}
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
Add a new topic
{% endblock content %}
new_topic.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a new topic:</p>
<form action="{% url 'learning_logs:new_topic' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Add topic</button>
</form>
{% endblock content %}
new_entry.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>{{ topic }}</p>
<p>Add a new entry:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name='submit'>Add entry</button>
</form>
{% endblock content %}
topic.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<p>
Add new entry
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
<p>
Edit entry
</p>
</li>
{% empty %}
<li>There are no entries for this topic yet.</li>
{% endfor %}
</ul>
{% endblock content %}
edit_entry.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>{{ topic }}</p>
<p>Edit entry</p>
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save changes</button>
</form>
{% endblock content %}
index.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Learning Log helps you keep track of what you've learned.</p>
{% endblock content %}
and that is literally everything I checked and I can't seem to find the error, please help me find the error and fix it.
In views.py, on the edit_entry function, pass context to the render method.
On the very last line of the edit_entry function, in the views.py file, add the context to the arguments you are passing to the returned render method.
def edit_entry(request, entry_id):
"""Edit and existing entry."""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method !='POST':
form = EntryForm(instance=entry)
else:
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html')
Correct the last line as follows, by adding context. This is so can you can use the entry, topic, and form that you defined in the context in the html template.
return render(request, 'learning_logs/edit_entry.html', context)
after researching for hours I cannot get rid of this error, I hope someone can help me.
Models:
class Puja(models.Model):
seller = models.OneToOneField(Seller, on_delete=models.CASCADE)
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True,null=True)
title = models.CharField(max_length=100)
video = models.FileField(blank=True)
photo = models.ImageField(blank=True)
published_date = models.DateTimeField("Published: ",default=timezone.now())
bidding_end = models.DateTimeField()
starting_price = models.IntegerField(default=1)
#slug = models.SlugField(null=True)
def __str__(self):
return str(self.title)
#def get_absolute_url(self):
# return reverse('bidding_list_detail', args=[str(self.id)])
#slug time
def get_absolute_url(self):
return reverse('bidding_list_detail',args={'id': self.id})
Views:
class bidding_list(ListView):
model = Puja
template_name = 'bidding_templates/bidding_list.html'
"""return render(request= request,
template_name='bidding_templates/bidding_list.html',
context = {"Pujas": Puja.objects.all})"""
class bidding_list_detail(DetailView):
model = Puja
template_name = 'bidding_templates/bidding_list_detail.html'
urls:
path('admin/', admin.site.urls),
path("bidding_list/", bidding_list.as_view(), name="bidding_list"),
path('<int:pk>', bidding_list_detail.as_view(), name='bidding_list_detail'),
admin:
class PujaAdmin(admin.ModelAdmin):
list_display = ('seller','title','video','photo','published_date','bidding_end','starting_price')
admin.site.register(Puja,PujaAdmin)
template 1:
{% extends 'header.html' %}
{% block content %}
<h1>Pujas</h1>
{% for Puja in object_list %} <!--object_list-->
<ul>
<li> {{ Puja.title }} </li>
</ul>
{% endfor %}
{% endblock %}
template 2:
{% extends 'header.html' %}
{% block content %}
<div>
<h2>{{ object.title }}</h2>
<p>{{ object.seller }}</p>
</div>
{% endblock %}
Note that, whenever I remove <a href="{{ Puja.get_absolute_url }}"> from the first template, the objects "puja" in the model get properly displayed on the template, but I cannot access them. They normally exist on the admin panel, but not displayed on the website directly.
Thank you very much on advance and stay healthy.
edit 1: Here is the urls.py directly from the app created by django. To be more specific, I created after the project a new app called "main" in which I programmed all the project, including all the code on this question except the edit.
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
#from django.config import settings
#from django.config.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('main.urls')),
#path('', include('model.urls')),
#path('', include('blog.urls')),
#path('', include('photo.urls')),
#path('', include('video.urls')),
] # +static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I guess the problem is this line - return reverse('bidding_list_detail',args={'id': self.id}), you are passing id as a string but trying to match with int in url.Try following return reverse ('bidding_list_detail',args=[self.id])
I am trying to create a contact form for my Django site but it's not working properly. There are three steps to the contact form. Step 1 has a box where you input the subject of the email. Step 2 has a box where you input the sender's email address. At this point, there are three buttons- "first step", "prev step", and "submit". If I click "submit", the site doesn't take me to step 3, which is supposed to be where you input the body of the email. Instead, it reroutes me back to the Step 1 page.
I did my research and I can't find anything online related to this particular problem.
Here is my views.py file, which is located in the django_test/django_test directory:
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.context_processors import csrf
from forms import MyRegistrationForm
from django.contrib.formtools.wizard.views import SessionWizardView
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
#import logging
#logr = logging.getLogger(__name__)
def login(request):
c = {}
c.update(csrf(request))
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('/accounts/loggedin')
else:
return HttpResponseRedirect('/accounts/invalid')
def loggedin(request):
return render_to_response('loggedin.html',
{'full_name': request.user.username})
def invalid_login(request):
return render_to_response('invalid_login.html')
def logout(request):
auth.logout(request)
return render_to_response('logout.html')
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html', args)
def register_success(request):
return render_to_response('register_success.html')
class ContactWizard(SessionWizardView):
template_name = "contact_form.html"
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render_to_response('done.html', {'form_data': form_data})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
logr.debug(form_data[0]['subject'])
logr.debug(form_data[1]['sender'])
logr.debug(form_data[2]['message'])
send_mail(form_data[0]['subject'],
form_data[2]['message'], form_data[1]['sender'],
[(my email address], fail_silently=False)
return form_data
This my forms.py file, also located in the django_test/django_test directory:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
class ContactForm1(forms.Form):
subject = forms.CharField(max_length=100)
class ContactForm2(forms.Form):
sender = forms.EmailField()
class ContactForm3(forms.Form):
message = forms.CharField(widget=forms.Textarea)
And my contact_form.html file, located in the django_test/templates directory:
{% extends "base.html" %}
{% block content %}
<h2>Contact Us</h2>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
{% for field in form %}
{{field.error}}
{% endfor %}
<form action="/contact/" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">"first step"</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"prev step"</buttom>
{% endif %}
<input type="submit" value="submit" />
</form>
{% endblock %}
And this is my urls.py file:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
from django_test.api import ArticleResource
from django_test.forms import ContactForm1, ContactForm2, ContactForm3
from django_test.views import ContactWizard
article_resource = ArticleResource()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/login/$', 'django_test.views.login'),
url(r'^accounts/auth/$', 'django_test.views.auth_view'),
url(r'^accounts/loggedin/$', 'django_test.views.loggedin'),
url(r'^accounts/invalid/$', 'django_test.views.invalid_login'),
url(r'^accounts/logout/$', 'django_test.views.logout'),
url(r'^accounts/register/$', 'django_test.views.register_user'),
url(r'^accounts/register_success/$', 'django_test.views.register_success'),
url(r'^articles/all/$', 'article.views.articles'),
url(r'^articles/create/$', 'article.views.create'),
url(r'^articles/get/(?P<article_id>\d+)/$', 'article.views.article'),
url(r'^articles/like/(?P<article_id>\d+)/$', 'article.views.like_article'),
url(r'^articles/add_comment/(?P<article_id>\d+)/$', 'article.views.add_comment'),
url(r'^articles/search/', 'article.views.search_titles'),
url(r'^articles/api/', include(article_resource.urls)),
url(r'^contact/', ContactWizard.as_view([ContactForm1, ContactForm2, ContactForm3])),
)
I'm not getting any error messages either, which is frustrating, so I don't know what I'm doing wrong. Thank you.
All I had to do was view the page source on the site. It turned out
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"prev step"</buttom>
in contact_form.html had a typo: </buttom>. I fixed the error and now I get the comment page.
The line should be:
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"prev step"</button>