Django model field by variable - python

Quick question. I'm trying yo access one of the fields of a model using a variable.
class ExampleModel(models.Model):
the_field = models.CharField()
the_field_two = models.CharField()
How would access the field dynamically? I tried:
model = ExampleModel.objects.get(pk=1)
fieldtoget = 'the_field'
test_var = model[fieldtoget]
But it doesn't seem to work, any ideas how I would do this?
Update: Thought I'd update my question. I'm trying to write a function (as part of larger function) that can not only get the value of the field but also update it from a variable fieldname. For example:
model[fieldtoget] = 'yo'
model.save()
In PHP you can use the {} wrapper - $model{$fieldtoget} - as an example, for dynamic variable names was hoping there was something similar in python :)
Cheers

You can use pythons getattr function to do this. Pass the field name in as the attribute.
getattr(model, fieldtoget)
Since fieldtoget is a variable, this is dynamic.
You can use setattr to set it the same way.

Related

How to get a name of the class from class declaration

I have a next model
class MyClass(models.Model):
# fields
When I try to get __class__ it returns 'ModelBase'.
What I actually need is to find a method of how to get a class name for models.MyClass.
Is it possible without having an instance of it?
Updated:
Sorry guys, I put it wrong, what I wanted to ask was a bit different. I am probably to tired.
This questions actually duplicates:
Get class name of django model
MyClass.__name__ should return the name of the class as a string.
.__name__ in general is the best way to get variables and functions names.
Try MyClass.__name__.
Django models are derived from the ModelBase, which is the Metaclass for all models.

Get Attribute type of a model in Django

Folks, I'm trying to get the type of the Model's attribute. For example, consider the following model below:
class Option(models.Model):
option_text = models.CharField(max_length=400)
option_num = models.IntegerField()
# add field to hold image or a image url in future
def __unicode__(self):
return self.option_text
I'm setting each of the attribute of this model programmatically. I need to access the type of the attribute. For example, for option_num, I should be able to get "IntegerField" or an equivalent.
I saw the meta api, and read the source, too. But I don't see a way to retrieve the internal type.
model._meta.get_field(attr_value).getInternalType() => gives me an error.
Getting an "'CharField' object has no attribute 'get Internal Type'".
To clarify a little, the reason I need to know whether an attribute is a string or an int is because, if from the front end, I get a string, which is actually an integer, i would like to typecast it.
Help?
Thanks!
you are close with the meta option but you need to remember some Python PEP8 Love.
if you have a model like this:
class Client(models.Model):
code = models.IntegerField()
name = models.CharField(max_length=96)
...
...
you can get the type name with:
Client._meta.get_field('code').get_internal_type()
u'IntegerField'
or you can get the type with:
type(Client._meta.get_field('name'))
django.db.models.fields.CharField
directly like a Class method, not only from the class instance.
your choice.
The point is use
model._meta.get_field(attr_name).get_internal_type()
instead of
model._meta.get_field(attr_value).getInternalType()

How to define a django model field with the same name as a Python keyword

I need to define a Django model field with the name in, which is a Python language keyword. This is a syntax error:
class MyModel(models.Model):
in = jsonfield.JSONField()
How can I make this work?
The reason I need this name is when I use django-rest-framework's ModelSerializer class, field name is used as the key for serialization output, and I thought it might be easier to manipulate django's Model class instead of ModelSerializer class to get the output I want.
Generally speaking, you don't. Avoid the use of keywords in your identifiers. The general Python convention is to add an underscore to such names; here that'd be in_:
class MyModel(models.Model):
in_ = jsonfield.JSONField()
However, Django prohibits names ending in an underscore because the underscore clashes with their filter naming conventions, so you have to come up with a different name still; pick one that still describes your case; I picked contained in rather than in, as a guess to what you want to do here:
class MyModel(models.Model):
contained_in = jsonfield.JSONField()
If you are trying to match an existing database schema, use the db_column attribute:
class MyModel(models.Model):
contained_in = jsonfield.JSONField(db_column='in')
If you want to be stubborn, in normal classes you could use setattr() after creating the class to use a string instead of an identifier:
class Foo:
pass
setattr(Foo, 'in', 'some value')
but you'll have to use setattr(), getattr(), delattr() and/or vars() everywhere in your code to be able to access this.
In Django you'll have the added complication that a models.Model subclass uses a metaclass to parse out your class members into others structures, and adding an extra field with setattr() doesn't work without (a lot of) extra work to re-do what the metaclass does. You could instead use the field.contribute_to() method, calling it after the class has been prepared by Django (technique taken from this blog post):
from django.db.models.signals import class_prepared
def add_field(sender, **kwargs):
if sender.__name__ == "MyModel":
field = jsonfield.JSONField('in')
field.contribute_to_class(sender, 'in')
class_prepared.connect(add_field)
but you have to make sure this hook is registered before you create your model class.
There is no way to make it work, and it's a bad idea anyway. Choose a different name.
If, for some reason, you want to have column name that matches some reserved keyword, use db_column argument for that field.
in_something = models.CharField(db_column='in', max_length=100)
You mentioned the use of django rest framework. Here's how to make it work on the serializer layer. The keyword used is from. to is just an example of a non-keyword if you want it mapped to a different name.
from django.db import models
from rest_framework import serializers
SP_FIELD_MAP = {
'from': 'sender'
}
# would be in models.py
class Transaction(models.Model):
recipient = models.CharField(max_length=16)
sender = models.CharField(max_length=64)
# would be in serializers.py
class TransactionSerializer(serializers.ModelSerializer):
to = serializers.CharField(source='recipient')
class Meta:
model = Transaction
fields = ('id', 'to', 'from')
# `from` is a python keyword hence this
extra_kwargs = {'from': {'source': 'sender'}}
def build_field(self, field_name, info, model_class, nested_depth):
# Catches python keywords like `from` and maps to its proper field
field_name = SP_FIELD_MAP.get(field_name, field_name)
return super(TransactionSerializer, self).build_field(
field_name, info, model_class, nested_depth)
Tested on CharField using POST and GET methods only but I don't see how it won't work on other methods. You might need special stuff for other field types though. I suggest going into the source. There's tons of fun stuff going on in DRF's source.
You should be giving all your variables descriptive names that clearly state what they are to be used for, and where possible it should be easy to assertain what type of variable it is.
in, to me, would appear at first glance to be a boolean so in order to use this variable in my own extension to the code I'd need to find other usages of it before I knew how I could use it.
Therefore, simply don't try to hack something together just so you can get this terrible variable name into your model, it offers no value to you to do so, its not really any quicker to type since intellisense is available in most places. Figure out what "in" relates to and then formulate a proper name that is descriptive.

Ways of defining a field in Django form

I am defining a field in a django form in the following two ways :
class MyForm(forms.Form):
myfield = forms.ChoiceField(choices=[(u.id,u.username) for u in User.objects.filter(type="TYPE1")])
OR
class MyForm(forms.Form):
pass
def_init_(self,*args,**kwargs):
super(MyForm,self)._init_(*args,**kwargs)
self.fields['myfield'] = forms.ChoiceField(choices=[(u.id,u.username) for u in User.objects.filter(type="TYPE1")])
Is there any different between these two approaches?? I tried to find this on web but did not get any relevant answers.
First of all, there is a special field to handle such things - ModelChoiceField
In your example the difference is the moment when code is executed.
In first approach it is executed when module with form is loaded, in second - every time the form is initialized (so basically on each request to your view). So first approach has a problem - Users will be loaded on first request. If any user registers after this moment - he will not be present in the select field until you restart the server.
Also I think it is a bad practice to introduce new field in __init__ method. If you really need something like this and you can't use ModelChoiceField the better way is
class MyForm(forms.Form):
myfield = forms.ChoiceField()
def __init__(self,*args,**kwargs):
super(MyForm,self).__init__(*args,**kwargs)
self.fields['myfield'].choices = [(u.id, u.username) for u in User.objects.filter(type="TYPE1")]
Don't you get an error when you run your server using the first way?
class MyForm(forms.Form):
myfield = forms.ChoiceField(choices=[(u.id,u.username) for u in User.objects.filter(type="TYPE1")])
If you use this method That for will be executed when the file is being read. Try using the second way or a function to execute that for and set the choices.
Usually in Form.__init__ you define some dynamic fields (for example, you want to show some checkboxes, which are set/unset according to the data from some model). In all other cases first approach is better because it's more readable.

Figure out child type with Django MTI or specify type as field?

I'm setting up a data model in django using multiple-table inheritance (MTI) like this:
class Metric(models.Model):
account = models.ForeignKey(Account)
date = models.DateField()
value = models.FloatField()
calculation_in_progress = models.BooleanField()
type = models.CharField( max_length=20, choices= METRIC_TYPES ) # Appropriate?
def calculate(self):
# default calculation...
class WebMetric(Metric):
url = models.URLField()
def calculate(self):
# web-specific calculation...
class TextMetric(Metric):
text = models.TextField()
def calculate(self):
# text-specific calculation...
My instinct is to put a 'type' field in the base class as shown here, so I can tell which sub-class any Metric object belongs to. It would be a bit of a hassle to keep this up to date all the time, but possible. But do I need to do this? Is there some way that django handles this automatically?
When I call Metric.objects.all() every objects returned is an instance of Metric never the subclasses. So if I call .calculate() I never get the sub-class's behavior.
I could write a function on the base class that tests to see if I can cast it to any of the sub-types like:
def determine_subtype(self):
try:
self.webmetric
return WebMetric
except WebMetric.DoesNotExist:
pass
# Repeat for every sub-class
but this seems like a bunch of repetitious code. And it's also not something that can be included in a SELECT filter -- only works in python-space.
What's the best way to handle this?
While it might offend some people's sensibilities, the only practical way to solve this problem is to put either a field or a method in the base class which says what kind of object each record really is. The problem with the method you describe is that it requires a separate database query for every type of subclass, for each object you're dealing with. This could get extremely slow when working with large querysets. A better way is to use a ForeignKey to the django Content Type class.
#Carl Meyer wrote a good solution here: How do I access the child classes of an object in django without knowing the name of the child class?
Single Table Inheritance could help alleviate this issue, depending on how it gets implemented. But for now Django does not support it: Single Table Inheritance in Django so it's not a helpful suggestion.
But do I need to do this?
Never. Never. Never.
Is there some way that django handles this automatically?
Yes. It's called "polymorphism".
You never need to know the subclass. Never.
"What about my WebMetric.url and my TextMetric.text attributes?"
What will you do with these attributes? Define a method function that does something. Implement different versions in WebMetric (that uses url) and TextMetric (that uses text).
That's proper polymorphism.
Please read this: http://docs.djangoproject.com/en/1.2/topics/db/models/#abstract-base-classes
Please make your superclass abstract.
Do NOT do this: http://docs.djangoproject.com/en/1.2/topics/db/models/#multi-table-inheritance
You want "single-table inheritance".

Categories

Resources