Django ListField with add and remove - python

The below link specifies how to create a list-field in Django.
How to create list field in django
My question; how to add, remove items to this field? if in case that's possible. I want to be able to add to and remove from this field of a Model's instance afterwards. If not possible please someone suggest me an alternative.

in ListField:
to_python function is used to convert database string to python object(here is list)
get_prep_value is used to handle python object to string(to store into database next step).
when you call your obj.listfield, such as a.list, you'll get a python list, so you could use a.list.append(val), a.list.insert(0, val) method to operate, and at last call a.save(), listfield will do the conversion for you between database and python.
class Dummy(models.Model):
mylist = ListField()
def insert_to_mylist(self, index, value):
self.mylist.insert(index, value)
#self.save()
def remove_from_mylist(self, value):
self.mylist.remove(value)
#self.save()
for example:
d = Dummy()
d.mylist.insert(0, 'tu')
d.save()
d.mylist.remove('tu')
d.save()
d.insert_to_mylist(0, "tu")
d.save()
d.remove_from_mylist('tu')
d.save()
if you want to insert or remove without .save(), just add .save() to insert_to_mylist and remove_from_mylist function.
ListField is just used to conversion between database and python, so add a remove or insert to it may be difficult. But you can do it in your Model, if many Models need to use this method, just write an abstract model.

My way of storing lists in models is by converting them to a string and storing them as TextField.

Related

Saving the query object of one Django-Model into another

I am new to Django.
I want to save the queried instance of Model-A,'Q' into Model-B. Model-A corresponds to Database D1
and Model-B to D2.
In simple terms something like:
Q=queryset(A).using('D1')
Q.save(database='D2',model='Model-B')
I this case, ‘A’ and ‘B’ are not the same kind of models, but the queryset used on ‘A’, returns the fields identical to those of ‘B’.
I realise this can be achieved by using a simple for loop to copy instance_A into instance_B and then use save(), but is there a way to do it by passing some arguments to save like save(model=‘B’, using=‘DB2’)?
Maybe check out Manually selecting a database for a QuerySet and Selecting a database for save.
My guess is that you should only use one model (if they have the same exact fields).
I'm not sure if the code below will work as is, but something like that.
queryset = A.objects.using('D1').all()
for instance in queryset:
instance.save(using='D2')

Django: How to add to an ArrayField?

I have some questions about the ArrayField mentioned here: https://docs.djangoproject.com/en/3.1/ref/contrib/postgres/fields/#django.contrib.postgres.fields.ArrayField
How do you add to an ArrayField? It's clear you can treat it like a regular field and do things like
my_array_field = []
my_array_field.save()
But what's confusing is I'm seeing everyone mention my_array_field.append("something") in StackOverflow questions. This isn't mentioned in the documentation at all. Moreover, if an arrayfield is .append()ed to, does it still require .save()?
do we need to call save()?
Yes, we need to call the save() method to COMMIT the changes to Database. Unless calling the save() method, the value only persists in the scope of the variable, as the python list. So, calling the save() is a must do thing while updating the values.
how to add values to array field?
You can treat it as a normal python list object, because Django converts the db array field to native Python list object
model_instance.my_array_field = [1,2,3]
model_instance.save()
model_instance.my_array_field += [4,5,6]
model_instance.save()
This isn't mentioned in the documentation
Probably, they may be missed to include this information.
Django documentation ArrayField
recommends to add some default value, and make it callable, so just try in your models:
class SomeModel(models.Model):
...
my_array_field = ArrayField(models.CharField(max_length=255), default=list)
So you'll be able to add items in it just like with regular list in python:
my_array_field.append("something")
my_array_field.append("another_something")
And even more - you can use all methods like pop, extend, index etc.

Is there a way to map data from form to insert in to database without explicitly defining each variable?

I have made a really long form with the help of colander alchemy and deform.
This form has 100 or so fields and currently the only way I know to add the data back to the database once form is submitted is to explicitly re-define each variable and then add that to the database but there must be a better way.
#my schema
class All(colander.MappingSchema):
setup_schema(None,atr)
atrschema =atr.__colanderalchemy__
setup_schema(None,chemicals)
chemicalsschema =chemicals.__colanderalchemy__
setup_schema(None,data_aquisition)
data_aquisitionschema =data_aquisition.__colanderalchemy__
setup_schema(None,depositor)
depositorschema =depositor.__colanderalchemy__
setup_schema(None,dried_film)
dried_filmschema =dried_film.__colanderalchemy__
form = All()
form = deform.Form(form,buttons=('submit',))
# this is how I get it to work by redefining each field but there must be a better way
if 'submit' in request.POST:
prism_material = request.params['prism_material']
angle_of_incidence_degrees =
request.params['angle_of_incidence_degrees']
number_of_reflections = request.params['number_of_reflections']
prism_size_mm = request.params['prism_size_mm']
spectrometer_ID = 6
page = atr (spectrometer_ID=spectrometer_ID,prism_size_mm=prism_size_mm,number_of_reflections=number_of_reflections,angle_of_incidence_degrees=angle_of_incidence_degrees,prism_material=prism_material)
request.dbsession.add(page)
Would like to somehow just be able to remap all of that 'multi dictionary' that is returned back to the database?
So, you have a dict (request.params) and want to pass the key-value pars from that dict to a function? Python has a way to do that using **kwargs syntax:
if 'submit' in request.POST:
page = Page(spectrometer_ID=6,**request.params)
request.dbsession.add(page)
(this works also because SQLAlchemy provides a default constructor which assigns the passed values to the mapped columns, no need to define it manually)
Of course, this is a naive approach which will only work for the simplest use-cases - for example, it may allow passing parameters not defined in your schema which may create a security problem; the field names in your schema must match the field names in your SQLAlchemy model; it may not work with lists (i.e. multiple values with the same name which you can access via request.params.get_all(name)).

ndb to_dict method does not include object's key

I am leveraging ndb's to_dict method to convert an object's properties into a python dict. From everything I can tell, this method does not include the object's key or parent within the dict as per the documentation:
https://developers.google.com/appengine/docs/python/ndb/modelclass#Model_to_dict
However for my situation I need the key to be in the dict. My preference would be to leverage the builtin method and subclass it or something similar rather than create my own to_dict method.
What is the best way to accomplish this or am I missing something obvious? Thanks in advance.
FYI: I am not leveraging django for this project but instead straight python deployed up to gae.
You're not missing anything ;-)
Just add the key to the dictionary after you call to_dict, and yes override the method.
If you have multiple models that don't share the same base class with your custom to_dict, I would implement it as a mixin.
to define to_dict as a method of a Mixin class. you would
class ModelUtils(object):
def to_dict(self):
result = super(ModelUtils,self).to_dict()
result['key'] = self.key.id() #get the key as a string
return result
Then to use it.
class MyModel(ModelUtils,ndb.Model):
# some properties etc...
Another easy way to achieve that (without having to override to_dict) is to add a ComputedProperty that returns the id, like so:
class MyModel(ndb.Model):
# this property always returns the value of self.key.id()
uid = ndb.ComputedProperty(lambda self: self.key.id(), indexed=False)
# other properties ...
A ComputedProperty will be added to the result of to_dict just like any other property.
There are just two constraints:
Apparently the name of the property can not be key (since that would conflict with the actual key) and id doesn't work either.
This won't work if you don't specify a key or id when you create the object.
Also, the computed value will be written to the data store when you call put(), so it consumes some of your storage space.
An advantage is that this supports the include and exclude arguments of to_dict() out of the box.

Ordering Django queryset by a #property [duplicate]

This question already has an answer here:
Sorting a Django QuerySet by a property (not a field) of the Model
(1 answer)
Closed 8 years ago.
I'm trying to order a query set by a property I defined in the model, but not sure the best way to do this. Here's the property:
#property
def name(self):
if self.custom_name:
return self.custom_name
else:
return self.module_object.name
Essentially, I'd like to do a:
things = Thing.objects.all().order_by('-name')
but of course getting a Caught FieldError while rendering: Cannot resolve keyword 'name' into field.
Any ideas?
EDIT: I understand that I can't sort this way because the #property isn't a database field. My question is how to sort given that #property isn't a database field.
You can't do that because that property is not in MySQL, but in your python code. If you really want to do this, you can on the client-side(though it will be very slow):
sorted(Thing.objects.all(), key=lambda t: t.name)
order_by happens on the sql level, so it can't make use of properties, only field data.
have a look at the queryset api, you may be able to make use of e.g. extra to annotate your query and sort on that
Have a look at django-denorm. It lets you maintain calculated values in the database (which you can then use to sort efficiently) for the cost of a single method decorator.
You can only order by database fields. You can pull all records, turn them into a list, and sort them, although that may be inefficient and slow.
Or you can add a database field called name and fill it in via a post-save hook; then you can sort it using order_by.

Categories