TemplateDoesNotExist at /edit-narration/13/edit/ - django

Why is my narrate_update_form template not showing? And why am I getting
TemplateDoesNotExist at /narration/7/edit/
narrate_update_form
My views.py is:
class NarrateUpdate(UpdateView):
model = Narrate
fields = ['title', 'body']
template_name = 'narrate_update_form'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['narrate'] = Narrate.objects.get(pk=self.kwargs['pk'])
return context
On my narrate template I have this button:
Edit/Update
On the narrate_update_form.html, I have:
{% extends 'base.html' %}
{% block body %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
{% endblock body %}
Can anyone help me?

It'd be template_name = 'narrate_update_form.html', you need to add html there.
Also depending on where the template file actually is, you might need to specify a relative path to it.

Related

Django Model Objects cannot seen in Django Template

Rendered django model object cannot give any output in template. My Code is:
model.py:
class MyModel(models.Model):
address = models.GenericIPAddressField(
max_length=15,
verbose_name=_('address')
)
Path = models.CharField(
max_length=300,
verbose_name='path',
)
activate = models.CharField(max_length=5, default='off', )
views.py:
class MyView(ListView):
model = models.MyModel.objects.all()[0]
template_name = '../on_off.html'
context_object_name = 'obj_list'
admin.py:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path', )
exclude = ('activate', )
change_list_template = '../on_off.html'
on_off.html:
{% extends 'admin/change_list.html' %}
{% block object-tools %}
{% if obj_list %}
<form id="on_off_status" method="POST">
<label id="onoff" class="switch">
{% csrf_token %}
<input type="checkbox" id="togBtn" value=" {{ obj_list.activate }} ">
<div class="slider round"></div>
</label>
</form>
{% endif %}
...
In Django model, the system accepts only one object and I want to give to toggle switch button value in template using activate field in MyModel model. But it is not rendered in template, I couldn't get any object data even if I try <h1> {{ obj_list }} </h1>, it turns <h1> </h1> . Any help or suggestion appreciated.
Render the field manually
<label id="onoff" class="switch">
{% csrf_token %}
{{ obj_list.activate }}
<div class="slider round"></div>
</label>
Instead of using the views.py, django-admin provide a function named changelist_view(). Now it is working, I deleted the funtion in views.py and I added changelist_view() function to my admin.py looks like:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path',)
exclude = ('activate',)
change_list_template = '../nfs_on_off.html'
def changelist_view(self, request, extra_context=None):
object = self.model.objects.all()
context={
'obj_list': object,
}
return super(MyAdmin, self).changelist_view(request, context)

Django UpdateView not loading forms with styles

I created a form using Django's UpdateView class, however, when the form loads it seems like the text boxes and text areas are not styled (looks like form.as_p style). Here is an example of exactly what I did.
Views.py
class UpdatePostView(UpdateView):
template_name = 'Post/UpdatePost.html'
model = Post
fields = ['Title', 'Body']
success_url = reverse_lazy('BlogApp:main')
def form_valid(self, form):
form.instance.Title = form.cleaned_data['Title']
form.instance.Body = form.cleaned_data['Body']
form.instance.save()
return super().form_valid(form)
Here is how I loaded the form in UpdatePost.html:
<form id="UpdatePostForm" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="PostTitle">{{form.Title.label}}</label>
{{form.Title}}
</div>
<div class="form-group">
<label for="PostBody">{{form.Body.label}}</label>
{{form.Body}}
</div>
<input class="btn btn-primary" type="submit" for="UpdatePostForm" value="Update">
</div>
</form>
If you use Bootstrap, you also can use django-crispy-forms (version for Bootstrap 4 https://github.com/django-crispy-forms/django-crispy-forms ,version for Bootstrap 5 - https://github.com/django-crispy-forms/crispy-bootstrap5). It is helpful to live DRY (Don't repeat yourself).
And then it will be something like(I use crispy-forms for Bootstrap 5):
pip install crispy-bootstrap5
INSTALLED_APPS = (
...
"crispy_forms",
"crispy_bootstrap5",
...
)
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
class UpdatePostView(UpdateView):
template_name = 'Post/UpdatePost.html'
model = Post
fields = ['Title', 'Body']
success_url = reverse_lazy('BlogApp:main')
def form_valid(self, form):
form.instance.Title = form.cleaned_data['Title']
form.instance.Body = form.cleaned_data['Body']
form.instance.save()
return super().form_valid(form)
template
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h1 class="text-center">Update Post</h1>
<br />
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form|crispy }}
<button class="btn btn-outline-primary">
Update
</button>
</form>
{% endblock content %}
Because by default the form.body and form.title render a html input, you can override the class attribut from your UpdateView like that :
def get_form(self, *args, **kwargs):
form = super(UpdatePostView, self).get_form(*args, **kwargs)
form.fields["Title"].widget.attrs["class"] = "form-group"
form.fields["Body"].widget.attrs["class"] = "form-group"
return form

queryset when building django form

I am trying to get specific querysets based when a customer-specific form loads, showing only that customer's name (embedded as an ID field), its respective locations and users.
The idea is to select one user and any number of locations from a multichoice box.
I've tried to pass the ID as a kwarg but am getting a KeyError. I've tried the kwarg.pop('id') as found on the web and same issue. Any advice?
forms.py
class LocGroupForm(forms.ModelForm):
class Meta:
model = LocationsGroup
fields = ('group_name', 'slug', 'customer', 'location', 'user_id',)
def __init__(self, *args, **kwargs):
qs = kwargs.pop('id')
super(LocGroupForm, self).__init__(*args, **kwargs)
self.fields['customer'].queryset = Customers.objects.get(pk=qs)
self.fields['location'].queryset = CustomerLocations.objects.filter(customer_id=qs)
self.fields['user_id'].queryset = CustomerUsers.objects.filter(customer_id=qs)
here is my view. it's just a generic view
views.py
class LocGroupCreate(LoginRequiredMixin, CreateView):
form_class = LocGroupForm
template_name = 'ohnet/a_gen_form.html'
the template is a dry template I use for all my forms- admittedly something I mostly stole from a tutorial
{% extends "ohnet/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<div class="container">
<h1>{{ title }}</h1>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" name="submit" value="Submit">
</form>
</div>
{% endblock content %}
This is the KeyError from the form load.
You need to pass a value for the id when constructing the LocGroupForm, you can do that by overriding get_form_kwargs:
class LocGroupCreate(LoginRequiredMixin, CreateView):
form_class = LocGroupForm
template_name = 'ohnet/a_gen_form.html'
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['id'] = …
return kwargs
You will need to fill in the … that specifies the value passed as id to the form. This might for example be self.request.user.pk, or a URL parameter with self.kwargs['name-of-url-parameter']

How to add user authentication in generic delete view in django2.0.6

I have a page which displays posts of all user and user can only delete his posts.
Heres the code:
class PostDelete(generic.DeleteView):
model = Post
template_name = 'dashboard/post_delete.html'
success_url = reverse_lazy('dashboard:posts')
post_delete.html:
{% extends 'dashboard/sidebar.html' %}
{% block title %}Confirmation{% endblock %}
{% block mainpage %}
<div id="page-wrapper" align="center">
<div id="page-inner">
<h1>New post</h1>
<form method="post">
{% csrf_token %}
Are you sure you want to delete?
<br>
<button class="btn btn-danger">Yes</button>
No
</form>
</div>
</div>
{% endblock %}
Urls.py:
path('delete/<int:pk>',views.PostDelete.as_view(),name='delete'),
How do I add user authentication code?
If it were a function I would have used " if request.user.is_authenticated "
But I don't know how to achieve this thing in a class. If you need an excerpt of another code then comment. Thanks!
Try to use UserPassesTestMixin:
from django.contrib.auth.mixins import UserPassesTestMixin
class PostDelete(UserPassesTestMixin, generic.DeleteView):
model = Post
template_name = 'dashboard/post_delete.html'
success_url = reverse_lazy('dashboard:posts')
raise_exception = True
def test_func(self):
self.object = self.get_object()
return self.object.user == self.request.user

Using modelformset_factory in a Django Class Based View

I am building a view that will let me update multiple fields on multiple objects at the same time. I'm doing this using ModelFormSet & modelformset_factory.
The template will be a table of forms with the object name to the left of the fields (see image below).
I found this example, but I am stuck on how to implement the class based view & template.
My Formset
class BaseFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseFormSet, self).__init__(*args, **kwargs)
self.queryset = Reference.objects.filter(
start__isnull=True)
ReferenceFormSet = modelformset_factory(
Reference,
fields=('start', 'end'),
formset=BaseFormSet,
extra=0)
My View
class ReferenceFormSetView(LoginRequiredMixin, SuperuserRequiredMixin, FormView):
model = Reference
form_class = ReferenceFormSet
template_name = "references/references_form.html"
def form_valid(self, form):
for sub_form in form:
if sub_form.has_changed():
sub_form.save()
return super(ReferenceFormSetView, self).form_valid(form)
My Template
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<h1>{{ headline }}</h1>
<div class="row">
<form action="" method="post">
{% crispy form %}
<div class="">
<input type="submit" value="Submit" />
</div>
</form>
</div>
</div>
{% endblock content %}
Questions
The view seems odd with the Formset in the form_class. Is there a better way to handle this?
How can I access the instance name to display in the form?
I found a solution using a package called django-extra-views.
There is a class called ModelFormSetView which does exactly what I wanted. Here is my implementation (simplified) for others to use -
My View
class ReferenceFormSetView(ModelFormSetView):
model = Reference
template_name = "references/references_form.html"
fields = ['start', 'end']
extra = 0
def get_queryset(self):
return self.model.objects.all()
def get_success_url(self):
return reverse('references:formset')
def formset_valid(self, formset):
"""
If the formset is valid redirect to the supplied URL
"""
messages.success(self.request, "Updated")
return HttpResponseRedirect(self.get_success_url())
def formset_invalid(self, formset):
"""
If the formset is invalid, re-render the context data with the
data-filled formset and errors.
"""
messages.error(self.request, "Error dummy")
return self.render_to_response(self.get_context_data(formset=formset))
My Template
<form class="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="">
{% for field in form %}
{{ field }}
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Save</button>
</form>