Django model derived class - python

i' ve a django model with some fields and methods like this:
class Follow(models.Model):
fields = ...
def methods(self, ...):
...
. I' d like to create another model with the same fields and methods, however in this new model i' d like to have new fields and methods as well, like this:
class Auto(Follow):
additionalfields = ...
def additionalmethods(self, ...):
...
, but in this case the problem is that if i create an Auto object, it' ll appear in the Follow.objects.filter() QuerySet as well. How could i workaround it? An idea was to specify an is_auto = models.BooleanField(default = ?) field in both of the models with relevant value, but that fails during the schemamigration:
django.core.exceptions.FieldError: Local field 'autob' in class 'Auto' clashes
with field of similar name from base class 'Follow'
. Any idea how to workaround it?

class BaseItem(models.Model):
#fields and methods
class Follow(BaseItem):
pass
class Auto(BaseItem):
#additional fields

Related

Define an arbitrary Field on a django-rest-framework Serializer that doesn't exist on the Django Model

I'd want to define an arbitrary Field on a django-rest-framework Serializer that doesn't exist on the Django Model.
My code looks like so:
class Person(models.Model):
pass
class PersonSerializer(serializers.ModelSerializer):
foo = serializers.CharField()
class Meta:
model = Person
fields = ('id', 'foo')
class PersonViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = PersonSerializer
This code fails with:
AttributeError: Got AttributeError when attempting to get a value for field `key` on serializer `PersonSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Person` instance.
Original exception text was: 'Person' object has no attribute 'key'.
But... If I adjust the Person class to this:
class Person(models.Model):
def foo(self):
pass
Then I don't get the error, and I can POST the data.
I don't like the idea of creating a dummy method on the Person class to get around this error. Is there a django-rest-framework way to alleviate this error that I missed?
You could do it like this, using a SerializerMethodField:
class PersonSerializer(serializers.ModelSerializer):
foo = serializers.SerializerMethodField()
...
def get_foo(self, obj):
return 'the foo'
Then the logic about how to serialize the additional field just lives on the serializer itself, however it does have access to the instance, if required, through obj.

How can i remove extra "s" from django admin panel?

I am really very much irritated by the extra "s" added after my class name in django admin eg class 'About' in my model.py becomes 'Abouts' in admin section. And i want it not to add extra 's'. Here is my model.py file-
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
Please anybody suggest me how django can solve my problem.
You can add another class called Meta in your model to specify plural display name. For example, if the model's name is Category, the admin displays Categorys, but by adding the Meta class, we can change it to Categories.
I have changed your code to fix the issue:
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
class Meta:
verbose_name_plural = "about"
For more Meta options, refer to https://docs.djangoproject.com/en/1.8/ref/models/options/
Take a look at the Model Meta in the django documentation.
Within a Model you can add class Meta this allows additional options for your model which handles things like singular and plural naming.
This can be used in the following way (in english we do not have sheeps) so verbose_name_plural can be used to override djangos attempt at pluralising words:
class Sheep(model.Model):
class Meta:
verbose_name_plural = 'Sheep'
inside model.py or inside your customized model file add class meta within a Model Class.
If not mentioned then a extra 's' will be added at the end of Model Class Name which will be visible in Django Admin Page.
class TestRoles(model.Model):
class Meta: verbose_name_plural = 'TestRoles'

Same Options For Different Django Admin Class

This should evident but I dont know how to do it.
How do I Apply the same options for instance a exclude for different model and different admin class
-- admin.py
class Tabla1(admin.ModelAdmin):
exclude('tenant')
...
class Tabla2(admin.ModelAdmin):
exclude('tenant')
...
class Tabla3(admin.ModelAdmin):
exclude('tenant')
...
That I want is exclude the same tenant field in the tables. I have the same field in several tables. In fact I have several actions(same actions) to do for the different admin models.
Just make a base admin class that you can inherit from:
class TablaBaseAdmin(admin.ModelAdmin):
class Meta:
exclude = ('tenant',)
class Tabla1Admin(TablaBaseAdmin):
pass
class Tabla2Admin(TablaBaseAdmin):
pass
class Tabla3Admin(TablaBaseAdmin):
pass

Standard way to pull a specific model from a common view in Django/DRF?

I currently have two models that are essentially the same (inheriting from a base model), but I have problems referring to them from a common view:
Models:
class BaseModel(models.Model):
name = models.CharField(...)
owner = ForeignKey(...)
class Cat(BaseModel):
...
class Dog(BaseModel):
...
View:
class CommonViewset(viewsets.ModelViewSet):
#link()
def set_owner(self, request, pk=None):
#how do I get Cat or Dog models cleanly here?
#super fugly/unstable way
url_path = request.META['PATH_INFO']
if 'cats' in url_path:
Cat.objects.get(pk=pk).owner = ...
elif 'dogs' in url_path:
Dog.objects.get(pk=pk).owner = ...
I can also put the set_owner link in separate views, but that feels un-DRY. Thanks in advance for looking into this!
You can pass the model to use in the as_view method of your class:
url(r'^cats/my-url/$', CommonViewSet.as_view(model=Cat)),
The ModelViewSet class inherits from Django's View class, so this will set the model attribute on the instance of your viewset. You can then use self.model to get the right model for the current url.

how to override the verbose name of a superclass model field in django

Let's say that I have a model Foo that inherits from SuperFoo:
class SuperFoo(models.Model):
name = models.CharField('name of SuperFoo instance', max_length=50)
...
class Foo(SuperFoo):
... # do something that changes verbose_name of name field of SuperFoo
In class Foo, I'd like to override the verbose_name of the name field of SuperFoo. Can I? If not, is the best option setting a label inside the model form definition to get it displayed in a template?
A simple hack I have used is:
class SuperFoo(models.Model):
name = models.CharField('name of SuperFoo instance', max_length=50)
...
class Meta:
abstract = True
class Foo(SuperFoo):
... # do something that changes verbose_name of name field of SuperFoo
Foo._meta.get_field('name').verbose_name = 'Whatever'
Bearing in mind the caveat that modifying Foo._meta.fields will affect the superclass too - and therefore is only really useful if the superclass is abstract, I've wrapped the answer #Gerry gave up as a reusable class decorator:
def modify_fields(**kwargs):
def wrap(cls):
for field, prop_dict in kwargs.items():
for prop, val in prop_dict.items():
setattr(cls._meta.get_field(field), prop, val)
return cls
return wrap
Use it like this:
#modify_fields(timestamp={
'verbose_name': 'Available From',
'help_text': 'Earliest date you can book this'})
class Purchase(BaseOrderItem):
pass
The example above changes the verbose_name and help_text for the inherited field 'timestamp'. You can pass in as many keyword args as there are fields you want to modify.
Your best bet would be setting/changing the label in the form itself. Referring to the name field of the Foo model (eg. by looking it up in Foo._meta.fields) will actually give you a reference to the name field of SuperFoo, so changing its verbose_name will change it in both models.
Also, adding a name field to the Foo class won't work either, because...
Overriding fields in a parent model
leads to difficulties in areas such as
initialising new instances (specifying
which field is being intialised in
Model.__init__) and serialization.
These are features which normal Python
class inheritance doesn't have to deal
with in quite the same way, so the
difference between Django model
inheritance and Python class
inheritance isn't merely arbitrary.
Have a look at how Django-CMS does this, they override the db_table field in the models inheriting from CMSPlugin. The basics (which I also use for my own stuff) boil down to:
class SuperFooMetaClass(ModelBase):
def __new__(cls, name, bases, attrs):
new_class = super(SuperFooMetaClass, cls).__new__(cls, name, bases, attrs)
new_class._meta.verbose_name = "...." # perhaps only if not customized
return new_class
class SuperFoo(models.Model):
__metaclass__ = SuperFooMetaClass
....
You can add some checks, e.g. only update for subclasses (not the direct type), or only update if the value is not customized.
I have different child classes deriving from the same base class. And I only care for the form view in the Django Admin interface.
The only solution that worked for me was to customize the Django Admin interface and set the verbose_name (or help_text) there:
class FooAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
form.base_fields['name'].verbose_name = "my verbose name"
return form
admin.site.register(models.Foo, FooAdmin)

Categories

Resources