can i set django model paranoid which acts like in Sequelize.js - django

// don't delete database entries but set the newly added attribute deletedAt
// to the current date (when deletion was done). paranoid will only work if
// timestamps are enabled
paranoid: true,
I used Sequelize.js ORM, and there was option paranoid like above description. (from Sequelize.js tutorial docs)
I want to make my Django Model paranoid.
I googled with keywords like "django paranoid", but i couldn't find informations. What is a general name for the option "paranoid" and how can i make my django model act like the option?
Or should I make mixins or middlewares to make paranoid?

of course, you can use django-paranoid
this library will add deleted_at, updated_at and created_at field, also a soft delete method.
You only need extend to model with ParanoidModel.
For see the deleted object you can use objects_with_deleted:
MyModel.objects_with_deleted.last()
and if do you want do hard delete an object you only should use True param:
m = MyModel.objects.last()
m.delete(True)

Related

How to find out whether default value is used for Datastore ndb property?

Let's say we have a model like this:
class UserConfig(ndb.Model):
name = ndb.StringProperty()
email_subscriber = ndb.BooleanProperty(default=True)
Let's assume email_subscriber was set to default True by mistake and we want to fix that mistake and use default=False instead. I tried changing the value to default=False and that works fine for users created after that code is deployed, but that doesn't fix the problem for existing users.
Is there a way (e.g. some internal property which isn't documented in Datastore documentation), which would provide info whether given prop value was set explicitly by user or using the provided default.
I can write an upgrade which would set email_subscriber=False for all users, but I'm afraid some users might have intentionally checked this property in the app and wouldn't like to break their experience.
tl;dr: How can I determine if value in ndb object was set using the default for that property or was provided explicitly.
There is no way to know this. Once a value is set in the database there is no way to know which part of your code (ndb runs in your code from the database perspective) set the value.

Django: How to depend on an externally ID, which can be switched?

Consider the following scenario:
Our Django database objects must rely on IDs that are provided by external service A (ESA) - this is because we use this ID to pull the information about objects that aren't created yet from the external directly. ESA might shut down soon, so we also pull information about the same objects from external service B (ESB), and save them as a fallback.
Because these IDs are relied on heavily in views and URLs, the ideal scenario would be to use a #property:
#property
dynamic_id = ESA_id
And then, if ESA shuts down, we can switch easily by changing dynamic_id to ESB_id. The problem with this though, is that properties cannot be used in queryset filters and various other scenarios, which is also a must in this case.
My current thought is to just save ESA_id, ESB_id, and dynamic_ID as regular fields separately and assign dynamic_ID = ESA_id, and then, in case ESA shuts down, simply go over the objects and do dynamic_ID = ESB_id.
But I feel there must be a better way?
Having ESA_id and ESB_id fields in the same table is a good solution, then you have some kind of setting (DEFAULT_SERVICE_ID='ESA_id'|'ESB_id') and your code change the lookup based on this option.
Here you can see an aproach to create filters dynamicly
https://stackoverflow.com/a/310785/1448667

Django 1.8 Migrations. Adding DateTimeField after db creation. Best practices?

So some time a couple migrations after my first one, I decided I wanted to include these fields:
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
into one of my models. When I makemigrations it gave me
You are trying to add a non-nullable field 'created' to episode without a default; we can't do that (the database needs
something to populate existing rows).
So I then changed it to
created = models.DateTimeField(auto_now_add=True, default=datetime.now)
After trying to makemigrations again, it said that at_api.Episode.modified: (fields.E160) The options auto_now, auto_now_add, and default are mutually exclusive. Only one
of these options may be present.
All right, so I just went ahead and removed the auto_now_add
created = models.DateTimeField(default=datetime.now)
I could now makemigrations without any problems. And then I later removed default=datetime.now and replaced it with auto_now_add=True, and migrated again without any problems. However, I can't help feeling that this might not be the best way of doing things. I feel like something might go wrong later in the project.
I think the best practice here would have been to make the fields nullable. What your created field means at the moment is: "The time when the instance was created, or the arbitrary time when I ran the migration." The standard way to represent the lack of a value is NULL, rather than an arbitrary value.
That said, if you do want to use some arbitrary value you just need to tell Django what it is. Usually makemigrations gives you the option to indicate a one-off value to use for existing rows - did that not happen?
A more laborious method would be to declare the field nullable, then create a data migration to fill in your desired value, and then make it non-nullable. What you did is basically a simplified version of that. I don't see it creating any problems moving forward other than the issue of created not really being the time the instance was created.
I've just had the exact problem. I use Django 1.10. I read Kevin answer and I've tried to put default value when Django asked me to fill it as datetime.now string.
And I was surprised because, for those fields, Django automatically ask you if you want to use datetime.now as default:
$ ./manage.py makemigrations
You are trying to add the field 'date_created' with 'auto_now_add=True' to projectasset without a default; the database needs something to populate existing rows.
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
You can accept the default 'timezone.now' by pressing 'Enter' or you can provide another value.
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
[default: timezone.now] >>>
So, I just confirm that and everything seems to be working fine!

Cascade changes in Mongodb in Django

Is there a way to change a element of collection in Mongoose and be cascade changed in other collection that points this element, similar to using MySQLs foreign keys?
For example, in MySQL I'd assign a foreign key and set it to cascade on change or delete. Thus, if I were to delete or change name of a activity_Type, all applications and associated activity_Types would be removed or affected as well.
class ValuesHelper(object):
NAME = 'activityType'
def __init__(self, neo_on=False):
self.client = MongoClient(settings.DATABASES['mongo']['HOST'],settings.DATABASES['mongo']['PORT'])
self.db = self.client[settings.DATABASES['mongo']['NAME']]
Unfortunately, there is no support for cascade changes at the moment.
(Take a look at this jira ticket)
So you need to implement that behavior in your application. For example, if you were using Mongoose, you can do it using its remove Middleware. Take a look at JohnnyHK's answer from another SO question for an example.

Django - How to pass dynamic models between pages

I have made a django app that creates models and database tables on the fly. This is, as far as I can tell, the only viable way of doing what I need. The problem arises of how to pass a dynamically created model between pages.
I can think of a few ways of doing such but they all sound horrible. The methods I can think of are:
Use global variables within views.py. This seems like a horrible hack and likely to cause conflicts if there are multiple simultaneous users.
Pass a reference in the URL and use some eval hackery to try and refind the model. This is probably stupid as the model could potentially be garbage collected en route.
Use a place-holder app. This seems like a bad idea due to conflicts between multiple users.
Having an invisible form that posts the model when a link is clicked. Again very hacky.
Is there a good way of doing this, and if not, is one of these methods more viable than the others?
P.S. In case it helps my app receives data (as a json string) from a pre-existing database, and then caches it locally (i.e. on the webserver) creating an appropriate model and table on the fly. The idea is then to present this data and do various filtering and drill downs on it with-out placing undue strain on the main database (as each query returns a few hundred results out of a database of hundreds of millions of data points.) W.R.T. 3, the tables are named based on a hash of the query and time stamp, however a place-holder app would have a predetermined name.
Thanks,
jhoyla
EDITED TO ADD: Thanks guys, I have now solved this problem. I ended up using both answers together to give a complete answer. As I can only accept one I am going to accept the contenttypes one, sadly I don't have the reputation to give upvotes yet, however if/when I ever do I will endeavor to return and upvote appropriately.
The solution in it's totality,
from django.contrib.contenttypes.models import ContentType
view_a(request):
model = create_model(...)
request.session['model'] = ContentType.objects.get_for_model(model)
...
view_b(request):
ctmodel = request.session.get('model', None)
if not ctmodel:
return Http404
model = ctmodel.model_class()
...
My first thought would be to use content types and to pass the type/model information via the url.
You could also use Django's sessions framework, e.g.
def view_a(request):
your_model = request.session.get('your_model', None)
if type(your_model) == YourModel
your_model.name = 'something_else'
request.session['your_model'] = your_model
...
def view_b(request):
your_model = request.session.get('your_model', None)
...
You can store almost anything in the session dictionary, and managing it is also easy:
del request.session['your_model']