Two self reference field in same db model mongoengine - python

I have a db models like following:
class Image(mongoengine.Document):
project = mongoengine.ReferenceField('Project', required=True,
reverse_delete_rule=mongoengine.CASCADE)
next = mongoengine.ReferenceField('self', required=False)
prev = mongoengine.ReferenceField('self', required=False)
name = mongoengine.StringField(unique_with='project', required=True)
created_on = mongoengine.DateTimeField(default=datetime.utcnow())
There are two fields referring back to same model.
Just to test the validity I removed one of them and then tried to save an Image object, it worked, but when both next and prev are in the dbmodel, in this case while saving an image object I am getting a error that:
ValidationError: None is not a valid ObjectId.
How to resolve this issue?
Does mongoengine does not support to have two self referring dbfields?
Any help would be really appreciated.

got the error.
next
is an inbuilt function, which should not be kept as a dbfield.
replacing it with any other variable which is not an inbuilt property will work.

Related

'Category' object is not subscriptable Django

I am learning Django. I wrote a simple model and some views method in Django rest framework so that I can modify some particular attributes when needed to all the records that need that. Here is the model:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255)
isActive = models.BooleanField(default=True)
def __str__(self):
return self.name
Then, I created this view to modify the isActive session when I call it:
class CategoriesChangeActiveView(views.APIView):
def post(self, request, format=None):
try:
categories = request.data.get('categories')
for category in categories:
category = Category.objects.get(id=category['id'])
category.isActive = category['isActive']
category.save()
except Exception as e:
return Response({'error': 'Bad request'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'success': 'Active changed'}, status=status.HTTP_200_OK)
Even when the format of my request is correct ( I debugged each line ) when it comes to the line category.isActive = category['isActive']it throws the error that'Category' object is not subscriptable`. I don't know why or how to fix it.
I saw in the official documentation, on older StackOverflow questions that this is doable, but I don't understand why I can't.
Can someone please suggest what I am doing wrong? Thank you
it's a simple mistake.
Simply change it as follows and it should be fixed:
categories = request.data.get('categories')
for category in categories:
category_obj = Category.objects.get(id=category['id'])
category_obj.isActive = category['isActive']
category_obj.save()
What you're doing is changing what the variable category is. You for loop and the unpacked variable is category, but then you get the model object and set the variable as category
So initially, the category variable is in fact a dictionary object, but you change it to be a django model object instance.
Specifically, the issue is here:
category = Category.objects.get(id=category['id'])
category.isActive = category['isActive']
You set category to be an instance of the Category model (which in this case corresponds to a db record, but that bit is a little irrelevant).
Accessing attributes on a class instance is not done by the square bracket notation, but rather dot notation.
So instead of category['isActive'] use category.isActive
If category was a dictionary, eg.
category = {
"name": "cat",
"isActive": True,
}
Then you would use the square bracket notation as category["isActive"] to get that value.
As it is, it's not a dict, so python thinks you are trying to subscript the instance somehow, which will not work.

AttributeError: module has no attribute

When I try to change function name "random_string" which is used in auth_code (variable in model class) to any other name it shows me the error in the command line: AttributeError: module 'users_data.models' has no attribute 'random_string'
from django.db import models
from django.utils.timezone import now
import random
from django.core.exceptions import ValidationError
def random_string():
return int(random.randint(000000, 999999))
def validate_phone_number(phone):
if len(phone) < 7:
raise ValidationError('Phone number can not be less than 7 digits')
class Users(models.Model):
phone = models.CharField(verbose_name='Phone', max_length=20, validators=
[validate_phone_number])
auth_code = models.IntegerField(verbose_name='Code',
default=random_string)
get_in_date = models.DateTimeField(default=now, blank=False,
editable=False)
I have seen many posts which cover my problem but I didn't find any useful. I would appreciate any help.
The issue lies within your migrations files, as shown in this issue. Basically, when you generated your previous migration files, it was written that the default was value for a field was random_string.
Now, if you change that function name, your current code will work, but because your already-generated migration files use this function, they will raise an error as they cannot find that function anymore.
I dont know if simply updating the files to replace the name within them would be enough. Other solutions would be to reset the migrations (though it might come as a cost).
The link I've provided offers a script to fix that, but I haven't tested it myself

Django model set lookup very slow

I'm getting a very slow lookup in my Django models.
I have two tables:
class Scan(models.Model):
scan_name = models.CharField(max_length=32, unique=True, validators=[alphanumeric_plus_validator])
class ScanProcessingInfo(models.Model):
scan_name = models.CharField(max_length=32)
processing_name = models.CharField(max_length=64)
in_progress = models.BooleanField(default=False)
When I perform the following operation to get a list of all Scan objects which have a ScanProcessingInfo for a specific processing_name:
scans = models.Scan.objects.all()
scan_set = []
for scan in scans:
if self.set_type_definition.test_scan(scan, self.arg1, self.arg2):
scan_set.append(scan)
(test_scan routes to)
def get_proc_info_been_done(scan, spd_name):
try:
proc_info = models.ScanProcessingInfo.objects.get(scan_name = scan.scan_name)
except models.ScanProcessingInfo.DoesNotExist:
proc_info = None
if proc_info == None:
return False
return not proc_info.in_progress
the request takes about 10 seconds. There are 300 Scans in total and 10 ScanProcessingInfos. The db backend is an RDS MySQL db. I also expect someone will tell me off for using strings for the cross-table identifiers, but I doubt that's the cause here.
I'm sure I'm doing something obvious wrong, but would appreciate a pointer, thank you.
I think what you're asking is how to get all Scans for which a matching ScanProcessingInfo exists.
The first thing to do is to declare the actual relationship. You don't need to change your database (you should, but you don't have to); you can use your existing underlying field, but just tell Django to treat it as a foreign key.
class ScanProcessingInfo(models.Model):
scan = models.ForeignKey('Scan', to_field='scan_name', db_field='scan_name', on_delete=models.DO_NOTHING)
Now you can use this relationship to get all the scans in one go:
scan_set = Scan.objects.exclude(scanprocessinginfo=None)
Edit
To get all matching objects with a specific attribute, use the double-underscore syntax:
scan_set = Scan.objects.filter(scanprocessinginfo__processing_name=spd_name)
Use Many-to-one relationship.
scan_name = ForeignKey(Scan, related_name='processing_infos',on_delete=models.CASCADE)

Django: how to save model instance after deleting a ForeignKey-related instance?

I am using Django 2.1.1.
I have a model Analysis that, among other fields, contains a ForeignKey to a MyFile model (a model I wrote to handle files):
from polymorphic.models import PolymorphicModel
from django.db.models import Model, DateTimeField, FileField, SET_NULL
from django.db.models.signals import pre_delete
class MyFile(Model):
file = FileField(upload_to='./', null=False, blank=False)
description = CharField(max_length=255, null=True, blank=True)
date_added = DateTimeField(auto_now_add=True)
#receiver(pre_delete, sender=MyFile)
def mymodel_delete(sender, instance, **kwargs):
"""
To delete the file connected to the `sender` class: receive the pre_delete signal
and delete the file associated with the model instance.
"""
instance.file.delete(False)
class Analysis(PolymorphicModel):
# ... other fields ...
file_results = ForeignKey(MyFile, on_delete=SET_NULL,
related_name='file_results',
null=True, blank=True)
Analysis is a PolymorphicModel for reasons related to the bigger project.
In Analysis.file_results I set on_delete=SET_NULL because I want to allow an Analysis instance to exist even without a file_result, which can be populated later.
Let's suppose I have added a few files (the MyFile table has a few rows) and a few Analysis instances. Now, if I want to delete the file related to one of the instances of Analysis I do:
a = Analysis.objects.get(pk=0)
a.file_results.delete()
a.save()
but I get the following error:
File "/Users/mtazzari/djangos/views.py" in update_job_refs
377. a.save()
File "/Users/mtazzari/anaconda/envs/djangos/lib/python3.6/site-packages/polymorphic/models.py" in save
83. return super(PolymorphicModel, self).save(*args, **kwargs)
File "/Users/mtazzari/anaconda/envs/djangos/lib/python3.6/site-packages/django/db/models/base.py" in save
670. "unsaved related object '%s'." % field.name
ValueError: save() prohibited to prevent data loss due to unsaved
related object 'file_results'.
The mymodel_delete function that is called on pre_delete signal works correctly as the file gets actually deleted from the file system.
However, I really don't understand how to solve the ValueError.
Interestingly, I notice that the following lines work fine, i.e. do not raise any ValueError, get the file deleted from the file system, and the FK in a.file_results set to Null:
a = Analysis.objects.get(pk=0)
tmp = a.file_results
a.file_results = None
tmp.file_results.delete()
a.save()
But, is this a proper way of doing this? What is the best practice for deleting a related object?
Thanks!
First, note that you don't need to save() just because of the delete(). The delete() will update the database as required.
That said, it's reasonable to want to continue using the instance to do other operations, leading to a save(). The reason you're getting the error is that the a.file_results Python object still exists, and references a database row that is now missing. The documentation for delete() mentions this:
This only deletes the object in the database; the Python instance will still exist and will still have data in its fields.
So if you want to continue to work with the instance object, just set the attribute to None yourself. Similar to your code above, except you don't need the temp object.
a = Analysis.objects.get(pk=0)
a.file_results.delete()
a.file_results = None
# ... more operations on a
a.save() # no error

how to get datetime instance?

Well it is look like simple question. but i am in the learning stage can`t figure out.
This is my model class
class Store(models.Model):
file = models.FileField(upload_to=content_file_name)
file_name = models.CharField(max_length=100)
created_date = models.DateTimeField(auto_now_add=True)
userfild = models.ForeignKey(user,null=True, blank=True)
Ok for some clarification i just included my content_file_name function here
def content_file_name(instance, filename):
return os.path.join(
"user_%d" % instance.created_date, filename)
but the output of the folder structure looks like this
`None`
----filename
i can get the file_name instance like this --> intance.file_name
but when i enter instance.created_date it is return 'None' value.
What i am missing.? And my another doubt is i set it DateTimeField as auto_now_add=True So it`s saved into the db when form is submitted. But why None return?
auto_now_add is not populated until the object is saved. If you want a default that is applied as soon as the object is instantiated, use the default parameter with a callable:
created_date = models.DateTimeField(default=datetime.datetime.now)
Not quite sure that this is what you're asking, but here goes anyway:
You create an instance of any class by instantiating it:
Store()
In Python, this calls the class's init() function. Since you don't have one, it will use the 'constructor' from the class you're inheriting from, models.Model.
So, for example, you could do something like this:
my_store = Store()
my_store.file_name = 'some new name!'

Categories