Django-import-export - export from model's functions? - django

For a Django model I'm using django-import-export package.
The manual says I can export fields that are not existing in the target model like so:
from import_export import fields
class BookResource(resources.ModelResource):
myfield = fields.Field(column_name='myfield')
class Meta:
model = Book
http://django-import-export.readthedocs.org/en/latest/getting_started.html
How do I export the output of functions from the model? e.g. Book.firstword()

Here's how you should do it (check this out https://django-import-export.readthedocs.org/en/latest/getting_started.html#advanced-data-manipulation):
from import_export import fields, resources
class BookResource(resources.ModelResource):
firstword = fields.Field()
def dehydrate_firstword(self, book):
return book.firstword()
class Meta:
model = Book
Update to answer OP comment
To return fields in a particular order, you can user the export_order Meta option (https://django-import-export.readthedocs.org/en/latest/api_resources.html?highlight=export_order#import_export.resources.ResourceOptions).

There is one more solution with less code, than that suggested by Serafeim:
from import_export import fields, resources
class BookResource(resources.ModelResource):
firstword = fields.Field(attribute='firstword')
class Meta:
model = Book

Just in case you need to get the full URL of the field and based on #Serafeim's solution
class CompanyModelResource(ModelResource):
def dehydrate_local_logo(self, company):
if company.local_logo and hasattr(company.local_logo, 'url'):
return company.local_logo.url
return company.local_logo
class Meta:
model = Company

Related

How to rename GraphQL type field autogenerated from Django model?

I've a model in Django with some fields. Let's say this exemplary one:
# <app>/models.py
from django.db import models
class Something(models.Model):
first_field = models.Charfield()
second_field = models.Charfield()
I use DjangoObjectType from graphene_django to map Django models to GraphQL types.
# <app>/schema.py
from graphene_django import DjangoObjectType
from .models import Something
class SomethingType(DjangoObjectType):
class Meta:
model = Something
Cause of auto camelcasing the model field second_field results in secondField in the GraphQL type. Now I'd like to rename the GraphQL type field from secondField to somethingFancy. How can I get this done easiest?
You can overwrite any field with DjangoObjectType. Your code may look like this.
class SomethingType(DjangoObjectType):
class Meta:
model = Something
something_fency = graphene.String()
def resolve_something_fency(self, info):
return self.second_field
For more details check out the docs

Avoid nested objects when using nested serializers

I have two models, one contains the other in a foreignKey relationship, I wanted to make an API that would return the combine of these two models, so I attempted to use nested Serializers to add the related model as well, but the data are not all on the same level, the related models is a object inside the first.
Here are the Models
class ModelOne(models.Model):
last_counter = models.IntegerField()
class ModelTwo(models.Model):
model_one = models.ForeignKey(ModelOne, on_delete=models.CASCADE)
category = models.CharField(max_length=64)
counter_type = models.CharField(max_length=32)
Here are the serializers
class ModelOneSerializer(serializers.ModelSerializer):
class Meta:
model = ModelOne
fields = "__all__"
class ModelTwoSerializer(serializers.ModelSerializer):
model_one= ModelOneSerializer(read_only=True)
class Meta:
model = ModelTwo
fields = "__all__"
This would return from the API in the form of
{
"category" : ...,
"counter_type" : ...,
"model_one" : {
"last_counter" : ...
}
}
But I don't want the response to be like that, I want it more like this
{
"category" : ...,
"counter_type" : ...,
"last_counter" : ...,
}
Is there a way to achieve this through serializers?
Use SerializerMethodField
from rest_framework.fields import SerializerMethodField
class ModelTwoSerializer(serializers.ModelSerializer):
last_counter = SerializerMethodField()
class Meta:
model = ModelTwo
fields = "__all__"
def get_last_counter(self, obj):
return ModelOneSerializer(obj.model_one).data['last_counter']
When creating custom fields(field_one for example) with SerializerMethodField, you have to create a method called get_field_one, for this method to be automatically detected by the serializer.
You can achieve what you want to do using SerializerMethodField from drf fields:
SerializerMethodField is a read-only field that computes its value at request processing time, by calling a method on the serializer class it is attached to. For example for your case it will look like this. Notice that the computed last_counter is added on the serialized model fields.
from rest_framework.fields import SerializerMethodField
class ModelTwoSerializer(serializers.ModelSerializer):
last_counter = serializers.SerializerMethodField()
class Meta:
model = ModelTwo
fields = ["category", "counter_type", "last_counter"]
def get_last_counter(self, obj):
return int(obj.model_one.last_counter)
SerializerMethodField accepts method_name, but it’s usually more convenient to use the default pattern for naming those methods, which is get_. Just make sure you‘re not overburdening your method fields with any heavy-lifting operations.
You can read more on the official documentation:enter link description here

Retrieving the Model object using table name

I would like to retrieve the Model object while knowing the table_name
For ex:
class User(models.Model):
class Meta:
db_table = 'my_users_table'
Are there ways that return User by taking my_users_table as input?
I would like to retrieve the Model object
I think you mean the Model class here instead of object.
One possible solution that I can think of is to get all the models and match for db_table:
from django.apps import apps
model = next((m for m in apps.get_models() if m._meta.db_table=='my_users_table'), None)
If there is no model with the given db_table name then the model will be None.
I don't think there is a direct way to do this. But you can create your own function which will do this for you.
Based on https://stackoverflow.com/a/29739109/3627387
from django.apps import apps
def get_model_by_db_table(db_table):
for model in apps.get_models():
if model._meta.db_table == db_table:
return model
else:
# here you can do fallback logic if no model with db_table found
raise ValueError('No model found with db_table {}!'.format(db_table))
# or return None
Or you can do this using ContentType model
Edit:
The link provided for ContentType is broken. This may be tried instead.

Adding custom data to django model field

I'd like to add some info to a model field to use at form rendering time. My real model has about 15 values of varying field types (adding and removing as I dev), and it does almost everything I need, so I'd rather not create custom model fields for all of them.
I'd like to do something like this:
from django.db import models
class MyModel(models.Model):
cost = models.DecimalField(max_digits=5,
decimal_places=2,
custom_info= {'glyph': 'glyphicon glyphicon-usd' }
)
And then in my form template use that glyph much like I'd use a verbose_name or help_text.
Something I learned from a post just the other day. Will defining the custom information on the form instead of the model work?
When you define formfield_callback on a forms.ModelForm it will iterate over the form fields and you can manipulate them. This comes in handy when you need to add a css class to widgets and don't want to explicitly override the field. Now you only need to put formfield_callback = modify_form_field on any forms.ModelForm where you want the custom_info to show up.
from django.db import models
def add_glyphicons(model_field):
form_field = model_field.formfield()
if isinstance(model_field, models.IntegerField):
form_field.custom_info = {'glyph': 'glyphicon glyphicon-usd'}
elif isinstance(model_field, models.CharField):
form_field.custom_info = {'glyph': 'glyphicon glyphicon-yen'}
return form_field
class MyModel(models.Model):
formfield_callback = add_glyphicons
class Meta:
model = MyModel
class MyOtherModel(models.Model):
formfield_callback = add_glyphicons
class Meta:
model = MyOtherModel

Custom labels for UserProfileForm in Django

I'm using the UserProfileForm class under django.db to take the UserProfile model class and turn it into a form. Currently, the labels for the form elements are the column names of the underlying db table. I'm wondering if there is a way that I can customize the labels?
Thanks,
Tino
I think you mean a model form using django.forms.ModelForm. You can add a verbose name to your UserProfileModel, or you can use the label arg in your ModelForm like so:
>>> class ArticleForm(ModelForm):
... pub_date = DateField(label='Publication date')
...
... class Meta:
... model = Article
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#a-full-example
http://docs.djangoproject.com/en/dev/ref/forms/api/