self.assertContains fails; Couldn't find *word* in response - python

I'm having difficulty completely rendering the template of TopicsPage. It's suppose to render sub_heading.html which extends listing.html (both templates reside in the same templates folder). The test passes the self.assertTemplateUsed() assertion.
However an AssertionError is raised at the point of:
self.assertContains(response, "Looking for more?")
AssertionError: False is not true : Couldn't find 'Looking for more?' in response
How can I get the sub_heading.html content to render for the test to pass when the template is being used already? I put the implementation for GET method as pass intentionally just to show how I'm subclassing the View.
test_views.py
class TestTopicsPage__002(TestCase):
'''Verify that a topic and associated information is displayed
on the main page once the topic is created'''
#classmethod
def setUpTestData(cls):
user = User.objects.create_user("TestUser")
python_tag = Tag.objects.create(name="Python")
js_tag = Tag.objects.create(name="JavaScript")
content = {
'heading': "Test Title",
'text': "Mock text content",
'posted': datetime.datetime.now()
}
cls.topic = Topic(**content)
cls.topic.author = user
cls.topic.save()
cls.topic.tags.add(python_tag, js_tag)
def test_topics_main_page_rendered_topics(self):
response = self.client.get(
reverse("listing")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "topics/sub_listing.html")
self.assertContains(response, "Looking for more?")
views.py
class AbstractListingPage(TemplateView):
template_name = "topics/sub_listing.html"
extra_content = {
'query_links': ['interesting', 'hot', 'week', 'month']
}
def get_context_data(self):
context = super().get_context_data()
context['topics'] = Topic.objects.all()
context['search_form'] = SearchForm()
context['login_form'] = UserLoginForm
return context
def post(self, request):
context = self.get_context_data()
form = context['login_form'](data=request.POST)
if form.is_valid():
resolver = resolve(request.path)
login(request, form.get_user())
if resolver.namespace:
url = f"{resolver.namespace}:{resolver.url_name}"
else:
url = resolver.url_name
return HttpResponseRedirect(
reverse(url)
)
return self.render_to_response(context)
class TopicsPage(AbstractListingPage):
def get(self, request):
pass
listing.html
{% extends 'index.html' %}
{% load static %}
{% block content %}
{% if not topics %}
<h1 class="topics_placeholder">"Whoops...no topics are being talked about"</h1>
<h2>Join the community...NOW!</h2>
{% else %}
{% for topic in topics %}
<ul class="topic_stats">
<li>{{ topic.answers.count }} answers</li>
<li>{{ topic.likes }} likes</li>
<li>{{ topic.views }} views</li>
</ul>
<div class="topic_wrapper">
<h1>{{ topic }}</h1>
<ul>
{% for tag in topic.tags.all %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
<p>{{ topic.posted }}</p>
<p>{{ topic.author }}</P>
</div>
{% endfor %}
{% endif %}
{% endblock content %}
{% block page_branch %}
{% endblock %}
<div class="question-header">
<button class="flex_item_btn button_widget red" type="button">
Ask Question
</button>
</div>
sub_listing.html
{% extends 'topics/listing.html' %}
{% load static %}
{% block page_branch %}
<h2>Looking for more? Browse the complete list of questions
or popular tags</h2>
{% endblock %}

The content at the bottom of listing.html is orphaned, not existing inside a block present in the parent template.
{% block page_branch %}
{% endblock %}
<div class="question-header">
<button class="flex_item_btn button_widget red" type="button">
Ask Question
</button>
</div>
Since listing.html extends index.html, it can only override blocks that exist in index.html. The above content must be put inside {% block content %} to be rendered at all. Then sub_listing.html's use of {% block page_branch %} will be rendered.

Related

Django display a variable in another template

I have a django project, where I have two templates: notification.html and base.html. Using get_context_data() method I display the number of answers at the notification.html. I tried to use the same variable in base.html, but it didn't work. I also created CBV that and used get_context_data() to pass the same logic and display it at the base.html, but it doesn't work. How do I display the variable in another template?
I don't how to pass 'answers.count' to the base.html, if base.html doesn't have a view (I created this only now trying to display this variable).
forum.views
class NotificationView(ListView):
model = Answer
template_name = 'forum/notification.html'
# If user visited the notification page - mark all answers as read
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
answer_read = self.model.objects.filter(question__in=question)
answer_read.update(is_read=True)
return answer_read
def get_context_data(self, **kwargs):
context = super().get_context_data()
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
context['answers_all'] = Answer.objects.filter(question__in=question).order_by('-date_posted')
context['answers'] = Answer.objects.filter(question__in=question, is_read=False)
return context
forum/notification.html
{% extends 'main/base.html' %}
{% block content %}
<div class="container">
<b>УNotofocations: {{ answers.count }}</b>
{% for answer in answers_all %}
<div class="card mb-3 mt-2">
<div class="card-body">
Ответ на вопрос: {{ answer.question }}
<p>{{ answer.detail }}</p>
{{ answer.user.username }}
<span class="ml-4">{{ answer.date_posted|naturalday }}</span>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
main.views
class BaseView(TemplateView):
template_name = 'main/base.html'
def get_context_data(self, **kwargs):
context = super().get_context_data()
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
context['answers'] = Answer.objects.filter(question__in=question)
return context
main/base.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
{% if user.is_authenticated %}
{% if answers.count < 1 %}
<i class="fas fa-bell"></i>
{% else %}
<i class="fas fa-bell"></i><span class="pending">{{ answers.count }}</span>
{% endif %}
{% endif %}
</head>
</html>
guess you are only missing the build-in template tags
in forum/notification.html
{% extends "base.html" %}
in main/base.html
{% block content %}{% endblock %}
https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#extends
https://docs.djangoproject.com/en/4.1/ref/templates/language/#template-inheritance
Finally, I solved this problem. The idea was to display the variable from context_data at base.html. As get_context_data didn't help, I found the solution in Django documentation. The solution was so easy, I hope to save time for other learners if they got the same problem.
I used context_processors.py to pass extra information and display it on the page. My step were:
Created a context_processors.py file in my app directory.
Created a function def get_notifications_number(request) where I filter what I want to display at base.html and returned return {'answers': answers}
Finally, I registered the file in Django TEMPLATES 'my_app.context_processors.get_notifications_number'.

Django Please help me place a checkbox and a mail box with a send button on the html page

One of functionality in my training project:
subscribe to the news by check-box and e-mail.
Send newsletter daily.
The user can unsubscribe from the mailing list in his profile by unchecking the checkbox.
It so happened that first I set up a daily newsletter for users who have booleanfield = true.
For it I marked the checkboxes in the admin panel. It works.
Now it is necessary to add the checkbox and the mail field to the news page.
I'm stuck on the simplest. Tired and confused.
Please help me place a checkbox and a mail box with a send button on the news page
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
hr = models.BooleanField(default=False)
subscribed_for_mailings = models.BooleanField(default=False)
subscription_email = models.EmailField(default="")
def __str__(self):
return str(self.user)
Forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscription_email', 'subscribed_for_mailings', )
widgets = {
'subscription_email': forms.EmailInput(attrs={"placeholder": "Your Email..."}),
'subscribed_for_mailings': forms.CheckboxInput,
}
views.py
def all_news(request):
today = date.today()
today_news = models.TopNews.objects.filter(created__gte=today)
return render(request, "news.html",
{'today_news': today_news})
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
mailing_form.save()
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
urls.py
...
path('news/', views.all_news, name='all_news'),
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1>
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<p>
{{ news.created }}
</p>
<hr>
{% endfor %}
<h4>I want to receive news by mail</h4>
<form action="." method="post">
{{ mailing_form.as_p }}
{% csrf_token %}
<label>
<input type="submit" value="Subscribe">
</label>
</form>
{% endblock %}
The page displays a list of news and only the "send" button. There is no check-box and a field for mail
enter image description here
Finally I realized this functionality in a different way:
forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscribed_for_mailings', 'subscription_email', )
views.py
#login_required
def mailing_news(request):
if request.method == "POST":
mailing_form = forms.MailingForm(request.POST,
instance=request.user.profile,
)
if mailing_form.is_valid():
mailing_news = mailing_form.save(commit=False)
mailing_news.subscribed_for_mailings = mailing_news.subscribed_for_mailings
mailing_news.subscription_email = mailing_news.subscription_email
mailing_news.save()
return render(request, "subscribe_complete.html",
{"mailing_news": mailing_news})
else:
mailing_form = forms.MailingForm()
return render(request, 'subscribe.html', {"mailing_form": mailing_form})
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
urls.py
...
path('subscribe/', views.mailing_news, name='subscribe')
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
subscribe.html
{% extends 'base.html' %}
{% block title %}
Subscribe
{% endblock %}
{% block body %}
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ mailing_news.as_p }}
{% if user.profile.subscribed_for_mailings is True %}
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings" checked="">
If you don't want to receive emails anymore, uncheck
<br>
Subscription email: <input type="email" name="subscription_email" value={{ user.profile.subscription_email }} class="vTextField" maxlength="254" id="id_subscription_email">
{% else %}
<label>
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings">
I want to subscribe for mailing news
</label>
<p><label>
Send news on my email:
<input type="email" name="subscription_email" class="vTextField" maxlength="254" id="id_subscription_email">
</label></p>
{% endif %}
<p><input type="submit" value="Update"></p>
</form>
{% endblock %}
subscribe_complete.html
{% extends 'base.html' %}
{% block title %}
Subscribing complete
{% endblock %}
{% block body %}
<h3>Hi {{ user.username }}</h3>
Thanks for subscribing.
You will receive daily news by email: {{ user.profile.subscription_email }}
{% endblock %}
you need to change subscribed_for_mailings in mailing news, like this
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
profile = mailing_form.save(commit=False) ####
profile.subscribed_for_mailings = mailing_form.cleaned_data.get('subscribed_for_mailings') ####
profile.subscription_email = mailing_form.cleaned_data.get('subscription_email') ####
profile.save() #### new_line
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
you can change in cleaned_data.get('....')

DeleteView doesn't delete and just refreshes the delete page

When I click on my delete project link it takes me to my delete page with a button to click which should delete the model data of the project and then take me to the profile page. However when I click the delete button, the page just refreshes and no data gets deleted?!
What am I doing wrong here? Any help would be much appreciated :-)
Views
class DeleteProject(UpdateView):
model = UserProject
template_name = 'howdidu/delete_project.html'
def get_object(self, queryset=None):
obj = super(DeleteProject, self).get_object()
if not obj.user == self.request.user:
raise Http404
return obj
def get_success_url(self):
project_username = self.request.user.username
#project_slug = self.object.slug
return reverse('user_profile', kwargs={'username':project_username})
delete_project.html template
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}Delete project{% endblock %}
{% block body_block %}
<h1>Delete project</h1>
<form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ userproject.title }}"?</p>
<input type="submit" value="Confirm" />
</form>
{% endblock %}
Urls
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^register_profile/$', views.register_profile, name='register_profile'),
url(r'^update_profile/$', views.update_profile, name='update_profile'),
url(r'^create_project/$', login_required(views.CreateProject.as_view()), name='create_project'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/update_project/$', login_required(views.UpdateProject.as_view()), name='update_project'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/delete_project/$', login_required(views.DeleteProject.as_view()), name='delete_project'),
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/$', views.project_page, name='user_project'),
)
Project.html template which has the delete link on
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}Project{% endblock %}
{% block body_block %}
{% if project %}
<h1>{{ project.title }}</h1>
<img src="{{ project.project_picture.url }}" width = "300" height = "300" />
<h3>{{ project.project_overview }}</h3>
{% if user.is_authenticated %}
{% if project_user.username == user.username %}
<p>Edit project</p>
<p>Delete project</p>
{% endif %}
{% endif %}
{% else %}
The specified project {{ project.title }} does not exist!
{% endif %}
{% endblock %}
You must use DeleteView not UpdateView.
See here.

Django Uploading Files

I have a dashboard where you upload files and can see the files you uploaded. Strangely enough, when you go to upload a second file, it uploads but gives the error: IntegrityError at /dashboard/ column client_id is not unique I'm not sure why. My database is fresh and clean. What would cause this? The first file uploads and displays correctly redirecting you to the dashboard. The second file uploads, but doesn't display in the file list and displays that error. Any ideas why this is occurring or how to fix this error? I'm really stuck here so any help would save me big time.
Here is the view:
#login_required(login_url='/dashboard-login/')
def dashboard(request):
current_user = request.user
current_client = request.user.client
files = ClientUpload.objects.filter(client=current_client)
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
new_file = ClientUpload(client=current_client, file_upload = request.FILES['file_upload'])
new_file.save()
return HttpResponsePermanentRedirect('/dashboard/')
else:
form = UploadFileForm()
data = {'form': form, 'client': current_client, 'files': files}
return render_to_response('dashboard.html', data, context_instance=RequestContext(request))
The models:
#python_2_unicode_compatible
class Client(models.Model):
user = models.OneToOneField(User)
company = models.CharField(max_length=100)
def __str__(self):
return self.company
class Meta:
verbose_name_plural = _("Clients")
verbose_name = _("Client")
permissions = (
("can_upload", _("Can upload files.")),
("can_access_uploads", _("Can access upload dashboard.")),
("is_client", _("Is a client.")),
)
def generate_filename(self, filename):
name = "uploads/%s/%s" % (self.client.company, filename)
return name
#python_2_unicode_compatible
class ClientUpload(models.Model):
client = models.OneToOneField(Client)
created_at = models.DateTimeField(auto_now_add=True)
file_upload = models.FileField(upload_to=generate_filename)
def __str__(self):
return self.client.company
class Meta:
verbose_name_plural = _("Client Uploads")
verbose_name = _("Client Upload")
The form:
class UploadFileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.add_input(Submit(_('submit'), _('Submit')))
super(UploadFileForm, self).__init__(*args, **kwargs)
class Meta:
model = ClientUpload
fields = ('file_upload',)
And lastly, the templates:
Upload file:
{% load i18n %}
{% load crispy_forms_tags %}
{% crispy form %}
File list:
{% load i18n %}
<table class="table">
<tr>
<th>{% blocktrans %}Filename{% endblocktrans %}</th>
<th>{% blocktrans %}Size{% endblocktrans %}</th>
<th>{% blocktrans %}Upload Time{% endblocktrans %}</th>
</tr>
{% for file in files %}
{% with uploaded_file=file.file_upload %}
<tr>
<th><a href='{{ uploaded_file.url }}'>{{ uploaded_file.name }}</a></th>
<th>{{ uploaded_file.size }}</th>
<th>Uploaded At</th>
{% endwith %}
{% endfor %}
</tr>
</table>
And the one that ties them together, dashboard:
{% extends "base.html" %}
{% load i18n %}
{% block title %}Shenkan & Associates - {% trans 'Dashboard' %}{% endblock title %}
{% block css %}
{{ block.super }}
{% endblock css %}
{% block extra_css %}
{% endblock extra_css %}
{% block ie_shim %}
{{ block.super }}
{% endblock ie_shim %}
{% block header %}
{{ block.super }}
{% endblock header %}
{% block slider %}
{% endblock slider %}
{% block page_header %}{% endblock page_header %}
{% block content %}
<!--=== Content ===-->
{% trans 'Logout' %}
<div class="container content-md">
{% include "upload_file.html" %}
</div>
<div class="container content-md">
{% include "file_list.html" %}
</div>
<!--=== End Content ===-->
{% endblock content %}
{% block footer %}
{{ block.super }}
{% endblock footer %}
{% block js %}
{{ block.super }}
{% endblock js %}
{% block ie_js %}
{{ block.super }}
{% endblock ie_js %}
{% block extra_js %}
{% endblock extra_js %}
You don't need to see base.html obviously.
If someone could help me solve this mystery it would help a ton as I am having tons of problems with this and have been stuck for days.
Thanks a bunch.
I think you should use "get_or_create" in the views.
I hope this can help: get_or_create throws Integrity Error

Django display in html from views.py

I'm newbie in Django and i would like to have a little help please.
I have this code in views.py
def display_meta(request):
values = request.META.items()
values.sort
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return HttpResponse('<table>%s</table>' % '/n'.join(html))
------- return render(HttpResponse,'current_datetime.html',{'about': html})
def current_datetime(request):
now = datetime.datetime.now()
return render(request, 'current_datetime.html', {'current_date': now})
The part with '------' is added by me but i don't know if it's ok . The question is here , how should I display in the html file the return HttpResponse to show what meta is the user using.
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
<p>You are using {{ HERE WILL BE DISPLAYED THE META FUNCTION, BUT HOW ??? }}</p>
{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
I couldn't understand exactly how to ....
Thank you guys in advence!
in settings.py add read what this mean
TEMPLATE_CONTEXT_PROCESSORS = (
...,
'django.core.context_processors.request',
)
and then, it is VERY important to load your custom templatetag
{% extends "base.html" %}
# NEW LINE
{% load custom_tags %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
<p>You are using {{ request|extract_meta }}</p>
{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
Create custom template tags named extract_meta here is doc
in templatetags/custom_tags.py:
from django import template
register = template.Library()
#register.filter(name="extract_meta")
def extract_meta(request):
values = request.META.items()
values.sort
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return '<table>%s</table>' % '/n'.join(html)

Categories