I have recently taken over the development of a Django/ Python project, and am looking into fixing a particular bug within the system as it currently stands.
There is a database of projects with quite a large amount of information about each project stored. On one of the webpages, there is a button, which when clicked will add a new form to the page- the form allows the user to enter some details about a new object for the given project. If there are existing objects for that project within the database, a 'table' will be displayed with a form on each row for each of the existing objects, and the user can manually update the fields in the form to update the information about each of the objects in the database. They can also add a new 'row' to the 'table' to create a new object to add to that project.
This page is displayed by the view:
def current_ccis(request, budget_id):
"""
View the CCIs for the current budget
"""
budget = Budget.objects.select_related('project').get(id=budget_id)
project = budget.project
ccis = CciItem.objects.select_related('budget', 'budget__project', 'project_room', 'project_room__room').filter(budget_id=budget_id).order_by('project_room__order', 'created')
formset = CciItemFormset(queryset=ccis.exclude(name=None), form_kwargs={'project':project})
context = {
'ccis': ccis,
'project': project,
'budget': budget,
'formset': formset,
'widths': ['60px', '120px', '220px', '120px', '60px', '60px', '60px', '280px', '280px'],
}
return render(request, 'costing/ccis_current.html', context)
The first cell in each form of the formset for each object displays the 'type' of object that it is, and every other cell displays/ stores other information relevant to the object itself.
On another one of the webpages, there is then a report displayed about a given project which includes information based on what the user input into the forms on the page displayed by the view current_ccis(request, budget_id)
This page is displayed by the view:
def report_ccis(request, project_id):
""" CCI items styled for pdf """
project = Project.objects.get(id=project_id)
budget = get_current_budget(project_id)
cci_total_exc = budget.cci_total_exc_vat_final
cci_grouped_items = budget.cci_items.all().order_by('project_room', 'name')
context = {
'project': project,
'cci_total_exc': cci_total_exc,
'cci_grouped_items': cci_grouped_items,
'webview': 1,
}
try: context['current_budget'] = project.budget_versions.get(current_marker=1) #For option name/date on top of pdfs
except ObjectDoesNotExist: pass
if request.GET.get('stage') == 'pd':
""" Render post deposit homepage """
context['html'] = render_to_string('costing/report2_ccis.html', context)
context['active_tab'] = '4'
return render(request, 'costing/reports_post_deposit.html', context)
else:
""" Render pre deposit homepage """
context['html'] = render_to_string('costing/report_ccis.html', context)
context['active_tab'] = '5'
return render(request, 'costing/reports_pre_deposit.html', context)
and the report currently displays the information in the format:
Title
Project ID
Object
detail
detail
Object
detail
i.e. a list of Objects belonging to the project, and underneath 'Object title' a list of details belonging to that object.
The issue that I'm having here, is that for some projects, the 'Object' names are all displayed with their 'details' listed beneath each 'Object', but for others, the details are not listed under their respective 'Objects', but rather all listed under one 'Object', which is titled "None"...
What I don't understand, is why there is this inconsistency- why is that for some projects, the 'Object' names are shown on the report, with all of the 'details' listed under their respective 'Objects', but for other projects, all of the 'details' are listed under the Object 'None'...?
Anyone have any suggestions why this is?
Edit
The reports are displayed in the HTML files with:
(post deposit):
{% block tabs %}
{% with 'Payment schedule,Agreed variations,Variations not yet finalised,Client choice items,Overview'|listify as tabs %}
{% for tab_name in tabs %}
{% with forloop.counter as tab %}
{% if not tab == active_tab|add:0 %}<a class="tab" href="{% url 'costing:report2_tabbed' project.id %}?tab={{tab}}">{% else %}<a class="active tab">{% endif %}{{tab_name}}</a>
{% endwith %}
{% endfor %}
{% endwith %}
{% endblock tabs %}
(pre deposit):
{% block tabs %}
{% with 'Overview, Construction budget, Schedule of works, Client choice items'|listify as tabs %}
{% for tab_name in tabs %}
{% with forloop.counter as tab %}
{% if not tab == active_tab|add:0 %}<a class="tab" href="{% url 'costing:report_tabbed' project.id %}?tab={{tab}}">{% else %}<a class="active tab">{% endif %}{{tab_name}}</a>
{% endwith %}
{% endfor %}
{% endwith %}
{% endblock tabs %}
Edit
The files where this HTML comes from both extend from the same HTML file (reports_tabbed.html), which has the following HTML:
{% extends "base.html" %}
{% load staticfiles utilities %}
{% block head_extras %}
<link rel="stylesheet" type="text/css" href="{% static "moon/scss/pdf-reports.css" %}">
{% endblock head_extras %}
{% block page_options %}
{% if request.user.first_name in 'Becky,Duncan'|listify and project.deposit_received %}
Make quick PDF
{% endif %}
{% endblock page_options %}
{% block content %}
<div class="tabbed m-r-lg text-sm">
<div class="navbar tabbed text-sm">
{% block tabs %}
{% endblock tabs %}
</div>
<div class="tabbed-section border {% block tabbed_class %}page{% endblock tabbed_class %}">
{{html}}
</div>
</div>
{% endblock content %}
{% block content_scripts %}
{% endblock content_scripts %}
Related
I installed the app careers mezanine and after creating a test position and turn the page to see the error TypeError at / careers / test /
jobpost_detail () got an unexpected keyword argument 'slug'. How do I fix this problem?
views
from calendar import month_name
from django.shortcuts import get_object_or_404
from collections import defaultdict
from django.contrib.contenttypes.models import ContentType
from django import VERSION
from careers.models import JobPost
from mezzanine.conf import settings
from mezzanine.generic.models import AssignedKeyword, Keyword
from mezzanine.utils.views import render, paginate
def jobpost_list(request, tag=None, year=None, month=None, template="careers/jobpost_list.html"):
"""
Display a list of job posts that are filtered by year, month.
"""
settings.use_editable()
templates = []
jobposts = JobPost.objects.published()
if tag is not None:
tag = get_object_or_404(Keyword, slug=tag)
jobposts = jobposts.filter(keywords__in=tag.assignments.all())
if year is not None:
jobposts = jobposts.filter(publish_date__year=year)
if month is not None:
jobposts = jobposts.filter(publish_date__month=month)
month = month_name[int(month)]
# We want to iterate keywords and categories for each blog post
# without triggering "num posts x 2" queries.
#
# For Django 1.3 we create dicts mapping blog post IDs to lists of
# categories and keywords, and assign these to attributes on each
# blog post. The Blog model then uses accessor methods to retrieve
# these attributes when assigned, which will fall back to the real
# related managers for Django 1.4 and higher, which will already
# have their data retrieved via prefetch_related.
jobposts = jobposts.select_related("user")
if VERSION >= (1, 4):
jobposts = jobposts.prefetch_related("keywords__keyword")
else:
if jobposts:
ids = ",".join([str(p.id) for p in jobposts])
keywords = defaultdict(list)
jobpost_type = ContentType.objects.get(app_label="careers", model="jobpost")
assigned = AssignedKeyword.objects.filter(jobpost__in=jobposts, content_type=jobpost_type).select_related("keyword")
for a in assigned:
keywords[a.object_pk].append(a.keyword)
for i, post in enumerate(jobposts):
setattr(jobposts[i], "_keywords", keywords[post.id])
jobposts = paginate(jobposts, request.GET.get("page", 1),
settings.CAREERS_PER_PAGE,
settings.MAX_PAGING_LINKS)
context = {"jobposts": jobposts, "year": year, "month": month, "tag": tag}
templates.append(template)
return render(request, templates, context)
def jobpost_detail(request, template="careers/jobpost_detail.html"):
""". Custom templates are checked for using the name
``careers/jobpost_detail_XXX.html`` where ``XXX`` is the job
posts's slug.
"""
jobposts = JobPost.objects.published()
jobpost = get_object_or_404(jobposts)
context = {"jobpost": jobpost, "editable_obj": jobpost}
templates = [u"careers/jobpost_detail_%s.html" %(slug), template]
return render(request, templates, context)
html
{% extends "careers/jobpost_list.html" %}
{% load mezzanine_tags keyword_tags i18n %}
{% block meta_title %}{{ jobpost.meta_title }}{% endblock %}
{% block meta_keywords %}{% metablock %}
{% keywords_for jobpost as tags %}
{% for tag in tags %}{% if not forloop.first %}, {% endif %}{{ tag }}{% endfor %}
{% endmetablock %}{% endblock %}
{% block meta_description %}{% metablock %}
{{ jobpost.description }}
{% endmetablock %}{% endblock %}
{% block title %}
{% editable jobpost.title %}{{ jobpost.title }}{% endeditable %}
{% endblock %}
{% block breadcrumb_menu %}
{{ block.super }}
<li class="active">{{ jobpost.title }}</li>
{% endblock %}
{% block main %}
<h6>
{% trans "Posted" %} {{ jobpost.publish_date|timesince }} {% trans "ago" %}.
</h6>
{% editable jobpost.content %}
{{ jobpost.content|richtext_filter|safe }}
{% endeditable %}
{% keywords_for jobpost as tags %}
{% if tags %}
{% spaceless %}
<ul class="unstyled tags">
<li>{% trans "Tags" %}:</li>
{% for tag in tags %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
{% endspaceless %}
{% endif %}
{% set_short_url_for jobpost %}
<a class="btn small primary share-twitter" target="_blank" href="http://twitter.com/home?status={{ jobpost.short_url|urlencode }}%20{{ jobpost.title|urlencode }}">{% trans "Share on Twitter" %}</a>
<a class="btn small primary share-facebook" target="_blank" href="http://facebook.com/sharer.php?u={{ request.build_absolute_uri }}&t={{ jobpost.title|urlencode }}">{% trans "Share on Facebook" %}</a>
{% endblock %}
url
from django.conf.urls import patterns, url
# Job Post patterns.
urlpatterns = patterns("careers.views",
url("^tag/(?P<tag>.*)/$",
"jobpost_list",
name="jobpost_list_tag"),
url("^archive/(?P<year>\d{4})/(?P<month>\d{1,2})/$",
"jobpost_list",
name="jobpost_list_month"),
url("^archive/(?P<year>.*)/$",
"jobpost_list",
name="jobpost_list_year"),
url("^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>.*)/$",
"jobpost_detail",
name="jobpost_detail_date"),
url("^(?P<slug>.*)/$",
"jobpost_detail",
name="jobpost_detail"),
url("^$",
"jobpost_list",
name="jobpost_list"),
)
The error tells you exactly what is going on: your "jobpost_detail" URL the captures a slug parameter and passes it on to the view, but that view does not expect a slug, only the request and a template. Also, you are not doing anything in that view to get the actual post identified by a slug: you are always getting the first published post.
I suspect you want to do the following:
def jobpost_detail(request, slug, template="careers/jobpost_detail.html"):
jobposts = JobPost.objects.published()
jobpost = get_object_or_404(jobposts, slug=slug)
Edited my code: In the custom fieldset of a model admin:
{%load app_extras %}
{% if field.field.name == 'mobile' %}
<a target="hiddenIframe" href="http://url_to_call.php?exten={{request.user.employee_profile.extension}}&phone={{ field.field.value }}">Click-to-call</a>
{% my_mobile mobile=field.field.value as mob %}
{% endif %}
{% if field.field.name == 'sms_message' %}{{ mob }}
<a target="hiddenIframe" href="http://url_for_send_sms.php?sms_message={{ field.field.value }}&phone={{ mob }}">Click-to-send-sms</a>
{% endif %}
Here I am trying to access mobile number as well as sms_message fields of the model admin form simultaneously.
I have figured that I need to use custom tags, so I created the templatetags module, with app_extras.py containiging the function to assign the value of mobile and return it as follows:
#register.assignment_tag
def my_mobile(*args, **kwargs):
m_mobile = int(kwargs['mobile'])
return {'m_mobile': m_mobile }
In the template fiedset.html above note changes: This returns a Long value as: {'m_mobile': 1234534519L}
When seen on the browser for url for hyperlink shows:
http://url_for_send_sms.php/?sms_message=fgdfg&phone={%27m_mobile%27:%1234534519L}
How do I access the mobile number? Is my custom tag correct?
I formatted the output in my tag as:
#register.assignment_tag
def my_mobile(*args, **kwargs):
m_mobile = ("%d" %int(kwargs['mobile']))
return {'m_mobile': m_mobile }
In the template fieldset.html changed the code as:
{% if field.field.name == 'sms_message' %}
<a target="hiddenIframe" href="http://url_for_send_sms.php?sms_message={{ field.field.value }}&phone=={{ mob.m_mobile }}">Click-to-send-sms</a>
{% endif %}
Important: Both the mobile number and the sms_message are in the same line of the fieldset in the django modeladmin (in my case). So above code belongs to the loop {% for line in fieldset %} loop
Try
{% for ln in fieldset %}
{% for fld in ln %}
{% if f.field.name == 'mobile' %}
{{ f.field.value }}
{% endif %}
{% endfor %}
{% endfor %}
Maybe this is not the best solution ... but it is solution :)
I'm working on an Inclusion Tag. In the super shell, the tag returns the appropiate data set nevertheles, I dont see the inclusion template rendered on the calling template. I can only guess the inclusion template is in the wrong location. As of this moment, the template is at MYPROJECT/templates which is the ONLY folder in TEMPLATE_DIRS. Please help me figure out what am I doing wrong here. TIA!
MYPROJECT/newsroom/templatetags/blog_extras.py -> http://pastebin.com/ssuLuVUq
from mezzanine.blog.models import BlogPost
from django import template
register = template.Library()
#register.inclusion_tag('featured_posts.html')
def featured_posts_list():
"""
Return a set of blog posts whose featured_post=True.
"""
blog_posts = BlogPost.objects.published().select_related("user")
blog_posts = blog_posts.filter(featured_post=True)
# import pdb; pdb.set_trace()
return {'featured_posts_list': blog_posts}
MYPROJECT/templates/featured_posts.html -> http://pastebin.com/svyveqq3
{% load blog_tags keyword_tags i18n future %}
Meant to be the the infamous "Featured Posts" Section!
{{ featured_posts_list.count }}
<ul>
{% for featured_post in featured_posts_list %}
<li> {{ featured_post.title }} </li>
{% endfor %}
</ul>
MYPROJECT/settings.py -> pastebin.com/Ed53qp5z
MYPROJECT/templates/blog/blog_post_list.html -> pastebin.com/tJedXjnT
As #Victor Castillo Torres said, you need to change the name of the tag you're loading, which will fix that aspect of your template tag. However, even though they are in different namespaces, I would still change the name of the context variable your tag returns just for sanity:
#register.inclusion_tag('featured_posts.html')
def featured_posts_list():
blog_posts = BlogPost.objects.published().filter(
featured_post=True).select_related("user")
return {'blog_posts': blog_posts}
Then in your template:
{{ blog_posts.count }}
<ul>
{% for blog_post in blog_posts %}
<li>{{ blog_post.title }} </li>
{% endfor %}
</ul>
And finally, in your main template:
{% load blog_extras keyword_tags i18n_future %}
...
{% featured_posts_list %}
I want to add some html element (button, "a" tag, etc ) to a django admin page. How can i do it? Please help.
Not sure where you want to add your stuff but this is a solution I found somewhere else on SO to change the HTML of a FileField (in my case i wanted to display the current image in an ImageField).
In other words you can make a widget that modifies the html of the field you want to customize:
# Widget that modifies the output of a FileField
class OutputWidget(AdminFileWidget):
# Overloaded django magic
def render(self, name, value, attrs=None):
output = []
# This is the place where we edit the output
if value and getattr(value, "url", None):
image_url = value.url
output.append(u' <img src="%s" alt="%s" />' % (image_url, image_url, image_url))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
# ModelAdmin class that is applied to the model
class MyModelSettings(admin.ModelAdmin):
# Overloaded django magic
def formfield_for_dbfield(self, db_field, **kwargs):
# Look for the field we want to edit and register the widget with it
if db_field.name == 'nameOfFieldIWantToEdit':
request = kwargs.pop("request", None)
kwargs['widget'] = OutputWidget
return db_field.formfield(**kwargs)
return super(MyModelSettings,self).formfield_for_dbfield(db_field, **kwargs)
# Register my overloaded settings with the model
admin.site.register(MyModel, MyModelSettings)
The code goes into admin.py where you register your models.
From the docs:
The Django admin site
Customizing the Django admin interface
I used Omokoli's solution from above but to make the field use my custom widget I did:
class MyModelAdminForm(forms.ModelForm):
class Meta:
model = get_model('myapp', 'mymodel')
widgets = {
'original_link': OutputWidget,
}
You can create a file under templates/admin called base_site.html
(create the "admin" folder in your app).
add this code:
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block userlinks %}
{% if site_url %}
{% trans 'View site' %} /
{% endif %}
{% if user.is_active and user.is_staff %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
{% trans 'Documentation' %} /
{% endif %}
{% endif %}
{% if user.has_usable_password %}
{% trans 'Change password' %} /
{% endif %}
{% trans 'Log out' %}
<!-- YOUR CUSTOM CODE HERE -->
<div class="your_custom_class">
{% trans 'your link 1' %} /
{% trans 'your link 2' %}
</div>
{% endblock %}
You can overwrite a lot of the admin html files. Make sure you extends the html you are overwriting, not to loose basic functionality.
See customize-django-admin-python for full admin templates tree you can overwrite.
You can also look at the base_site.html in Django project in Github. You'll find all of the "base_site" blocks you can plant your custom code in.
I'm trying to write a custom inclusion_tag in django.
Following the example on http://docs.djangoproject.com/en/dev/howto/custom-template-tags/
I'm just writing
from django import template
from libmas import models
register = template.Library()
#register.inclusion_tag('records.html')
def display_records(book_id):
book = models.book.objects.get(id__exact=book_id)
records = models.objects.filter(books=book)[0:10]
return {'records':records}
But I'm getting a
Invalid block tag: 'libmas_tags'
error in ie .
'records.html' file:
{% for record in records %}
<blockquote>{{record.id}}</blockquote>
{% endfor %}
my other html file is :
{% extends "admin/change_form.html" %}
{% libmas_tags %}
{% block after_field_sets %}
{% if object_id %}
{% display_records object_id %}
{% endif %}
{% endlock %}
The problem lies in your template. Its calling {% libmas_tags %}. Have you created template tags called libmas_tags? If so you might need to change it to
{% load libmas_tags %}
What is libmas_tags? The tag you have defined is called display_records, and that's what you should be calling in your template. If the tags file is called libmas_tags, you'll need to load that first as czarchaic points out.