Check if column nullable before insert? - doctrine-orm

TL;DR: Can I check if a field is nullable or not during or before persisting?
I am currently trying to find a smooth way to implement an "insert entry if sufficiently complete" form.
This simplified table is an autogenerated table for the entity class "User". Phone is nullable, the rest is not nullable in the schema.
<table>
<tr data-id="25">
<td><input type="text" data-property="FirstName">Alice</td>
<td><input type="text" data-property="LastName">Smith</td>
<td><input type="text" data-property="Mail">alice#example.org</td>
<td><input type="text" data-property="Phone"></td>
</tr>
... more populated rows and at the end one empty row for new entries
<tr data-id="*">
<td><input type="text" data-property="FirstName"></td>
<td><input type="text" data-property="LastName"></td>
<td><input type="text" data-property="Mail"></td>
<td><input type="text" data-property="Phone"></td>
</tr>
</table>
I have a simple ajax call which in the event that any input field is changed, sends data-property, value and data-id to the backend. The backend decides if this is an update or insert (data-id == *) and performs the action, returning the new id if it was an insert.
Now the big question: The update fails, of course, since the backend can't create a new entity if not all nonnullable fields are filled with information.
I was therefore wondering if there is any possibility to dynamically check before any insert if a field is nullable or not.

Thanks to Cerad's hint I could write a function that seems to work! Feel free to modify according to your liking!
Note that the class name must be fully qualified. I use ShortName::class for my solution.
public function getNonNullableFieldNames(EntityManagerInterface $EM, string $class_name)
{
$table_name = $EM->getClassMetadata($class_name)->getTableName();
$columns = $EM->getConnection()->getSchemaManager()->listTableColumns($table_name);
$nonnullable_fields = [];
foreach($columns as $col){
if($col->getNotnull()){
$nonnullable_fields[] = $col->getName();
}
}
return $nonnullable_fields;
}
I'm not particularly proud of the foreach-loop, but a combination of array_map and array_filter became too convoluted for my taste.

Related

HTMX form submission with a table

I am trying to use the Click to Edit example with HTMX, by using a table.
Each row (<tr>) is a database record that looks like this:
<tr hx-target="this" hx-swap="outerHTML">
<form>
<td><input type="text" name="name" value="{{row.name}}"></td>
<td><input type="text" name="email" value="{{row.email}}"></td>
<td>
<button class="btn" hx-put="/edit/{{row.id}}">Update<buttun>
<button class="btn" hx-get="/view/{{row.id}}">Cancel</button>
</td>
</form>
</tr>
Unfortunately, when I print the request body with request.form.keys on my flask server, I see that that the request is empty ([])
It seems like the button click did not trigger the form submission with all the input fields.
How can I make the button click trigger the form submission with all the fields populated ?
Ah, just remembered: you are working with tables here. Unfortunately tables are super picky about the elements inside them, and I bet form doesn't work where you put it. If you inspect the DOM I bet you'll find that there isn't really a form element in there, so htmx isn't finding it to include the inputs.
You'll need to rework this to include the values in a different way, for example using hx-include.
Something like this:
<tr hx-target="this" hx-swap="outerHTML">
<td><input type="text" name="name" value="{{row.name}}"></td>
<td><input type="text" name="email" value="{{row.email}}"></td>
<td>
<button class="btn" hx-put="/edit/{{row.id}}"
hx-include="closest tr">
Update
<button>
<button class="btn" hx-get="/view/{{row.id}}">Cancel</button>
</td>
</tr>
If you are willing to switch from table rows to divs, the original code you had should work fine.
This is an unfortunate situation where tables are not very flexible.
update: #guettli reminded me that you can include any element and it will include all inputs below it, so you can just use closest tr in your hx-include attribute. Thanks!
Can you post what the request looks like from the chrome or firefox console?
This looks correct, in general.

pass both loaded and input values ​to a function using url_for

i'm trying to pass values ​​as parameters using url_for but i have some problems as i have first some data loaded by a function and then, some data inserted manually using the <input ../> constructs. How can I do?
<td align = "center"> <a href = "{{url_for ('insertResults', idGia = attribute [0], language = attribute [4], level = attribute [5], info = info, written = written, oral = oral, session = session)}} "type =" submit "class =" btn btn-primary "> Insert </td>
where info, written and oral are the data entered as input in the following ways:
<td align = "center"> <input type = "text" placeholder = "100" id = "info" name = "info" /> </td>
<td align = "center"> <input type = "text" placeholder = "100" id = "written" name = "written" /> </td>
<td align = "center"> <input type = "text" placeholder = "100" id = "oral" name = "oral" /> </td>
The url_for function is executed on the server side. It is not possible to pass parameters from form fields to this.
Are you sure you want to use a GET request for this? It seems to me that a POST request makes more sense in your situation.
The following example shows you different methods with which you can transfer variables with a POST request and query them within your route. The data largely find their place within the request body. Only the attribute with the name "attr0" is sent within the url.
<form action="{{ url_for('indert_results', attr0=attr[0]) }}" method="POST">
<input type="hidden" name="val0" value="{{ attr[1] }}" />
<input type="text" name="val1" />
<input type="text" name="val2" />
<button type="submit">Submit</button>
</form>
#app.route('/insert-results/<int:attr0>', methods=['POST'])
def insert_results(attr0):
val0 = request.form['val0']
val1 = request.form.get('val1')
val2 = request.form.get('val1', 'default-value1')
print(
f'attribs: {attr0}',
f'values: {val0}, {val1}, {val2}',
sep='\n'
)
# ...
If you do insist on a GET request, I still advise you to use a form so that you can transfer the entries from the form fields as query parameters.
All data is transmitted in different sections of the url. The query parameters are added to the url in the form "?param0=value0&param1=value1".
<form action="{{ url_for('insert_results', attr0=attr[0], attr1=attr[1]) }}" method="GET">
<input type="text" name="param0" />
<input type="text" name="param1" />
<input type="text" name="param2" />
<button type="submit">Submit</button>
</form>
#app.route('/insert-results/<int:attr0>-<str:attr1>', methods=['GET'])
def insert_results(attr0, attr1):
param0 = request.args['param0']
param0 = request.args.get('param1')
param1 = request.args.get('param2', 'default-value2')
print(
f'attribs: {attr0}, {attr1}',
f'params: {param0}, {param1}, {param2}'
sep='\n'
)
# ...
Regardless of whether you use the form or ask for the arguments within the url, you use a kind of dictionary which allows you to use .get(key [, default] [, type = <func_ptr>]) to ensure that a KeyError is bypassed, a default value is passed and possibly the type of the value is converted.
Choose the transmission method wisely and consider the visibility of the data for third parties, taking into account that the transmission may later take place in encrypted form. You should also consider the amount of data you want to send. The more data you want to transfer, the sooner you will switch to a POST request.
Especially with several data records that are transmitted individually, you can later think of a transmission using ajax. However, this is a more complex solution and the explanation would lead too far at this point.

Loop over tbody in Django views

I am trying to loop over a tbody in my django views to get the data from the form but when i print the items in the tbody it only shows the last one
Here's the part I am trying to loop on
<tbody class="player-instances">
<tr>
<td><input type="text" name="form-0-pname" id="id_form-0-pname"></td>
<td><input type="number" name="form-0-hscore" id="id_form-0-hscore"></td>
<td><input type="number" name="form-0-age" id="id_form-0-age"></td>
</tr>
<tr>
<td><input type="text" name="form-0-pname" id="id_form-1-pname"></td>
<td><input type="number" name="form-0-hscore" id="id_form-1-hscore"></td>
<td><input type="number" name="form-0-age" id="id_form-1-age"></td>
</tr>
</tbody>
Views.py
if form.player_instances.cleaned_data is not None:
for item in form.player_instances.cleaned_data:
print("item", item)
print("form.cleaned_data", form.cleaned_data)
player = Player()
player.pname= item['pname']
player.hscore= item['hscore']
player.age= item['age']
player.save()
team.player.add(player)
team.save()
The output in terminal is the following:
item {'pname': 'tt22', 'hscore': 8, 'age': 89}
form.cleaned_data {'tname': 'tt1'}
Why is it overriding the first input fields despite having different id?
Try different name in name field like : form-1-pname and so on.
Thanks.

How to generate dynamic name for a <td> and pass the name of it to server

I have the following code :
{% for assessments in list_assessments%}
<form action="/test/" method="post">{%csrf_token%}
<tr>
<td>{{assessments.assessment_id}}</td>
<td>{{assessments.name}}</td>
<td>{{assessments.assessment_begin_date}}</td>
<td>{{assessments.assessment_end_date}}</td>
<td>{{assessments.is_active}}</td>
<td>{{assessments.is_complete}}</td>
<td>{{assessments.created_at}}</td>
<td>{{assessments.updated_at}}<br></td>
<td><input type="submit" value="Edit Assessment" /></td>
</tr>
{%endfor%}
</form>
All the data here are dynamically coming.
In this following code, i need to assign an name to assessments.name dynamically, something like
<td name="dynamic_name">{{assessment.name}}</td>.
And on clicking the button "Edit Assessment", i want the dynamic_name to be passed and received my the view.
The idea is each assessment has its own set of parameters. I want to display only the parameters related to the name. So if i could pass the value i would be able to do it.
Any help appreciated.
Your ending **</form>** tag should be before for loop.
{% for assessments in list_assessments%}
<form action="/test/" method="post" name="form-{{ assessments.counter }}">{%csrf_token%}
<tr>
<td>{{assessments.assessment_id}}</td>
<td>{{assessments.name}}</td>
<td>{{assessments.assessment_begin_date}}</td>
<td>{{assessments.assessment_end_date}}</td>
<td>{{assessments.is_active}}</td>
<td>{{assessments.is_complete}}</td>
<td>{{assessments.created_at}}</td>
<td>{{assessments.updated_at}}<br></td>
<td><input type="submit" value="Edit Assessment" /></td>
</tr>
</form>
{%endfor%}
Now, You can get specific block values by form name ( see above code ) in javascript as well as in python.
In Javascript,
form = document.getElementByTagName("form")
elems = form.children("td")
elems will give you all td elements.

Hidden data in a form, but PrimaryKey or ForeignKey

I have a view that edits an instance of model Foo. It's either called with one arg (form post) or three args (initial request to edit the object):
def edit_it(request, key1_id=-1, key2_id=-1):
where key1_id and key2_id identify the particular instance to edit. On entry, I check to see if I've been called from a form post or from a link
if request.method == 'POST':
key1_id = request.key1_id # first thing that doesn't work
key2_id = request.key2_id # (also doesn't work)
foo = Foo.objects.get(key1=key1_id, key2=key2_id)
form = Foo(request.POST, instance=foo)
...
else:
foo = Foo.objects.get(key1=key1_id, key2=key2_id)
form = Foo(instance=foo)
In my template, I explicitly insert <input type="hidden" ... > for key1_id and key2_id. So it seems reasonable that key1_id and key2_id should be in request.POST somewhere, but I've not found it poking through code, docs, and google.
Or am I completely confused and I should do this differently? I tried specifying the key[12]_id fields in the model with "widget=forms.HiddenInput", but widget doesn't work here: key1_id is a primary key and key2_id is ForeignKey whose job is just to avoid fishing for other people's objects by modifying key1_id in the URL.
The html that results (now slightly modified thanks to the suggestion to maintain the args to the post) is this:
<table>
<form action="/seededit/u=2/sh=14" method="post">
<div style='display:none'>
<input type='hidden' name='csrfmiddlewaretoken'
value='19a559c496e637cdbf3132ce8e147cc4' /></div>
[...]
<tr>
<td><input type="hidden" name="user_id" value="2" />
<input type="hidden" name="shareable_id" value="14" /></td>
<td><input type="submit" value="Submit" name="submit" /></td>
</tr>
</form>
</table>
</p>
It's not request.key2_id It's request.POST['key2_id]` request.POST is a QueryDict that acts like a dictionary, so print request.POST will show you a dictionary.
That being said, you can still use/define those fileds as HiddenInput and then use django's form validation to make sure that they are the right type/exist etc. There are loads of options when it comes to handling forms, request variables, and validation.