self excluding excecution of functions in django - python

i have a django model that has values stored in a json field.
but some of the values have to be unique, for that i have a function check_unique().
but this check fails if two users try to save the same value at the same time since when check_unique() runs neither of the values is stored in the database and then they are individually correct.
There is a way to avoid this behavior?
i tried avoiding this using trheadeing.Lock but apache runs in different processes and it does'nt work in that case.
Besides, i would like that the check would be at application level (in python) and not at database level.
the code looks like this:
semaphore.claim()
try:
uniques = check_unique(self.answers)
if not uniques:
self.go_save()
semaphore.release()
return Response("All OK")
except Exception as e:
semaphore.release()
return e

Have you looked at atomic requests in Django? https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.atomic
Aas far as I know, if you make that transaction with the database atomic, it would not be able for the second user to save it to the database. What atomic does, basically, is that it will try to save the values to the database, but when it recognizes an exception, it will revert those changes to the database.
Another approach would be to create a custom validator, that checks the value twice. So once it will check to see if the value exists in the db, and then x seconds later (randomize that so both users won't be able to validate the exact same time). That way, if user 1 has already saved it to the database, the second check would see it and cancel the operation.
Finally, check out https://github.com/alecthomas/voluptuous. May be it does what you need!
Hope that helps.

Related

When updating unpredictable columns out of many, how to keep the other columns with their current values?

Using Python and the built-in Sqlite:
When I use a prepared statement, not knowing what columns the user will want to update:
UPDATE_AUTHOR = """UPDATE lastName=?, firstName=?, age=?, nationality=? FROM authors
WHERE _id = ?
"""
How can I replace the '?' with some value that will keep the current value for some of the columns?
From the user perspective, I will tell him for example to press 'Enter' if he wishes to keep the current value. So for instance, he presses 'Enter' on lastName, updates firstName, updates age, and presses 'Enter' on nationality. And I replace his 'Enter' with, hopefully, a value that will keep the current value.
Is that possible? If not, how can I solve this problem differently but efficiently?
I thought about building the prepared statement dynamically, in the above example: adding firstName=?, and age=?, after "UPDATE, and then the rest of the statement FROM authors WHERE _id = ?". But this seems less comfortable and less organized.
There are 2 ways of handling this question. One is to build a specific UPDATE query containing only the fields that will change. As you have said it is less comfortable because the query and the parameter list have to be tweaked.
Another way it to consistently update all the parameters, but keep the saved values for those which should not change. This is a common design in user interfaces:
the user is presented all the values for an object and can change some of them
if they confirm their choice, the application retrieves all the values, either changed or not and uses them in an UPDATE query.
Anyway, it is common the read the all the values before changing some, so it is not necessarily expensive. And at the database level, changing one or more values in an update has generally almost the same cost: a record is loaded from disk (or cache), some values are updated which is the cheapest operation, and it is then written back to disk. Even with the database caches, the most expensive part in the databases I know is to load and save the record.

Does it possible that transaction.atomic does not work as expected?

This is a DRF API View for entry like. When someone like a entry, i will insert a like record into table entry_like, and plus by 1 to field likes_num in another table entry. But, something went wrong that some of the count of entry_like records corresponding to one entry is less than the field likes_num in table entry. I do not know why it does not work as expected even the post method is with decorator transaction.atomic on. Are there some cases that the decorator transaction.atomic does not run as expected?
Yes, I think it is the case that transaction.atomic() does not work the way you expect.
To understand what it does, you have to understand SQL's transaction isolation levels and exactly what behavior they guarantee. You don't mention what database you're using, but PostgreSQL has good documentation on the subject.
Your expectation seems to be that it will work as if the isolation level was SERIALIZABLE. In fact, the default isolation level in Django is READ COMMITTED. And in that isolation level, if you have two of these transactions operating at once, they will both overwrite likes_num with the same number.
One solution is to use an F-object instead of setting likes_num to a specific value. In that case, the new value will be based on whatever value is in the field at the time of the write, rather than what value was in the field at the earlier point when you read the row.
entry.likes_num = F('likes_num') + 1
The other solution is to use select_for_update(), which will lock the entry row. It's better to avoid locks if you can, so I would opt for the F-object version.
I think you need to use F objects
from django.db.models import F
...
entry.likes_num = F('likes_num') + 1
entry.save()
Because you do not have any errors in code execution and two transactions are valid.

how to handle exceptions in alembic migrations?

I have an alembic migration script and I want to add some exception handling but not sure what is the best practice.
Basically, I have several issues to handle:
A change was already made and not needed (e.g. if I try to
add_column, and this column already exists, I want it to continue)
A table is locked (if I try to perform some operation on a table and
it is locked, I want to raise an exception)
other exceptions?
def upgrade():
engine = op.get_bind().engine
op.add_column('t_break_employee', sa.Column('auto', sa.Boolean()))
op.add_column('t_employee', sa.Column('settings', sa.Text()))
I thought about adding a class to be used with the 'with' statement on every change. Does it sound reasonable?
for example:
def upgrade():
engine = op.get_bind().engine
with my_test():
op.add_column('t_break_employee', sa.Column('auto', sa.Boolean()))
with my_test():
op.add_column('t_employee', sa.Column('settings', sa.Text()))
In that case, what are the exceptions I need to handle and how do I know if a table is locked?
I'm not refering to specific issues of the API you use, but I discourage you from this approach.
Really migration is something that has two two outcomes:
Migration did apply succesfully
Database is in state before migration (and hence there was some kind of error).
Proper way to deal with errors is to fix the migration. Your approach is allows third migration outcome:
Migration did fail but some changes were applied
This would result in schema corruption which is a bad thing!

Django Models Counter

I am using Django with a bunch of models linked to a MySQL database. Every so often, my project needs to generate a new number (sequentially, although this is not important) that becomes an ID for rows in one of the database tables. I cannot use the auto-increment feature in the models because multiple rows will end up having this number (it is not the primary key). Thus far, I have been using global variables in views.py, but every time I change anything and save, the variables are reset with the server. What is the best way to generate a new ID like this (without it being reset all the time), preferably without writing to a file every time? Thanks in advance!
One way is to create a table in your database and save those values that you want in it. Another way is to use HTTP Cookies to save values if you want to avoid server reset problem. Though, I do not prefer this way.
You can follow this link to set and read values from Cookies in django:-
https://docs.djangoproject.com/en/dev/topics/http/sessions/#s-setting-test-cookies

Appengine (python) returns empty for valid queries

EDIT: Figured it out. For whatever reason the field in the index was called strWord instead of wordStr. I didn't notice because of the similarities. The file was auto generated, so I must have called the field that in a previous development version.
I've got an app with around half a million 'records', each of which only stores three fields. I'd like to look up records by a string field with a query, but I'm running into problems. If I visit the console page, manually view a record and save it (without making changes) it shows up in a query:
SELECT * FROM wordEntry WHERE wordStr = 'SomeString'
If I don't do this, I get 'no results'. Does appengine need time to update? If so, how much?
(I was also having trouble batch deleting and modifying data, but I was able to break the problem up into smaller chunks.)
When this has happened to me it's because I've been using a TextField, which cannot be queried (but confusingly just gets ignored). Try switching to StringField.

Categories

Resources