django-tables2 exporting custom URL column - python

G'day All,
Hope everyone is doing well.
I have a table that I render with a custom column that is a hyperlink.
The problem is when i export to CSV it just gives me the text of the hyperlink and not the hyperlink.
I'm wanting to export the hyperlink instead of just the text, is this possible?
(if i need to switch to xlsx export that's also fine)
(worse comes to worse I can just make the text the full path)
Custom column:
document_link = tables.TemplateColumn('{{record.document_file}}', verbose_name="Document location")
Thanks in advance,

I would suggest making use of "Including and Excluding Columns"
https://django-tables2.readthedocs.io/en/latest/pages/export.html#including-and-excluding-columns
Add exclude_from_export=True to the document_link field, and an invisible document_link_for_csv field.
class DocumentTable(tables.Table):
document_link = tables.TemplateColumn(
'<a href="{{record.document_file.url}}/"
target="_blank">{{record.document_file}}</a>',
verbose_name="Document location",
exclude_from_export=True
)
document_link_for_csv = columns.Column(
visible=False,
accessor="document_file__url"
)
Update based on comment:
You can pass the request through to the table, and then do a custom render and request.build_absolute_uri().
class DocumentTable(tables.Table):
document_link = tables.Column(
verbose_name="Document location",
exclude_from_export=True
)
document_link_for_csv = columns.Column(
visible=False,
accessor="document_file__url"
)
def render_document_link_for_csv(self, value, record):
return format_html(
'{},
request.build_absolute_uri(),
record.document_file.url,
record.document_file
)

This was the final way how I managed to do it:
class DocumentTable(ExportMixin,tables.Table):
document_link = tables.TemplateColumn('{{record.document_file}}', verbose_name="Document location", exclude_from_export=True)
document_URL = tables.TemplateColumn('render_replaces_this',visible=False)
def render_document_URL(self, value, record):
return format_html(
'{}{}',
self.request.META['HTTP_HOST'],
record.document_file.url,
)

Related

Unable to display multiple readonly fields in Django admin, only one will display

I'm trying to display two new rows (fields) in the "posts" section of django admin which are read-only fields that take data from two other database columns. My code works, but it will not create two new fields, it only displays one.
I'm relatively new to Django and python, and I'm struggling to figure out how to do this. I spent too much time trying different things only to have no success.
In the context of my test, I want to see two readonly fields called "New row 1" and "New row 2", which take the data from two database columns called "est_completion_time" and "downtime". I can only see "New row 2" on the output.
This is my code in admin.py:
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = JBForm
exclude = ['est_completion_time'] # hide this database column
exclude = ['downtime'] # hide this database column
readonly_fields = ['placeholder_1'] # display this one
readonly_fields = ['placeholder_2'] # display this one
#admin.display(description="New row 1")
def placeholder_1(self, obj):
return obj.est_completion_time # a new readonly field which should display contents of 'est_completion_time' column
#admin.display(description='New row 2')
def placeholder_2(self, obj):
return obj.downtime # a new readonly field which should display contents of 'downtime' column
After reading through the docs I couldn't find a solution:
https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets
https://docs.djangoproject.com/en/4.0/ref/contrib/admin/actions/
Any help would be greatly appreciated.
I believe you need to specify the excluded and readonly_fields once.
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = JBForm
exclude = ["est_completion_time", "downtime"]
readonly_fields = ["placeholder_1", "placeholder_2"] # display these two
#admin.display(description="New row 1")
def placeholder_1(self, obj):
return obj.est_completion_time
#admin.display(description="New row 2")
def placeholder_2(self, obj):
return obj.downtime

simple-salesforce - How to create Knowledge Page Layout programatically?

I've been able to create a Record Type and Custom Field for the Knowledge module of Salesforce with the metadata api implemented in simple-salesforce's python library, but when trying to create a Page Layout it throws an exception without much info on why is the creation failing (or at least I don't get it).
I'm trying to create the page layout in the following way:
def create_page_layout(self, layout_name, fields):
mdapi = self.sf.mdapi
# custom_layout_section = []
custom_layout_items = []
for field in fields:
custom_layout_items.append(mdapi.LayoutItem(
field=field
))
custom_layout_section = [mdapi.LayoutSection(
label='Information',
style='OneColumn',
layoutColumns=mdapi.LayoutColumn(
layoutItems=custom_layout_items
)
)]
custom_layout = mdapi.Layout(
fullName='Knowledge__kav.' + layout_name + '__c',
layoutSections=custom_layout_section
)
mdapi.Layout.create(custom_layout)
The param layout_name contains 'TestDefaultPL'.
The param fields contains ['Title', 'UrlName'].
The exception: Exception: Knowledge__kav.TestDefaultPL__c: (FIELD_INTEGRITY_EXCEPTION, Parent entity failed to deploy).
The docs about this object: link.
As an example, I was able to create a custom field for the Knowledge module in the following way:
def create_custom_field(self, name):
mdapi = self.sf.mdapi
# TODO: Field permissions
custom_field = mdapi.CustomField(
label=name, # Field label
fullName='Knowledge__kav.' + name + '__c', # Field name (format has to be CustomObject.FieldName)
type=mdapi.FieldType("LongTextArea"),
length=32000,
description='Default Rich Text Area',
visibleLines=25
)
return mdapi.CustomField.create(custom_field)
Could someone help me with this problem about the Page Layout creation?

How to send data into word document with Django?

I'm using Django I want to send some data from my database to a document word, I'm using Python-Docx for creating word documents I use the class ExportDocx it can generate a static word file but I want to place some dynamic data (e.g. product id =5, name=""..) basically all the details to the "product" into the document
class ExportDocx(APIView):
def get(self, request, *args, **kwargs):
queryset=Products.objects.all()
# create an empty document object
document = Document()
document = self.build_document()
# save document info
buffer = io.BytesIO()
document.save(buffer) # save your memory stream
buffer.seek(0) # rewind the stream
# put them to streaming content response
# within docx content_type
response = StreamingHttpResponse(
streaming_content=buffer, # use the stream's content
content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
)
response['Content-Disposition'] = 'attachment;filename=Test.docx'
response["Content-Encoding"] = 'UTF-8'
return response
def build_document(self, *args, **kwargs):
document = Document()
sections = document.sections
for section in sections:
section.top_margin = Inches(0.95)
section.bottom_margin = Inches(0.95)
section.left_margin = Inches(0.79)
section.right_margin = Inches(0.79)
# add a header
document.add_heading("This is a header")
# add a paragraph
document.add_paragraph("This is a normal style paragraph")
# add a paragraph within an italic text then go on with a break.
paragraph = document.add_paragraph()
run = paragraph.add_run()
run.italic = True
run.add_text("text will have italic style")
run.add_break()
return document
This is the URL.py of the
path('<int:pk>/testt/', ExportDocx.as_view() , name='generate-testt'),
How can I generate it tho I think I need to make the data string so it can work with py-docx.
for the python-docx documentation: http://python-docx.readthedocs.io/
For a product record like: record = {"product_id": 5, "name": "Foobar"), you can add it to the document in your build_document()` method like:
document.add_paragraph(
"Product id: %d, Product name: %s"
% (record.product_id, record.name)
)
There are other more modern methods for interpolating strings, although this sprintf style works just fine for most cases. This resource is maybe not a bad place to start.
So I found out that I need to pass the model I was doing it but in another version of code and forgot to add it... Basically, I just had to add these lines of code, hope this helps whoever is reading this.
def get(self, request,pk, *args, **kwargs):
# create an empty document object
document = Document()
product = Product.objects.get(id=pk)
document = self.build_document(product)
And in the build of the document we just need to stringify it simply by using f'{queryset.xxxx}'
def build_document(self,queryset):
document = Document()
document.add_heading(f'{queryset.first_name}')

Django-admin linked column issue

Following this answer I wanted to add a linked column to my admin page,
class AnswerAdmin(admin.ModelAdmin):
list_display = ('__str__', 'link_to_question', 'time_created', 'time_updated', 'created_by', 'down_vote', 'up_vote')
def link_to_question(self, obj):
link = urlresolvers.reverse("admin:QnA_question_change",
args=[obj.question.id]) # model name has to be lowercase
text = obj.question.__str__
str = format_html("{}", text)
return mark_safe(u'%s' % (link, str))
class Meta:
model = Answer
but what I get in return is this:
<bound method Entry.__str__ of <Question: This is a question about technology?>>
I only want the "This is a question ..." part shown in my admin.
Sidenote:
when I use something like obj.question.text instead of a function it works smoothly.
It isn't clear why you are using format_html then passing the result to mark_safe. You should be able to do it in one step with format_html. This has the advantage of escaping text, in case a use has inserted malicious content.
link = urlresolvers.reverse(...)
text = obj.question
link_str = format_html('{}', link, text)
To call the __str__ method you need to call it with obj.question.__str__(). However, it's more pythonic to call str(obj.question) rather than obj.question.__str__(). In this case, I don't think you need to use str() at all, since you are using format_html.
just set the allow_tags = True property of the method.
class AnswerAdmin(admin.ModelAdmin):
list_display = ('__str__', 'link_to_question', 'time_created', 'time_updated', 'created_by', 'down_vote', 'up_vote')
def link_to_question(self, obj):
link = urlresolvers.reverse("admin:QnA_question_change",
args=[obj.question.id]) # model name has to be lowercase
return u'{1}'.format(link, obj.question)
link_to_question.short_description = u'Link'
link_to_question.allow_tags = True

Django-tables2 - can't I use [A('argument')] inside the "text" parameter?

I'm trying to make this table with a clickable field which changes the boolean for the entry to its opposite value. It works, but I want an alternative text as "False" or "True" does not look nice, and the users are mainly Norwegian.
def bool_to_norwegian(boolean):
if boolean:
return "Ja"
else:
return "Nei"
class OrderTable(tables.Table):
id = tables.LinkColumn('admin_detail', args=[A('id')])
name = tables.Column()
address = tables.Column()
order = tables.Column()
order_placed_at = tables.DateTimeColumn()
order_delivery_at = tables.DateColumn()
price = tables.Column()
comment = tables.Column()
sent = tables.LinkColumn('status_sent', args=[A('id')])
paid = tables.LinkColumn('status_paid', args=[A('id')], text=[A('paid')])
class Meta:
attrs = {'class': 'order-table'}
If you look under the "paid" entry I am testing this right now, why can't I access the data with the same accessor as I do in the args? If I change the args to args=[A('paid')] and look at the link, it does indeed have the correct data on it. The model names are the same as the ones in this table, and "paid" and "sent" are BooleanFields.
This is kind of what I ultimately want:
text=bool_to_norwegian([A('paid')])
Here is what I send to the table:
orders = Order.objects.order_by("-order_delivery_at")
orders = orders.values()
table = OrderTable(orders)
RequestConfig(request).configure(table)
The text argument expects a callable that accepts a record, and returns a text value. You are passing it a list (which it will just ignore), and your function is expecting a boolean instead of a record. There is also no need for using accessors here.
Something like this should work:
def bool_to_norwegian(record):
if record.paid:
return "Ja"
else:
return "Nei"
Then in your column:
paid = tables.LinkColumn('status_paid', text=bool_to_norwegian)
(Note, it is not clear from your question where the data is coming from - is paid a boolean? You may need to adjust this to fit).
As an aside, the way you are passing args to your columns is weird (it seems the documentation also recommends this, but I don't understand why - it's very confusing). A more standard approach would be:
id = tables.LinkColumn('admin_detail', A('id'))
or using named arguments:
id = tables.LinkColumn('admin_detail', accessor=A('id'))

Categories

Resources