My higher level goal is to have a polymorphic association between models and I think I can solve it with a model with this signature:
class Relation(models.Model):
left = ForeignKey(Entity)
right = ForeignKey(Entity)
class Meta:
db_table = 'entities'
then I can extend Relation as proxy so I can be more clear on my intention of left and right field, for ex:
class Authorship(Relation)
author = AliasField('left')
content = AliasField('right')
class Meta:
proxy = True
So then we can do the following:
Authorship.objects.filter(author=user_entity)
or
Authorship.objects.create(author=user_entity)
My question is, how do I implement AliasField function described above?
I have looked at:
https://shezadkhan.com/aliasing-fields-in-django/
How to create an alias for Django Model field?
for the first link, I am getting error about name is not a field or something
for the second one, I am getting an error saying "can't adapt type"
is this even possible to do in Django 2.0?
I prefer not to use django-polymorphic
Thank you!
Related
Within the Django Rest framework documentation it is suggested to declare the "field" list explicitly to avoid providing the data of new columns just by adding them to the model which may contain sensitive information.
The field list is an array of strings, containing the field ids. To avoid declaring field ids, which actually do not exist in the model (e.g. typos or changed models) I tried to declare the list using object references - but always end up with "DeferredAttribute: object has no attribute ".
I have read something that meta information is not available in objects and that you could solve that by defininig your own Meta class using Object._meta.get_fields() and store it in the class, but I thought there might be a simpler/more elegant way (and I do now know, how, in detail ;-)).
Example:
class Samples(models.Model):
# Meta data, primarily used in AdminSite.
class Meta:
verbose_name = _('Samples')
verbose_name_plural = _('Samples')
samples_boolfield = models.BooleanField
samples_textfield = models.CharField(max_length=2000, blank=True)
views.py:
class SamplesView(viewsets.ModelViewSet):
serializer_class = SamplesSerializer
queryset = Samples.objects.all()
serializers.py:
Version 1, which does not show any errors in pyCharm or makemigrations, but calling the API reults in "TypeError at /api/samples/: argument of type 'DeferredAttribute' is not iterable":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield,
Samples.samples_textfield,
)
Version 2, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute name":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.__name__,
Samples.samples_textfield.__name__,
)
Version 3, which does not show any errors in pyCharm, but makemigrations fails with "DeferredAttribute: object has no attribute get_attname":
class SamplesSerializer(serializers.ModelSerializer):
class Meta:
model = Samples
fields = (
'id',
Samples.samples_boolfield.get_attname(),
Samples.samples_textfield.get_attname(),
)
Is there a way to declare the field list using object references (so that it fails e.g. in pyCharm/during compilation)?
Thank you for your feedback.
Regards,
HerrB92
So, after adding or removing a GenericRelation to one of my model classes nothing happens.
I try to makemigrations and it tells me no changes were detected. So there must be something wrong, because it should be hitting the database and try to apply some changes.
I followed Django example and I can't make the relationship work.
class Person(models.Model):
identity = models.CharField(max_length=13, verbose_name="ID")
name = models.CharField(max_length=255, verbose_name="Name")
board = GenericRelation('second_app.BoardMember') #Second Try
def __unicode__(self):
return self.identity
class Meta:
verbose_name = "Person"
verbose_name_plural = "People"
class Student(Person):
class Meta:
proxy = True
class Parent(Person):
class Meta:
proxy = True
class Teacher(Person):
board = GenericRelation('second_app.BoardMember') # first try
class Meta:
proxy = True
On a different app I have the following model.
class BoardMember(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id', for_concrete_model=False)
responsabilities = models.CharField(max_length=255)
At first I tried setting the Generic Relation on a proxy model. Nothing happened, then I tried setting it on the main Person class. Nothing. This is what I did to test the relation on the shell.
>>>from first_app.models import Teacher
>>>from second_app.models import BoardMember
>>>teacher = Teacher(identity='123456', name='Fermin Arellano')
>>>teacher.save()
>>>bm = Boardmember(content_object=teacher,responsabilities='Check stuff')
>>>bm.save()
>>>teacher.board.all()
[]
Following this example: https://docs.djangoproject.com/en/1.8/ref/contrib/contenttypes/#reverse-generic-relations
The expected result should be: [<Teacher: 123456>]
Am I doing something wrong? There are no errors showing anywhere. Data is saved properly, both the Teacher and BoardMemer objects were created successfully in my database.
I just removed for_concrete_model=False from the GenericForeignKey declaration. Although on Django´s documentation it clearly states that it has to be setted to false in order to use ProxyModels.
Everythings is working fine now.
EDIT.
I just realized that the problem persists. After further investigation I noticed that in order to get the generic relation to work I need to save the content_type_id of the Person model, and not the proxy one. That is why deleting the for_concrete_model parameter helped, because this way I told Django to use the parents content type, and there it worked fine. Funny thing is that if I do the following the relations still works eventhough I have the content_type_id of Person.
Teacher.objects.filter(board__isnull=False)
This returns all the teachers who are in the board.
This is really confusing, if you can shed some light on this mess I'll be very thankful.
I am trying to open django admin for the following models..
class FirstModel(models.Model):
name = models.CharField(max_length=100)
class SecondModel(models.Model):
name = models.CharField(max_length=100)
firstModel = models.ForeignKey(FirstModel, related_name='secondList')
class ThirdModel(models.Model):
name = models.CharField(max_length=100)
secondModel = models.ForeignKey(SecondModel, related_name='thirdList')
I am trying to create an admin.py for the following models as follows..
class ThirdModelInline(admin.TabularInline):
model = ThirdModel
extra = 1
class SecondModelInline(admin.StackedInline):
model = SecondModel
inlines = [ThirdModelInline]
class FirstModelAdmin(admin.ModelAdmin):
inlines = [SecondModelInline]
admin.site.register(FirstModel, FirstModelAdmin)
I want to be able to edit the SecondModel and ThirdModel as a recursive relation inside FirstModel. But this is not working. I tried to follow this link : [Model with recursive self relation in Django's admin
[1]: Model with recursive self relation in Django's admin. Any help would be appreciated. Thanks!!
Found a very good library after some websearch. Might help someone else..
https://github.com/s-block/django-nested-inline
django-nested-inline isn't (yet?) supported on latest django releases.
But you could consider using django-nested-admin that is almost the same.
In my Django app, I have the following Models:
class MyModelA(models.Model):
myAttributeA = models.CharField(max_length=255)
class MyModelB(models.Model):
myParent = models.OneToOneField(myModelA)
myAttributeB = models.CharField(max_length=255)
My settings.py has the following Rest Permission settings:
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
I also have the following Serializers:
class MyModelASerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModelA
fields = ('myAttributeA',)
class MyModelBSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModelB
fields = ('myParent', 'myAttributeB',)
Now I want to write a simple Django-Rest-Framework API that will allow any user (weather authenticated or not) to retrieve the value of myParent on any instance of MyModelB assuming they have the Primary Key of the MyModelB instance. This should be rather simple. I'm not trying to update, create, or delete anything. I just want to retrieve the value of one attribute of the instance. But I also want my urls.py to match this endpoint to the API:
url(r'^api/AttrMyModelA/(?P<myModelAID>\d+)/?$', SOMETHING HERE. NOT SURE WHAT)
However, I cannot figure out which pattern to use from the tutorial to make this work. Should I use function based or class based views? Should I use Generic API views? Do I need a decorator or no? Mixins? Can someone please show me what my view should look like and what the urls.py endpoint should look like?
Thanks
You require a RetrieveAPIView-derived class to tie things together:
class MyModelAView(RetrieveAPIView):
model = MyModelA
serializer_class = MyModelASerializer
The route mentioned by you would then look like this:
url(r'^api/AttrMyModelA/(?P<pk>\d+)/?$', MyModelAView.as_view())
Note that pk is the default look-up field used by APIView-derived classes when performing single object queries.
You have defined a default permission class (in settings.py), so unless you want to override that you don't need to specify a permission_classes value in your view class.
from the documentation:
read_only
Set this to True to ensure that the field is used when serializing a representation, but is not used when updating an instance during deserialization.
Defaults to False
required
Normally an error will be raised if a field is not supplied during deserialization. Set to false if this field is not required to be present during deserialization.
Defaults to True.
So I have a model which has a field that's not nullable but I want it to be populated in the pre_save method, so I have set the field to required=False in serializer, but doesn't seem to work. I am still getting error when saving the record.
class FavoriteListSerializer(serializers.ModelSerializer):
owner = serializers.IntegerField(required=False)
class Meta:
model = models.FavoriteList
Update:
I have added serializer_class = serializers.FavoriteListSerializer to the ViewSet, now instead of getting This field is required, which I think got past the validation but then I am getting This field cannot be null. I have checked the pre_save method is not being executed, any ideas?
Yeah, I ran into this issue at some point as well. You need to also update the validation exclusions.
class FavoriteListSerializer(serializers.ModelSerializer):
owner = serializers.IntegerField(required=False)
class Meta:
model = models.FavoriteList
def get_validation_exclusions(self):
exclusions = super(FavoriteListSerializer, self).get_validation_exclusions()
return exclusions + ['owner']
Late Entry to this thread. This issue was fixed in django-rest-framework 2.3.13. Here is the link of the PR.
You use it like this in your case:
class Meta:
model = models.FavoriteList
optional_fields = ['owner', ]
In case somebody lands here with a similar issue, pay attention to the following attributes along with required:
allow_blank:
If set to True then the empty string should be considered a valid value.
allow_null:
Normally an error will be raised if None is passed to a serializer field.
required:
Normally an error will be raised if a field is not supplied during deserialization.
I was straggling to figure out why I was getting a validation error with required=False where I had missed the allow_null attribute.
In 2020, for DRF 3.12.x, the approach that I prefer the approach that relies on
Serializer's extra_kwargs.
So assuming your
class FavoriteListSerializer(serializers.ModelSerializer):
owner = serializers.IntegerField(required=False)
class Meta:
model = models.FavoriteList
fields = ["owner"] # and whatever other fields you want to expose
extra_kwargs = {"owner": {"required": False, "allow_null": True}}
If you have unique_together constraint on one of the fields you are trying to set required=False you need to set validators=[] in serializers Meta like
class FavoriteListSerializer(serializers.ModelSerializer):
owner = serializers.IntegerField(required=False)
class Meta:
model = models.FavoriteList
validators = []
Here is the original answer
You can also do this:
class ASerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
...
As referred here: https://www.django-rest-framework.org/api-guide/validators/#advanced-field-defaults
There you can also find the case when you also wanna let the view show owner
I would set model field to allow null value (and possible also default to None)
class FavoriteList(models.Model):
owner = models.PositiveIntegerField(null=True, default=None)
Then it's possible to just leave owner field to Meta section. These fields, without any extra settings, will automatically get all attributes from model field and be non-required.
class FavoriteListSerializer(serializers.ModelSerializer):
class Meta:
model = models.FavoriteList
fields = ('owner',)