How to circumvent the restriction on field names? - python-2.7

If I define a recarray r with a field called data as follows
import numpy
r = numpy.zeros( 1, numpy.dtype([('data', 'f8')]) ).view(numpy.recarray )
the data field will refer to some internal recarray buffer rather than a floating point number. Indeed, running
r.data
yields
<read-write buffer for 0x7f3c10841cf8, size 8, offset 0 at 0x7f3c1083ee70>
rather than [0]. I suspect the reason for the failure is that recarray already has a member called data and hence it just ignores my field called data. The same problem occurs if I try to use any name of already existing members of recarray.
My questions are:
1) Is it possible to circumvent this limitation of recarray and how to do it?
2) Is this limitation likely to be lifted in the future?

Here is the getattribute method for recarray. Python translates obj.par1 to obj.__getattribute__('par1'). This would explain why the field name has to be a valid attribute name, when used in recarrays.
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr) #**
except AttributeError: # attr must be a fieldname
pass
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
except (TypeError, KeyError):
raise AttributeError("record array has no attribute %s" % attr)
obj = self.getfield(*res)
# if it has fields return a recarray, otherwise return
# normal array
if obj.dtype.fields:
return obj
if obj.dtype.char in 'SU':
return obj.view(chararray)
return obj.view(ndarray)
The ** line explains why obj.data returns the buffer pointer, not your field. Same would apply to 'shape' and 'strides'. This also makes it possible to access array methods. You want the recarray to behave as much like a regular array as possible, don't you?
The field names in a structured array are like the keys of a dictionary, relatively free form (though I've never explored the limits). But in recarray, those names have to function also a attribute names. Attributes names have to be valid variable names - that's a Python constraint.
In https://stackoverflow.com/a/32540939/901925 I quote from the genfromtxt docs:
Numpy arrays with a structured dtype can also be viewed as recarray, where a field can be accessed as if it were an attribute. For that reason, we may need to make sure that the field name doesn’t contain any space or invalid character, or that it does not correspond to the name of a standard attribute (like size or shape), which would confuse the interpreter.
Also a tutorial on Python classes says:
Attribute references use the standard syntax used for all attribute references in Python: obj.name. Valid attribute names are all the names that were in the class’s namespace when the class object was created.
https://docs.python.org/2/tutorial/classes.html#tut-object

Related

Converting an object into a Queryset

I have two functions
def xyz(obj):
obj_queryset = Sample.objects.filter(id=obj.id)
callfunction(obj_queryset)
def callfunction(obj_queryset):
for obj in obj_queryset:
obj.start_date = datetime.date.today()
obj.end_date = datetime.date.today()
obj.save()
I need it as a queryset for certain reasons because i want to update multiple objects and I am also doing few calculations before updating which I am not posting here.
Is there any way to turn obj into a queryset without doing a database query.
callfunction does not use anything specific from queryset. It treats its argument as a sequence a.k.a. iterable. Practically speaking it means that anything you can use in a for loop can be passed to the function.
In order to process a single object by this function you can pass a sequence with that object to your function and it can be any sequence that is iterable (not necessarily queryset), for example it can be a list:
callfunction([obj])
This is absolutely valid and it a usual python idiom.

get_or_create returning error that multiple value of objects exist when I check same parameters with filter it retuns 0 objects

I am trying to use get_or_create method to see if a record exists. If the record exists do nothing otherwise create it.
This model is basically used on the command that is failing
class modelStudentExamsPerformed(models.Model):
patient = models.ForeignKey(modelPatient)
student = models.ForeignKey(modelStudent,on_delete=models.CASCADE)
normalBodyPart = models.ForeignKey(modelNormalBodyPartResult,default=None,blank=True,null=True)
abnormalBodyPart = models.ForeignKey(modelAbnormalBodyPartResult,default=None,blank=True,null=True)
tool = models.CharField(max_length=128, default="")
Now this is the command that is using the above model and failing
exams.modelStudentExamsPerformed.objects.get_or_create()(patient=patient_qset, student=stud_qset,abnormalBodyPart=qset[0],normalBodyPart=None,date=None)
The above statement gives me the error :
get() returned more than one modelStudentExamsPerformed -- it returned 2!
Now this is where I am having trouble. When I look into the database through my admin I do notice two objects but those objects both have a value associated with normalBodyPart and their abnormalBodyPart is empty.Since I explicitly specified and assigned a value to abnormalBodyPart why does django say that two items already exist ? I hope this makes sense .
Let e explain this another way as well suppose there are two statements 1 and 2.
Statement 1 gets or creates a record based on a specified parameter . This get or create fails as django thinks there are already two records. However statement 2 uses the same exact parameters and returns 0 records. Why is that ? What am I missing and not understanding here ?
Statement 1:
exams.modelStudentExamsPerformed.objects.get_or_create()(patient=patient_qset, student=stud_qset,abnormalBodyPart=qset[0],normalBodyPart=None,date=None)
when clearly none of the objects in this table have a value for abnormalBodyPart. I validated this by doing the following
Statement 2:
k = exams.modelStudentExamsPerformed.objects.filter(patient=patient_qset, student=stud_qset,abnormalBodyPart=qset[0], normalBodyPart=None,date=None)
The above statment 2 does not return anything. My question is why does Statement 2 not return anything while statement 1 is complaining that there are 2 items already thus failing the get call.
You're invoking get_or_create() without arguments and then invoke the __call__() method on the resulting instance.
Put the keywords inside the get_or_create to make it work properly. Also study the method signature again: you're missing a defaults argument. The method works like this:
Filter on provided keyword arguments, except "defaults"
If nothing is returned, create a new instance with those keyword arguments and use the "defaults" keyword argument, which should be a dictionary to fill additional fields.
Sometimes, it's better to illustrate:
instance, created = Players.objects.get_or_create(
username='Lagolas',
defaults={'class': 'ranger', 'gender': 'male'}
)
Is equivalent to:
try:
instance = Players.objects.get(username='Lagolas')
return instance, False
except Players.DoesNotExist:
instance = Players.objects.create(
username='Lagolas', class='ranger', gender='male'
)
return instance, True

ObjectDoesNotExist vs. .filter().first() and check for None

In Django 1.6 they introduced .first() to get the first element of a queryset. [Source]
Now there are 2 ways to get a single element:
user_id = 42
try:
obj = User.objects.get(id=user_id)
except ObjectDoesNotExist:
raise Exception("Invalid user id given")
and:
user_id = 42
obj = User.objects.filter(id=user_id).first()
if not obj:
raise Exception("Invalid user id given")
Following the pythonic way to ask for forgiveness, the first one would be more appreciated way to use.
However, the second one might be easier to understand and it is one line shorter.
Q1: Is there any difference in speed between these two code snippets?
Q2: Which one is the preferred way to get a single object?
The two have different semantics and different gaurantees. The main difference is how they handle multiple matching objects.
.get() will raise an exception if multiple objects match the given query. You should therefore use .get() to fetch an item based on a unique property (such as id) or set of properties.
.first() will return the first item, based on the defined ordering, if multiple objects match the given query. Use this to filter on non-unique properties, when you need a single item, the first one based on some (possibly undefined) ordering.
So while .get() guarantees that exactly one item matches the query, .first() only guarantees that it returns the first item based on the given ordering.
How they handle a missing object is more a case of semantics. It is trivial to convert an exception to None or the other way around. While you might save a single line here and there, I wouldn't base my decision to use one over the other on this. The performance difference is negligible as well, and probably depends on the results of the query.

MongoEngine: Replacing get_or_create with upsert/update_one

I understand that get_or_create is now deprecated in favour of using upsert, but how do I make update_one to return the object rather the number of objects modified, and can I just retrieve an object if I don't want to update anything?
e.g.
Model.objects.get_or_create(first_name='John', last_name='Potter', age=40)
# assuming that first_name + last_name + age are enough to uniquiely indentify a person
returns a Model object (a new object if it didn't exist, and existing object if it does). What would be the equivalent of this using the new method?
Model.objects(first_name='John', last_name='Potter', age=40).update_one(upsert=True)
# returns number of objects (1)
Model.objects(first_name='John', last_name='Potter', age=40).update_one(set__first_name='John', set__last_name='Potter', set__age=40,upsert=True)
# returns number of objects (1)
Is there a way to make it return the object, and make it behave exactly like get_or_create?
I couldn't find how to do this in the documentation
You are very close but you need to use a findAndModify command via modify rather than an update command.
NewDoc = Model.objects(first_name='John',
last_name='Potter',
age=40).modify(upsert=True, new=True,
set__first_name='John,
set__last_name='Potter',
set__age=40,
set_on_insert__newUser=True)
Take note of the first 2 modify kwargs - upsert and new. Also take note of the $setOnInsert operator example which will only set a field if the findAndModify does an upsert.
You should look at modify. Passing a new=True you'll get the updated object (or document, in mongodb parlance).

how to extract fields data from filtered object django

By below line m getting
members = Member.objects.filter(profile=profiles)
i want to pass memeber with field name in this line same as here https://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-initial-data-with-a-formset
member_formset = MemberFormSet(initial=members)
gives me an error
'Member' object is not iterable
please suggest best way to do it ?
Try to pass only one object to initial, e.g. members[0]. Filter returns list of objects.
You don't pass objects as initial to a formset (it's for a dictionary of values). Use queryset=members instead.