1. Project Overview & Quickstart (Abdenasser/LICENSE)
LICENSE
Open-source repository Abdenasser/LICENSE
Repository Details
- Repository: Abdenasser/LICENSE
- Primary Language: Code
Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.
2. Official Technical Reference & Guides (Abdenasser/Abdenasser.github.io)
File: README.md
gatsby-starter-point
This is a tweaked and restyled version of Gatsby Starter which I use for my personal blog @ abdenasser.com feel free to clone it and use it for your personal websites. :shipit:
Basic Guide
Install dependencies
npm installwhen it's done
gatsby developContact
Contact me on twitter.
File: package.json
{
"name": "gatsby-starter-point",
"private": true,
"description": "be water my friend",
"version": "0.2.0",
"author": "George Brown [email protected]",
"bugs": {
"url": "https://github.com/teaware/gatsby-starter-point/issues"
},
"dependencies": {
"gatsby": "^2.24.47",
"gatsby-image": "^2.4.16",
"gatsby-plugin-dark-mode": "^1.1.2",
"gatsby-plugin-manifest": "^2.4.23",
"gatsby-plugin-offline": "^3.2.23",
"gatsby-plugin-react-helmet": "^3.3.10",
"gatsby-plugin-sass": "^2.3.12",
"gatsby-plugin-sharp": "^2.6.27",
"gatsby-plugin-transition-link": "^1.20.2",
"gatsby-plugin-typography": "^2.5.10",
"gatsby-remark-copy-linked-files": "^2.3.12",
"gatsby-remark-images": "^3.3.25",
"gatsby-remark-prismjs": "^3.5.10",
"gatsby-remark-responsive-iframe": "^2.4.12",
"gatsby-remark-smartypants": "^2.3.10",
"gatsby-source-filesystem": "^2.3.24",
"gatsby-transformer-remark": "^2.8.28",
"gatsby-transformer-sharp": "^2.5.13",
"gsap": "^3.5.0",
"node-sass": "^4.14.1",
"prismjs": "^1.21.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-headroom": "^3.0.0",
"react-helmet": "^6.1.0",
"react-typography": "^0.16.19",
"typeface-merriweather": "0.0.72",
"typeface-montserrat": "0.0.75",
"typography": "^0.16.19",
"typography-theme-wordpress-2016": "^0.16.19"
},
"devDependencies": {
"prettier": "^2.0.5",
"gh-pages": "^3.2.3"
},
"homepage": "https://gatsby-starter-point.netlify.app/",
"license": "MIT",
"scripts": {
"build": "rm -rf public && rm -rf .cache && gatsby build",
"develop": "gatsby develop",
"format": "prettier --write '{gatsby-.js,src/**/.{js,jsx,json,css}}'",
"start": "npm run develop",
"serve": "gatsby serve",
"deploy": "gatsby build && gh-pages -d public"
}
}
File: src/pages/my-personal-drf-serializers-draft/my-personal-drf-serializers-draft.md
title: "My personal drf serializer notes" tags: ["django", "apis", "notes"] date: "2021-09-03" spoiler: "A use case driven draft, UDD ๐ค !!"
Before today it was only me and god who can read my hand writing, but today it is only god who can... today I got stuck reading one of my DRF drafts about serializers and decided that it's that time of the year again where I start thinking that I should have a blog where I can save my notes -then forget about it again-, but as I already got a blog I said why not ๐ค ? ... let's create a digital copy of my drf serializer notes, maybe someone will find it useful.
save time creating django apis with this cool django package, and support the repository by dropping a star โญ
Let's define an Index or a table of content that we can use as reference in the future.
Table of content
1 - Fields
--------------------------
- Serializer Method Field
- Read Only Field
- Custom Field Validation
- Using Multiple Serializers
--------------------------
2 - Data
--------------------------
- Custom Data Validation
- Custom Output with `to_representation`()
- Custom Input with `to_internal_value`().
- Pass additional data directly to `save()`
--------------------------
3 - Keywords
--------------------------
- The `source` Keyword
- The `context` Keyword1- Fields
Serializer Method Field
This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.
SerializerMethodField gets its data by calling get_<field_name>.
Example:
class UserSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField()
class Meta:
model = User
fields = '__all__'
def get_days_since_joined(self, obj):
return (now() - obj.date_joined).daysRead Only Field
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any read_only fields that are incorrectly included in the serializer input will be ignored.
Example:
class AccountSerializer(serializers.Serializer):
id = IntegerField(label='ID', read_only=True)Custom Field Validation
Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class.
With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class.
Let's take an example where we want to only allow students that have age between 12 and 18:
class StudentSerializer(serializers.ModelSerializer):
...
def validate_age(self, age):
if age > 18 or age < 12:
raise serializers.ValidationError('Age has to be between 12 and 18.')
return ageUsing Multiple Serializers
You can override the get_serializer_class() of your ViewSet when for example you want to use a different Serializer in your create and update actions like the following:
class MyViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
def get_serializer_class(self):
if self.action in ["create", "update"]:
return WriteSerializer
return ReadSerializer2- Data
Custom Data Validation
Besides Custom Field Validation, there are two additional ways we can use to validate our data, when for example we need to compare some of our fields between each other the best way to do that is on the object level.
example:
class OrderSerializer(serializers.ModelSerializer):
...
def validate(self, data):
if data['discount_amount'] > data['total_amount']:
raise serializers.ValidationError('discount cannot be bigger than the total amount')
return dataAnother good way to do validation is when a validation logic is repeated multiple times in some serializers, you can then extract it to a function, example:
def is_valid_age(value):
if age < 12:
raise serializers.ValidationError('age cannot be lower than 12.')
elif age > 18:
raise serializers.ValidationError('age cannot be higher than 18')Then you can pass it like this in the other serializers:
class AnotherSerializer(serializers.ModelSerializer):
age = IntegerField(validators=[is_valid_age])Custom Output with `to_representation()`
When you want to customize the output right before it is sent use to_representation(), imagine you have an output like the following after serialization is completed:
{
"id": 1,
"username": "abdenasser",
"bio": "Hey ... you already know!",
"followed_by": [2, 3]
}and you want to add a total followers count to it... you can simply do:
class ResourceSerializer(serializers.ModelSerializer):
...
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['followers'] = instance.followed_by.count()
return representationThen you'll get:
{
"id": 1,
"username": "abdenasser",
"bio": "Hey ... you already know!",
"followed_by": [2, 3],
"followers": 2
}Custom Input with `to_internal_value()`
Let's say that your API is expecting some input from a 3rd party service and you are only interested in a chunk of that input, you can use to_internal_value() as follow:
class SomeSerializer(serializers.ModelSerializer):
...
def to_internal_value(self, data):
useful_data = data['useful']
return super().to_internal_value(useful_data)Pass additional data directly to save()
Calling .save() will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)3- Keywords
The source Keyword
In essence, you can use source in a field like this
field_name = serializers.SomeFieldType(source='prop')where prop could be a call for a function that return some value, or a property that exists in a related model like ...(source='author.bio') or even a serializer field that you want to rename in output.
You can also attach the whole object with source='*' if you need.
The context Keyword
You can provide arbitrary additional context by passing a context argument when instantiating a serializer. For example:
resource = Resource.objects.get(id=1)
serializer = ResourceSerializer(resource, context={'key': 'value'})The context dictionary can then be used within any serializer field logic, such as a custom .to_representation() method, by accessing the self.context attribute.
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['key'] = self.context['key']
return representationFinal word:
Django Rest Framework has a very good documentation which you can find and read here, try to spend some time on it and use it as a fall back any time you feel that things started getting complicated in your serializers, also bare in mind that while you are using serializers you are most of the time using, overriding or extending the base serializer functionalities so go check it out and take a look at it here.
File: src/pages/scaffold-django-apis/scaffold-django-apis.md
title: "Scaffold django apis like a champion" tags: ["django", "python", "oss"] date: "2021-08-26" spoiler: "The very first blog post"
Hey ๐ my name is Abdenasser I'll give you a proper introduction to who I'm in the next blog, but today I'll show you how to use this little django scaffold library I crafted last week https://github.com/Abdenasser/dr_scaffold to create a ready to use and fully functional REST apis with django only using the command line, let's get started.
Setting a django environment is outside of the scope of this article, I'm sure there's a lot of guides and tutorials on how to do that all over internet you can follow one of them and get back, I'll be waiting for you just right here!
In a nutshell here is what we gonna do in three steps:
- Create a django project
- Setup django rest framework and dr_scaffold
- Scaffold a blog api with Articles and Authors
1. Create a django project:
Let's create a django project using this django-admin command:
$ django-admin startproject myApithis command does the same as python manage.py startproject myApi the only difference is that it doesn't require a python environment to get executed.
Let's then cd to our newly created django project cd myApi and create a virtualenv with:
$ python3 -m virtualenv envFinally let's activate our virtual env with:
$ source env/bin/activate2. Setup django rest framework and dr_scaffold:
Let's install django rest framework and dr_scaffold packages using pip like the following:
$ pip install djangorestframework
$ pip install dr-scaffoldNext let's add these packages to our project INSTALLED_APPS inside myApi/settings.py like this:
INSTALLED_APPS = [
...,
'rest_framework',
'dr_scaffold'
]Then let's add our core and api folders settings to myApi/settings.py, (for the simplicity of the tutorial we'll leave them empty):
CORE_FOLDER = "" # you can leave them empty
API_FOLDER = "" # or set them to be the same3. Scaffold a blog api with Articles and Authors
Our blog api will be composed of two main resources an Article and a Author, Let's scaffold our Author first:
$ python manage.py dr_scaffold blog Author name:charfield
๐ Your RESTful Author api resource is ready ๐this command will generate a blog folder with models.py > admin.py views.py serializers.py urls.py all populated with appropriate code that your REST api needs for Author resource
Lets also generate the Article resource:
$ python manage.py dr_scaffold blog Post body:textfield author:foreignkey:Author
๐ Your RESTful Post api resource is ready ๐this command will do the same thing but also will add a relation to our Author resource through a foreignkey field.
In order to generate the database tables let's add blog to our INSTALLED_APPS inside myApi/settings.py:
INSTALLED_APPS = [
...,
'rest_framework',
'dr_scaffold',
'blog'
]Then let's run these commands to generate our migrations and migrate the database:
$ python manage.py makemigrations
$ python manage.py migrateFinally add our blog to our project's urlpatterns inside myApi/urls.py:
urlpatterns = [
...,
path("blog/", include("blog.urls")),
]Don't forget to import include in your project's urls.py like so :
from django.conf.urls import includeYour urls.py should look something like this in the end:
from django.conf.urls import include #our added import
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
path("blog/", include("blog.urls")), #our added bol path
]Now that we are completely done let's run python manage.py runserver and head over to http://127.0.0.1:8000/blog/ to see your fully created REST blog API.. and also you can generate a super user with python manage.py createsuperuser then head over to http://127.0.0.1:8000/admin to check the admin panel.
Don't forget to star the repo on github If you like it.. Enjoy ๐ !