Package: restframework-datachange
Restframework-datachange is an enhancement of rest_framework. To use it, we must have basic understandings of Django and rest_framework.1. InstallationAs usual, use pip:$ pip install restframework_datachange
$ pip install django
$ pip install djangorestframework2. Before using restframework_datachangeWe make a sample restframework-support project.$ django-admin startproject my_project
my_project$ cd my_project
my_project$ django-admin startapp movieNow we write the files as followed:Make models.my_project/movie/models.pyfromdjango.dbimportmodelsclassCast(models.Model):SEX_CHOICE=((1,"Male"),(2,"Female"))sex=models.IntegerField(choices=SEX_CHOICE,default=1)profession=models.CharField(max_length=100,default="")foreign_name=models.CharField(max_length=100,default="")def__str__(self):returnself.foreign_nameclassOneMovie(models.Model):COUNTRY_CHOICE=((1,"UK"),(2,"US"))name=models.CharField(max_length=200,default="")director=models.ManyToManyField(Cast,related_name="director")actors=models.ManyToManyField(Cast,related_name="actors")country=models.IntegerField(default="",choices=COUNTRY_CHOICE)def__str__(self):returnself.nameMake Serializers. For usage ofSlugRelatedField, please refer tothe document of djangorestframework.my_project/movie/serializers.pyfromrest_framework.serializersimportModelSerializer,SlugRelatedFieldfrommovie.modelsimportOneMovie,CastclassMovieSerializer(ModelSerializer):director=SlugRelatedField(slug_field="foreign_name",queryset=Cast.objects.all(),many=True)actors=SlugRelatedField(slug_field="foreign_name",queryset=Cast.objects.all(),many=True)classMeta:model=OneMoviefields="__all__"Make viewsmy_project/movie/views.pyfromdjango.shortcutsimportrenderfromrest_framework.viewsetsimportModelViewSetfrommovie.modelsimportOneMoviefrommovie.serializersimportMovieSerializerclassMovieViewSet(ModelViewSet):queryset=OneMovie.objects.all()serializer_class=MovieSerializerChange settingsmy_project/my_project/settings.py...INSTALLED_APPS=["django.contrib.admin","django.contrib.auth","django.contrib.contenttypes","django.contrib.sessions","django.contrib.messages","django.contrib.staticfiles","rest_framework",#"movie"#]...Make migrations and migrate.my_project/my_project $ cd ..
my_project $ python manage.py makemigrations
Migrations for 'movie':
  movie/migrations/0001_initial.py
    - Create model Cast
    - Create model OneMovie

my_project$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, movie, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying movie.0001_initial... OK
  Applying sessions.0001_initial... OKMake URLs for the whole project.my_project/my_project/urls.pyfromdjango.contribimportadminfromdjango.urlsimportpathfromrest_frameworkimportroutersfrommovie.viewsimportMovieViewSeturlpatterns=[path("admin/",admin.site.urls),]router=routers.DefaultRouter()router.register(r"movie",MovieViewSet,base_name="movie")urlpatterns+=router.urlsNow we create some data for the database.my_project$pythonmanage.pyshellIn[1]:frommovie.modelsimportOneMovieIn[2]:frommovie.modelsimportCastIn[3]:daniel=Cast.objects.create(sex=1,profession="actor",foreign_name="Daniel")In[4]:danielOut[4]:<Cast:Daniel>In[5]:emma=Cast.objects.create(sex=2,profession="actor",foreign_name="Emma")In[6]:Cast.objects.all()Out[6]:<QuerySet[<Cast:Daniel>,<Cast:Emma>]>In[7]:david=Cast.objects.create(sex=1,profession="director",foreign_name="David")In[8]:harry_potter_movie=OneMovie.objects.create(name="Harry Potter and the Goblet of Fire",country=2)In[9]:harry_potter_movie.director.add(david)In[10]:harry_potter_movie.actors.add(daniel)In[11]:harry_potter_movie.actors.add(emma)In[12]:harry_potter_movie.save()In[13]:harry_potter_movieOut[13]:<OneMovie:HarryPotterandtheGobletofFire>In[14]:harry_potter_movie.director.all()Out[14]:<QuerySet[<Cast:David>]>In[15]:harry_potter_movie.actors.all()Out[16]:<QuerySet[<Cast:Daniel>,<Cast:Emma>]>In[16]:exit()Now we run the server.my_project $ python manage.py runserver 0.0.0.0:8000Start your browser and enterhttp://127.0.0.1:8000/, click"movie": "http://127.0.0.1:8000/movie/"Ta da! Everything seems perfect. Below is what you'll see.[
    {
        "id": 1,
        "director": [
            "David"
        ],
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry Potter and the Goblet of Fire",
        "country": 2
    }
]3. Changing DataWe just want the movie"name"to be"Harry"instead of"Harry Potter and the Goblet of File". That is to say, we want to change the data returned. That's when restframework_datachange comes in!my_project/movie/views.pyfromrestframework_datachange.viewsetsimportRModelViewSet#frommovie.modelsimportOneMoviefrommovie.serializersimportMovieSerializerclassMovieAdjust(object):#defchange_name(self,value):# xx = namereturnvalue.split(" ")[0]#classMovieViewSet(MovieAdjust,RModelViewSet):#queryset=OneMovie.objects.all()serializer_class=MovieSerializerBy adding achange_xxto theAdjustobject and changing inheritance toRModelViewSet, we change the value of the returned"name"field from"Harry Potter and the Goblet of File"to"Harry"![
    {
        "id": 1,
        "director": [
            "David"
        ],
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry",
        "country": 2
    }
]Now we change the"country"code into correspondent country name:my_project/movie/views.py...classMovieAdjust(object):defchange_name(self,value):returnvalue.split(" ")[0]defchange_country(self,value):dic={1:"UK",2:"US"}returndic[value]...Ta da![
    {
        "id": 1,
        "director": [
            "David"
        ],
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry",
        "country": "US"  
    }
]4. Adding new data based on one fieldWe want a new field that is based on the data's original field. For example, we want a string version of"actors"named as"string_actors".my_project/movie/views.py...classMovieAdjust(object):string_actors_src1="actors"defchange_name(self,value):returnvalue.split(" ")[0]defchange_country(self,value):dic={1:"UK",2:"US"}returndic[value]defadd_string_actors(self,value):return", ".join(value)...Make anadd_xxmethod, pass avalueand modify it, and specify the source field asxx_src1. Then you can see this.[
    {
        "id": 1,
        "director": [
            "David"
        ],
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry",
        "country": "US",
        "string_actors": "Daniel, Emma"
    }
]4. Adding new data based on two or more fieldsSuppose we want to join the"country"field and the"name"field to form a"detail"field.classMovieAdjust(object):string_actors_src1="actors"detail_src1="country"# xx = detaildetail_src2="name"# xx = detaildefchange_name(self,value):returnvalue.split(" ")[0]defchange_country(self,value):dic={1:"UK",2:"US"}returndic[value]defadd_string_actors(self,value):return", ".join(value)defadd_detail(self,*value):# xx = detailreturn", ".join([str(i)foriinvalue])Now you can see:[
    {
        "id": 1,
        "director": [
            "David"
        ],
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry",
        "country": "US",
        "detail": "2, Harry Potter and the Goblet of Fire",
        "string_actors": "Daniel, Emma"
    }
]Pay attention to the"country"part in"detail", it is the original value2instead of the modified value"US". Here,"detail"has source fields"country"and"name", sovalue[0]is the value of"country"field,2. Andvalue[1]is the value of"name","Harry Potter and the Goblet of Fire".You can also write the code like this:classMovieAdjust(object):string_actors_src1="actors"detail_src1="country"detail_src2="name"defchange_name(self,value):returnvalue.split(" ")[0]defchange_country(self,value):dic={1:"UK",2:"US"}returndic[value]defadd_string_actors(self,value):return", ".join(value)defadd_detail(self,country,name):returnstr(country)+", "+str(name)Make sure the number and the position of parameters besideselfare the same as thesrcs of your newly-created field.5. Meddle with other actions.If you happen to know theretrieve,create,update,  actions of restframework, you can meddle your return by creatingAdjustobjects based on the tables below:ActionsModificationMethod PrefixSource Field Suffixlistadd a fieldaddsrclistchange a fieldchange--retrieveadd a fieldappendorgretrievechange a fieldmodify--createadd a fieldattachbircreatechange a fieldreform--updateadd a fieldadjoinlchupdatechange a fieldvary--For example:http://127.0.0.1:8000/movie/1/calls theretrievemethod.classMovieAdjust(object):string_actors_src1="actors"detail_src1="country"# xx = detail(list)detail_src2="name"# xx = detail(list)string_actors_retrieve_org1="actors"# yy = string_actors_retrieve(retrieve)defchange_name(self,value):returnvalue.split(" ")[0]defchange_country(self,value):dic={1:"UK",2:"US"}returndic[value]defadd_string_actors(self,value):return", ".join(value)defadd_detail(self,*value):# xx = detailreturn", ".join([str(i)foriinvalue])defmodify_country(self,value):dic={1:"United Kingdom",2:"United States"}returndic[value]defappend_string_actors_retrieve(self,value):# yy = string_actors_retrievereturn", ".join(value){
    "id": 1,
    "director": [
        "David"
    ],
    "actors": [
        "Daniel",
        "Emma"
    ],
    "name": "Harry Potter and the Goblet of Fire",
    "country": "United States",
    "string_actors_retrieve": "Daniel, Emma"
}6. Show/hide a fieldIf you want to show or hide a field, you can modify the action-specific_fieldsand_excludeproperty.classMovieAdjust(object):list_exclude=["actors"]will get you:[
    {
        "id": 1,
        "director": [
            "David"
        ],
        "name": "Harry Potter and the Goblet of Fire",
        "country": 2
    }
]classMovieAdjust(object):list_fields=["actors","name"]will get you:[
    {
        "actors": [
            "Daniel",
            "Emma"
        ],
        "name": "Harry Potter and the Goblet of Fire"
    }
]7. Turn python dict into a modelIf you have a python dict and wants to turn it into a Django model, you can usemodelmaker.model_maker(dic,file='fake_model.py',class_name='Default',name_changer=camel_to_,default_settings=None,**config)dic: A python dic.file: The model will be written in the file specified. Passed as""and it will only return a printed version.class_name: Model name.name_changer: A method to change some string into another string. Default is a function that turns camel cases to underlines.default_settings: A python dict to specify default properties settings of a type of field.config: Set the properties of model. For detail, please refer tothe documents of django.Example:fromrestframework_datachange.model_makerimportmodel_makerfromdatetimeimportdatetimedic={"apple":1,# IntegerField"boy":1.2,# FloatField"cat":"string",# CharField"dog":[{"json":1}],# JSONField"elephant":datetime.now(),# DatetimeField"changed":"string"}config={"apple__choices":[(1,"UK"),(2,"US")],"boy__null":True,"cat__max_length":20,"dog__verbose_name":"Dog","elephant__auto_now":True}defname_changer(string):li=["apple","boy","cat","dog","elephant"]ifstringnotinli:return"fog"returnstringprint(model_maker(dic,file="",class_name="M",name_changer=name_changer,**config))will give you:fromdjango.contrib.postgres.fieldsimportJSONFieldfromdjango.dbimportmodelsclassM(models.Model):apple=models.IntegerField(verbose_name="",help_text="",null=True,choices=[(1,"UK"),(2,"US")])boy=models.FloatField(verbose_name="",help_text="",null=True)cat=models.CharField(verbose_name="",help_text="",default="",max_length=20)dog=JSONField(verbose_name="Dog",help_text="",null=True,blank=True)elephant=models.DateTimeField(verbose_name="",help_text="",auto_now=True,auto_now_add=False)fog=models.CharField(verbose_name="",help_text="",default="",max_length=64)You can change the default settings ofmodel_makerby passing a python dict to thedefault_settingsparameter.dic={"apple":1}# IntegerFieldprint(model_maker(dic,file="",class_name="AppleCart",default_settings={"int":{"null":True}}))will give you:fromdjango.dbimportmodelsclassAppleCart(models.Model):apple=models.IntegerField(null=True)Default settings for different types are as followed:{"int":{"verbose_name":"","help_text":"","null":True},"str":{"verbose_name":"","help_text":"","default":"","max_length":64},"datetime":{"verbose_name":"","help_text":"","auto_now":False,"auto_now_add":False},"date":{"verbose_name":"","help_text":"","auto_now":False,"auto_now_add":False},"json":{"verbose_name":"","help_text":"","null":True,"blank":True},"bool":{"verbose_name":"","help_text":"","null":True},"float":{"verbose_name":"","help_text":"","null":True}}