What I need is returning all the parameters from field :
Example :
Class MyClass(models.Model):
field = models.Charfield(blank = True, null = True)
I want to return all the parameters of "field" from "MyClass".
Here, it should be the parameters blank and null.
For a model MyModel
class MyModel(models.Model):
my_field = models.Charfield(max_length=100)
You can get the field using the Meta api.
>>> field = MyModel._meta.get_field('my_field')
You can then use the deconstruct method to get the kwargs that were passed to the field when it was instantiated.
>>> name, path, args, kwargs = field.deconstruct()
>>> print(kwargs)
{u'max_length': 100}
I did not really get the purpose of getting the parameters, but I think you can use 'vars'. It's kind of wrap for '__dict__'.
As django model fields have '__dict__' attribute, 'vars' will give you access to the field's parameters as follow:
def has_parameter(field_name, parameter_name):
parameter_dict = vars(field_name)
return not parameter_dict.get(parameter_name) == None
if equal to None means it's not set yet otherwise it's set or has a default value.
in you case: >>> has_parameter(field_name,'through')
Related
I have class, where I try to set student_id as _id field in elasticsearch. I am referring persistent example from elasticsearch-dsl docs.
from elasticsearch_dsl import DocType, String
ELASTICSEARCH_INDEX = 'student_index'
class StudentDoc(DocType):
'''
Define mapping for Student type
'''
student_id = String(required=True)
name = String(null_value='')
class Meta:
# id = student_id
index = ELASTICSEARCH_INDEX
I tied by setting id in Meta but it not works.
I get solution as override save method and I achieve this
def save(self, **kwargs):
'''
Override to set metadata id
'''
self.meta.id = self.student_id
return super(StudentDoc, self).save(**kwargs)
I am creating this object as
>>> a = StudentDoc(student_id=1, tags=['test'])
>>> a.save()
Is there any direct way to set from Meta without override save method ?
There are a few ways to assign an id:
You can do it like this
a = StudentDoc(meta={'id':1}, student_id=1, tags=['test'])
a.save()
Like this:
a = StudentDoc(student_id=1, tags=['test'])
a.meta.id = 1
a.save()
Also note that before ES 1.5, one was able to specify a field to use as the document _id (in your case, it could have been student_id), but this has been deprecated in 1.5 and from then onwards you must explicitly provide an ID or let ES pick one for you.
I have tried to add a key serializer.data['test'] = 'asdf', this does not appear to do anything.
I want to transform the representation of a key's value. To do this, I'm trying to use the value to calculate a new value and replace the old one in the dictionary.
This is what I want to accomplish, but I don't know why the value is not being replaced. There are no errors thrown, and the resulting dictionary has no evidence that I've tried to replace anything:
class PlaceDetail(APIView):
def get(self, request, pk, format=None):
place = Place.objects.select_related().get(pk=pk)
serializer = PlaceSerializer(place)
#serializer.data['tags'] = pivot_tags(serializer.data['tags'])
serializer.data['test'] = 'asdf'
print(serializer.data['test'])
return Response(serializer.data)
Terminal: KeyError: 'test'
I have observed by printing that serializer.data is a dictionary.
I have also tested that the syntax I'm trying to use should work:
>>> test = {'a': 'Alpha'}
>>> test
{'a': 'Alpha'}
>>> test['a']
'Alpha'
>>> test['a'] = 'asdf'
>>> test
{'a': 'asdf'}
How can I properly modify the serializer.data dictionary?
The Serializer.data property returns an OrderedDict which is constructed using serializer._data. The return value is not serializer._data itself.
Thus changing the return value of serializer.data does not change serializer._data member. As a consequence, the following calls to serializer.data are not changed.
# In class Serializer(BaseSerializer)
#property
def data(self):
ret = super(Serializer, self).data
return ReturnDict(ret, serializer=self)
# In class ReturnDict(OrderedDict)
def __init__(self, *args, **kwargs):
self.serializer = kwargs.pop('serializer')
super(ReturnDict, self).__init__(*args, **kwargs)
You can keep a copy of the return value of serializer.data, which is an ordered dictionary, and manipulate it as you wish.
Example:
# keep the return value of serializer.data
serialized_data = serializer.data
# Manipulate it as you wish
serialized_data['test'] = 'I am cute'
# Return the manipulated dict
return Response(serialized_data)
Why:
If you look at the source code of Django Restframework, you will see that in Serializer class,
Serializer._data is just a normal dictionary.
Serializer.data is a method decorated to act like a property. It returns a ReturnDict object, which is a customized class derived from OrderedDict. The returned ReturnDict object is initialized using key/value pairs in Serializer._data.
If Serializer.data returns Serializer._data directly, then your original method will work as you expected. But it won't work since it's returning another dictionary-like object constructed using Serializer._data.
Just keep in mind that the return value of Serializer.data is not Serializer._data, but an ordered dictionary-like object. Manipulating the return value does not change Serializer._data.
I believe the reason why serializer.data does not return serializer._data directly is to avoid accidental change of the data and to return a pretty representation of serializer._data.
You'll want to use SerializerMethodField instead of explicitly overwrite the representations.
Building further on #yuwang's answer, I used SerializerMethodField to modify value of a particular field in the serializer. Here's an example:
The field that I wanted to modify, let us call it is_modifyable. This field is present on the Django Model as models.BooleanField and hence it was not present in the list of fields on serializer definition and simply mentioned in the class Meta: definition under within the serializer definition.
So here's how my code looked before:
# in models.py
# Model definition
class SomeModel(models.Model):
is_modifyable = models.BooleanField(default=True)
# in serializers.py
# Serializer definition
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = ('is_modifyable',)
As a result of the above, the value for the field is_modifyable was always fetched on the basis of what the value was in the record of SomeModel object. However, for some testing purpose, I wanted the value of this field to be returned as False during the development phase, hence I modified the code to be as follows:
# in models.py
# Model definition (Left unchanged)
class SomeModel(models.Model):
is_modifyable = models.BooleanField(default=True)
# in serializers.py
# Serializer definition (This was updated)
class SomeModelSerializer(serializers.ModelSerializer):
# This line was added new
is_modifyable = serializers.SerializerMethodField(read_only=True)
class Meta:
model = SomeModel
fields = ('is_modifyable',)
# get_is_modifyable function was added new
def get_is_modifyable(self, obj) -> bool:
"""
Dummy method to always return False for test purpose
Returns: False
"""
return False
Once the above code was in, the API call always returned the value of serializer field is_modifyable as False.
So I have a Django serializer and I am trying to get a certain output, but failing at it. Here's the serializer:
class MedTestsGetSerializer(serializers.ModelSerializer):
test_type = MedTestsTypeNameSerializer(source='medteststypetest_id')
class Meta:
model = MedTests
fields = ('medtests_id',
'test_type',)
def to_representation(self, value):
return '%s: %s' % (value.medtests_id, value.test_type)
Now theoretically, this should give me the output {"uuid-goes-here-right-now": "test type name"}, but it doesn't (and that's not even the final version of what I want).
It throws an error that says 'MedTests' object has no attribute 'test_type'
Now my ultimate goal is to be in this form:
{"uuid-goes-here-right-now":{"test_type":"test name"}}
But I can't figure it out. How can I control the output to put a dict as a value to a uuid key, with the inner dict having a label as a key, and the inner dict having the value as the field. So basically this:
{VALUE OF MEDTESTS_ID: {"test_type": VALUE OF TEST_TYPE}}
As an FYI, MedTestsTypeNameSerializer just returns a string.
First of all: I am not able to find out the proper Title of this question.
Anyhow the question is:
I have to fill a form at template and the fields of this form are user dependent. For example you passes integer (integer is not a datatype) as a parameter to the method and it should returns like this:
fileds = forms.IntegerField()
If you pass bool then it should like this:
fields = forms.BooleanField()
So that i can use them to create my form. I tried with this code but it returns into the form of string.
Some.py file:
choices = (('bool','BooleanField()'),
('integer','IntegerField()'))
def choose_field():
option = 'bool' # Here it is hardcoded but in my app it comes from database.
for x in choices:
if x[0]==option:
type = x[1]
a = 'forms'
field = [a,type]
field = ".".join(field)
return field
When i print the field it prints 'forms.BooleanField()'. I also use this return value but it didn't work. Amy solution to this problem?
The simpliest way is to create your form class and include fields for all possible choices to it. Then write a constructor in this class and hide the fields you don't want to appear. The constructor must take a parameter indicating which fields do we need. It can be useful to store this parameter in the form and use it in clean method to correct collected data accordingly to this parameter.
class Your_form(forms.ModelForm):
field_integer = forms.IntegerField()
field_boolean = forms.BooleanField()
def __init__(self, *args, **kwargs):
option = kwargs["option"]
if option == "integer":
field_boolean.widget = field_boolean.hidden_widget()
else:
field_integer.widget = field_integer.hidden_widget()
super(Your_form, self).__init__(*args, **kwargs)
In your controller:
option = 'bool'
form = Your_form(option=option)
Apart from one example in the docs, I can't find any documentation on how exactly django chooses the name with which one can access the child object from the parent object. In their example, they do the following:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __unicode__(self):
return u"%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
def __unicode__(self):
return u"%s the restaurant" % self.place.name
# Create a couple of Places.
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
# Create a Restaurant. Pass the ID of the "parent" object as this object's ID.
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
# A Restaurant can access its place.
>>> r.place
<Place: Demon Dogs the place>
# A Place can access its restaurant, if available.
>>> p1.restaurant
So in their example, they simply call p1.restaurant without explicitly defining that name. Django assumes the name starts with lowercase. What happens if the object name has more than one word, like FancyRestaurant?
Side note: I'm trying to extend the User object in this way. Might that be the problem?
If you define a custom related_name then it will use that, otherwise it will lowercase the entire model name (in your example .fancyrestaurant). See the else block in django.db.models.related code:
def get_accessor_name(self):
# This method encapsulates the logic that decides what name to give an
# accessor descriptor that retrieves related many-to-one or
# many-to-many objects. It uses the lower-cased object_name + "_set",
# but this can be overridden with the "related_name" option.
if self.field.rel.multiple:
# If this is a symmetrical m2m relation on self, there is no reverse accessor.
if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
return None
return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
else:
return self.field.rel.related_name or (self.opts.object_name.lower())
And here's how the OneToOneField calls it:
class OneToOneField(ForeignKey):
... snip ...
def contribute_to_related_class(self, cls, related):
setattr(cls, related.get_accessor_name(),
SingleRelatedObjectDescriptor(related))
The opts.object_name (referenced in the django.db.models.related.get_accessor_name) defaults to cls.__name__.
As for
Side note: I'm trying to extend the
User object in this way. Might that be
the problem?
No it won't, the User model is just a regular django model. Just watch out for related_name collisions.