Querying a django model using a model name string input - python

Let's say i have the following django models:
class ModelB(models.Model):
title = models.CharField(max_length=20)
class ModelD(models.Model):
name = models.CharField(max_length=20)
In the django ORM, i am trying to read a string which will be the name of a model, and use it to query. Something like this:
>>b = 'ModelB'
>>b.objects.all()
This will obviously not work as it is a string. I have looked at ContentType but i am not sure how it will be helpful in my scenario. Any suggestions?
I also tried doing a get operation on Contentype like this:
>>> z = ContentType.objects.get(model='modelb')
>>> z
<ContentType: model b>
>>> z.__dict__
{'model': u'modelb', '_state': <django.db.models.base.ModelState object at 0x7f195346c150>, 'id': 14, 'app_label': u'testapp'}
>>>
But i did not know how to proceed further from here!

If you're using Django < 1.7, I think you can do this.
from django.db.models.loading import get_model
z = ContentType.objects.get(model='modelb')
ModelB = get_model(z.app_label, 'ModelB')
For django >= 1.7, you can
from django.apps import apps
z = ContentType.objects.get(model='modelb')
ModelB = apps.get_model(z.app_label, 'ModelB')
you can then use ModelB to query.

Related

Sorting dictionary in django model using json field

I am trying to store a dictionary in my Django project as a model. The model is present but it wont update the values. any ideas?
model.py:
class MyModel(models.Model):
jsonM = JSONField()
Main.py:
myList = [1,2,3,4,5,6,7,8,9]
print("this is my model")
MyModel.objects.all().update(jsonM=myList)
When i do:
print(MyModel.objects.all())
print(type(MyModel.objects.all()))
I get the following:
<QuerySet []>
<class 'django.db.models.query.QuerySet'>
Try this:
newObject = MyModel(jsonM = mylist)
newObject.save()

Determine if an M2M field has a custom through model

With a custom through model for an M2M relationship, .add(), .create() and .remove() are disabled.
At the moment, I attempt to use .add() (or whatever) and catch and deal with AttributeError for those custom M2M relationships.
Is there an 'official' way to identify a custom through model, using the Meta API or otherwise? At this stage in my processing, I would rather treat all custom through relationships as generically as possible (rather than lots of if m2m_field.related.through == FooBar statements)
(A solution was found for Django 1.8, but I'm starting a bounty for 2.2)
Looks as though
m2m_field.related.through._meta.auto_created is False
does the job.
From Django 2.2 the .add(), .create(), etc. methods are able to work with a custom through Model as long as you provide the corresponding values for the required fields of the intermediate model using through_defaults:
From the documentation:
You can also use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields:
>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
You may prefer to create instances of the intermediate model directly.
The .remove() method's behavior needs a bit of attention:
If the custom through table defined by the intermediate model does not enforce uniqueness on the (model1, model2) pair, allowing multiple values, the remove() call will remove all intermediate model instances:
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>
About the _meta field I haven't been able to access it from the m2m field, but the above part of the documentation seems to allow avoiding the "gymnastics" of accessing _meta.
If I find anything interesting I will update my answer accordingly.
For django 2.2 you can directly check the whether the through model is autocreated or not
This can be checked through a direct check like the following
# check for the auto_created value
m2m_field.through._meta.auto_created == False
To test this I created some sample clases with multiple M2M fields one with a custom through field and one with default class.
from django.db import models
import uuid
class Leaf(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(null=True, max_length=25, blank=True)
# Create your models here.
class MainTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
new_leaves = models.ManyToManyField(Leaf, through='LeafTree')
leaves = models.ManyToManyField(Leaf, related_name='main_branch')
class LeafTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tree = models.ForeignKey(MainTree, on_delete=models.CASCADE)
leaf = models.ForeignKey(Leaf, on_delete=models.CASCADE)
Testing our method
In [2]: from trees.models import MainTree
In [3]: m = MainTree()
In [4]: m.leaves.through._meta
Out[4]: <Options for MainTree_leaves>
In [5]: m.leaves.through._meta.auto_created
Out[5]: trees.models.MainTree
In [6]: m.new_leaves.through._meta.auto_created
Out[6]: False
In [7]: m.new_leaves.through._meta.auto_created == False
Out[7]: True
In [8]: m.leaves.through._meta.auto_created == False
Out[8]: False

Reverse foreignkey query with peewee

I'm using the peewee orm and I would like to know how to do a reverse foreignkey query.
These are my models:
class Device(BaseModel):
mac = CharField()
ip = CharField()
class Metrics(BaseModel):
device = ForeignKeyField(Device, related_name="metrics")
sensor = CharField()
analog = FloatField(null = True)
timestamp = DateTimeField()
I would like to know the simplest way to get all the Devices that have a Metric with a field sensor="temperature".
I can solve it with various querys and some iteration, but I wonder if there is a more direct way to do it.
Thanks
One way:
Device.select().join(Metric).where(Metric.sensor == 'temperature')
Another way:
Device.select().where(fn.EXISTS(
Metric.select().where((Metric.sensor == 'temperature') & (Metric.device == Device.id))
))

How to get properties of a model attribute?

Let's say that I have a class such as :
class MyClass(models.Model):
attributeA = models.CharField(max_length=100)
attributeB = models.IntegerField()
attributeC = models.CharField(max_length = 150, blank=True, nullable = True)
attributeD = models.ForeignKey('ModelB',related_name='FK_modelB')
attributeE = models.ManyToManyField('ModelC')
What I want to do is to get the properties of every attribute, not just the name that I got with :
my_instance._meta.get_all_field_name()
(which gave me a list of attributes names). No, what I want is, for every attribute, know what is his type (CharField,IntegerField, ForeignKey, ManyToManyField...), who's related if it's a ForeignKey / ManyToManyField and all the meta data such as max_length and so on.
The aim of it is to serialize a class into a XML and the representation in the XML will be different if it's a ManyToManyField, a ForeignKey or a simple value.
By the way, If anyone know a great class serializer to XML, it would help me a lot !
Thanks for your responses !
Django models _meta.fields is fields list that you can access to get field attributes:
>>> from django.contrib.auth.models import User
>>> u = User.objects.all()[0]
>>> u._meta.fields[1].__class__.__name__
'CharField'
>>> u._meta.fields[1].name
'username'
>>> u._meta.fields[1].max_length
30
>>> u._meta.fields[1].blank
False
# ...
You can get attributes of a specific field by using get_field()
MyClass._meta.get_field('attributeA').max_length

How can I store an array of strings in a Django model?

I am building a Django data model and I want to be able to store an array of strings in one of the variables; how can I do that?
e.g.
class myClass(models.Model):
title = models.CharField(max_length=50)
stringArr = models.???
Thanks for the help.
You can use some serialization mechanism like JSON. There's a snippet with field definition that could be of some use to you:
http://djangosnippets.org/snippets/1478/ (take a look at the code in the last comment)
With such field you can seamlessly put strings into a list and assign them to such field. The field abstraction will do the rest. The same with reading.
If you are using PostgreSQL or MongoDB(with djongo) you can do this
For PostgreSQL:
from django.contrib.postgres.fields import ArrayField
For MongoDB(with Djongo):
from djongo import models
from django.contrib.postgres.fields import ArrayField
Then
stringArr = ArrayField(models.CharField(max_length=10, blank=True),size=8)
The above works in both cases.
Make another model that holds a string with an optional order, give it a ForeignKey back to myClass, and store your array in there.
I did this for my model and it worked
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Skill(models.Model):
name = models.CharField(max_length=50)
skills = ArrayField(models.CharField(max_length=200), blank=True)
To create
Skill.objects.create(name='First name', skills=['thoughts', 'django'])
To Query
Skill.objects.filter(skills__contains=['thoughts'])
You can refer to the django documentation for more help
https://docs.djangoproject.com/en/3.0/ref/contrib/postgres/fields/
I hope this helps
You can use cPickle...
class myClass(models.Model):
title = models.CharField(max_length=50)
stringArr = models.TextField()
from cPickle import loads, dumps
data = [ { 'a':'A', 'b':2, 'c':3.0 } ]
obj = Myclass.objects.get(pk=???)
# pickle data into a string-like format
obj.stringArr = dumps(data)
obj.save()
# restore original data
data = loads(obj.stringArr)
You can use JSONField for such functionality:
from django.db import models
from django.contrib.postgres.fields import JSONField
class TestModel(models.Model):
title = models.CharField(max_length=100)
strings = JSONField(default=list, blank=True, null=True)
def __str__(self):
return self.title
for example:
In [1]: fruits = ['banana', 'apple', 'orange']
In [2]: TestModel.objects.create(title='my set', strings=fruits)
Out[2]: <TestModel: my set>
In [3]: o = TestModel.objects.first()
In [4]: o.strings
Out[4]: ['banana', 'apple', 'orange']

Categories