Flask-Admin - Inline Model not working with field named something other than 'id' - flask-sqlalchemy

I am looking at inline models and have been testing out the example here:
https://github.com/mrjoes/flask-admin/tree/master/examples/sqla-inline
I have noticed that if the primary key field of the LocationImage model/table is renamed to something other than ID, then the after_delete handler does not get triggered.
So this works
class LocationImage(db.Model):
id = db.Column(db.Integer, primary_key=True)
alt = db.Column(db.Unicode(128))
path = db.Column(db.String(64))
location_id = db.Column(db.Integer, db.ForeignKey(Location.id))
location = db.relation(Location, backref='images')
#event.listens_for(LocationImage, 'after_delete')
def _handle_image_delete(mapper, conn, target):
try:
if target.path:
os.remove(op.join(base_path, target.path))
except:
pass
But if I rename the id column like so,
image_id = db.Column(db.Integer, primary_key=True)
Then _handle_image_delete does not get called.
I cannot fathom where this field is specified and how to make it work with a PK named something other than 'id'.
Thank you

In field_list.html a hidden field is rendered for the primary key. You need to change it to output your renamed field {{ field.form.image_id }}.
{% import 'admin/model/inline_list_base.html' as base with context %}
{% macro render_field(field) %}
{% set model = field.object_data %}
{% if model and model.path %}
{{ field.form.image_id }}
<img src="{{ url_for('static', filename=model.path) }}" style="max-width: 300px;"></img>
{% else %}
{{ field }}
{% endif %}
{% endmacro %}
{{ base.render_inline_fields(field, template, render_field) }}

Related

DBT - how can i add model configuration (using a macro on {{this}}) in dbt_project.yml

I want to add node_color to all of my dbt models based on my filename prefix to make it easier to navigate through my dbt documentation :
fact_ => red
base__ => black.
To do so i have a macro that works well :
{% macro get_model_color(model) %}
{% set default_color = 'blue' %}
{% set ns = namespace(model_color=default_color) %}
{% set dict_patterns = {"base__[a-z0-9_]+" : "black", "ref_[a-z0-9_]+" : "yellow", "fact_[a-z0-9_]+" : "red"} %}
{% set re = modules.re %}
{% for pattern, color in dict_patterns.items() %}
{% set is_match = re.match(pattern, model.identifier, re.IGNORECASE) %}
{% if is_match %}
{% set ns.model_color = color %}
{% endif %}
{% endfor %}
{{ return({'node_color': ns.model_color}) }}
{% endmacro %}
And i call it in my model .sql :
{{config(
materialized = 'table',
tags=['daily'],
docs=get_model_color(this),
)}}
This works well but force me to add this line of code in all my models (and in all the new ones).
Is there a way i can define it in my dbt_project.yml to make it available to all my models automatically?
I have tried many things like the config jinja function or this kind of code in dbt_project.yml
+docs:
node_color: "{{ get_model_color(this) }}"
returning Could not render {{ get_model_color(this) }}: 'get_model_color' is undefined
But nothing seems to work
Any idea? Thanks

How do I loop through alll columns using Jinja in DBT?

I want to iterate over all the columns using dbt.
You can use the built-in adapter wrapper and adapter.get_columns_in_relation:
{% for col in adapter.get_columns_in_relation(ref('<<your model>>')) -%}
... {{ col.column }} ...
{% endfor %}
I think the star macro from the dbt-utils package + some for-loop logic might help you here? This depends on the exact use case and warehouse you're using (as pointed out in the comments).
The star macro generates a list of columns in the table provided.
So a possible approach would be something along the lines of:
{% for col in [{{ dbt_utils.star(ref('my_model')) }}] %}
...operation...
{% endfor %}
If you have the model node, and you have columns defined as model properties, this will work:
{% for col in model.columns.values() %}
... {{ col.name }} ... {{ col.data_type }} ...
{% endfor %}
You can get the model node from the graph:
{% set model = graph.nodes.values()
| selectattr("resource_type", "equalto", "model")
| selectattr("name", "equalto", model_name)
| first %}

How to use variables in Twig filter 'replace'

Handing over an array from php of form
$repl_arr = array('serach-string1' => 'replace1', ...)
to a Twig template I would like to replace strings in a Twig variable per replace filter similar to this:
{{ block | replace({ repl_arr }) }}
That does not function and neither a variable loop like
{% for key,item in repla_arr %}
{% set var = block | replace({ key : item }) %}
{% endfor %}
does. What is wrong with it? How could it work?
Either you pass the whole array, or you loop the replaces.
But when looping the replaces you need to wrap key and value in parentheses to force interpolation of those
{% set replaces = {
'{site}' : '{stackoverflow}',
'{date}' : "NOW"|date('d-m-Y'),
} %}
{% set haystack = '{site} foobar {site} {date} bar' %}
{{ haystack | replace(replaces) }}
{% set output = haystack %}
{% for key, value in replaces %}
{% set output = output|replace({(key) : (value),}) %}
{% endfor %}
{{ output }}
fiddle

How access tuple item

models.py
class MyModel(models.Model):
GENDER = (('M',"Male"),('F',"Female"))
gender = models.CharField(max_length = 1, choices = GENDER)
template.html
{% for item in mymodels %}
{{ item.GENDER[item.gender] }} #HOW TODO?
{% endfor %}
You can find some answers here
I think that best bet is to use helper function that returns proper value or extend/write new filter.

Django template tag for Model query result

I wonna simple tag, for showing table of any model arrays like:
{% table city_list %}
Do anybody see such things?
You can try django-tables app, which allows you to do the following, given model Book:
# Define
class BookTable(tables.ModelTable):
id = tables.Column(sortable=False, visible=False)
book_name = tables.Column(name='title')
author = tables.Column(data='author__name')
class Meta:
model = Book
# In your views
initial_queryset = Book.objects.all()
books = BookTable(initial_queryset)
return render_to_response('table.html', {'table': books})
# In your template table.html
<table>
<!-- Table header -->
<tr>
{% for column in table.columns %}
<th>{{ column }}</th>
{% endfor %}
</tr>
<!-- Table rows -->
{% for row in table.rows %}
<tr>
{% for value in row %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I think the above is much more elegant and self explanatory than just doing
{% table book_list %}
Try generic vieww e.g. http://www.djangobook.com/en/2.0/chapter11/
I've made a fork of django-tables which makes this extremely easy. Here's a simple example:
In models.py:
from django.db import models
class City(models.Model):
name = models.CharField(max_length=200)
state = models.CharField(max_length=200)
country = models.CharField(max_length=200)
In tables.py:
import django_tables as tables
from .models import City
class CityTable(tables.Table):
class Meta:
model = City
In views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from .models import City
from .tables import CityTable
def city_list(request):
queryset = City.objects.all()
table = CityTable(queryset)
return render_to_response("city_list.html", {"city_table": table},
context_instance=RequestContext(request))
In city_list.html:
{% load django_tables %}
{% render_table city_table %}