The Promise object represents the eventual completion (or failure) of an asynchronous operation and its
resulting value. A Promise is a proxy for a value not necessarily known when the promise is created. It
allows you to associate handlers with an asynchronous action’s eventual success value or failure reason. This lets
asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the
asynchronous method returns a /promise/ to supply the value at some point in the future.
- Generator
- something that yield is a generator
- List comprehension build with [], generator expression build with ()
- (i**2 for i in range(5))
- Lazy evaluation and local scope . get value of i**2 until next
- yield and yield from (python 3.3)
- yield is used to produce a value from the generator and to suspend the function’s state so that it can be resumed right from where it left off.
- It essentially allows the function to return a value (like a regular function would with return) but remembers its state for future calls.
``` python
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
```
- `yield from` is used to delegate part of its operations to another generator. This simplifies the code when a generator function is calling another generator function. It's a way to yield all values from another iterable (often another generator) without using a loop.
- Example:
``` python
def generator_without_yield_from():
for item in simple_generator():
yield item
gen = generator_without_yield_from()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
# with yield from
def generator_with_yield_from():
yield from simple_generator()
gen = generator_with_yield_from()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
```
- User case
- `yield`: When you're producing values in a generator function.
- `yield from`: When you want to delegate yielding values to another generator (or any iterable) within a generator function.
- also `yield from` is useful when `with open(filename) as f:` context and you should `yield from` instead of `yield` or `return` the lazy iterator inside context
Set
operations
| : union, set1|set2|set3
&: join set1 & set2 & set3
-: difference set1 - set2
^: semmetric difference, same as (s1 | s2) -( s1 & s2 )
Normally there are following way to deploy python service
ECS/EKS
EC2
EBS (elastic beanstalk)
Lambda
WSGI
WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications
why we need a gateway mediator
flexiblity
If you directly point your web server to your application, it reduces the flexibility** **of your application. Since your web server now directly points to your web application, you are unable to swap out web stack components.
:drawer:
let’s say you’ve decided to deploy your application using Gunicorn, but several years later, you decide to switch from Gunicorn to mod_wsgi. In this situation, you could easily switch to mod_wsgi without making any changes in the application or framework because you used WSGI. WSGI provides flexibility to your application.
:END:
scalability
WSGI is capable of serving thousands of requests at a time. The WSGI server is responsible for handling the requests from the web server and making decisions for carrying out the communication of those requests to an application framework’s process. we can divide the responsibilities among the servers for scaling web traffic.
INSTALLED_APPS=['django.contrib.staticfiles','api.apps.ApiConfig',# this include app : api'rest_framework']MIDDLEWARE=['django.middleware.security.SecurityMiddleware','django.middleware.common.CommonMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',]TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[],'APP_DIRS':True,'OPTIONS':{'context_processors':['django.template.context_processors.debug','django.template.context_processors.request',],},},]REST_FRAMEWORK={"UNAUTHENTICATED_USER":None# disable user-content reference}
- ((651210f8-a2fe-4194-9216-f1eefdded8a6))
heading:: 2
- APIView
heading:: 2
desc:: REST framework provides an APIView class, which subclasses Django’s View class.
- APIView <- django.views.View and it implemented as_view()
- APIView has csrf_exempt. It implemented as_view and dispatch
- Requests passed to the handler methods will be REST framework’s Request instances, not Django’s HttpRequest instances.
- Handler methods may return REST framework’s Response, instead of Django’s HttpResponse The view will manage content negotiation and setting the correct renderer on the response.
- Any APIException exceptions will be caught and mediated into appropriate responses.
- Incoming requests will be authenticated and appropriate permission and/or throttle checks will be run before dispatching the request to the handler method.
-
- Requests
heading:: 2
desc:: REST framework’s Request class extends the standard HttpRequest, adding support for REST framework’s flexible request parsing and request authentication.
- Requests - Django REST framework
heading:: 3
- DRF extend django HttpRequests by adding
heading:: 3
- data: use request.data.get('fieldname') to get data from a POST request
- query_params handle URL like /users/?id=12
- Authentication
- Browser enhancement
- extends HttpRequest
- META
- session
- version
- request.version
- request.versioning_{ schema}
- parser
- negotiator
-
- Authentication
heading:: 2
desc:: Auhentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The permission and throttling policies can then use those credentials to determine if the request should be permitted.
id:: 65136fb1-b3fd-40b2-b22b-d8ea5e0908b9
- Create a new Authentiation class
heading:: 3
- SimpleAuth
heading:: 3
# auth.pyclassSimpleAuth(BaseAuthentication):defauthenticate(self,request):token=request.query_params.get('token')iftoken:return'admin',token#return user and tokenraiseAuthenticationFailed('token missing')defauthenticate_header(self,request):return"xxx app"# return when you need something put in header when failed# view.pyclassUserView(APIView):authentication_class=[SimpleAuth]# Auth is requireddefget(self,request):print(request.user,request.auth)# prints 'admin', tokenreturnResponse({})
- Apply Authentication Globally
heading:: 3
- in Settings.py
``` python
REST_FRAMEWORK= {
"DEFAULT_AUTHENTICATION_CLASS": ["api.view.SimpleAuth",] # use string to avoid imporiting packages
}
```
- Override
- First get Auth from setting.py and in each view read `authentication_class`. The 2nd will override global setting if it is not `None` set 2^{ nd} to `[]` will disable global setting and disable Auth
Multi Authenticators
heading:: 4
If authenticate() returns None when failed, DRF will go to next Authenticator until the return value is not None.
If all returns None. then self.auth == None
If you want to prevent None go through, put an authenticator that will raise fail at end of list
Verify token in Authentication middleware
classQueryTokenAuth(BaseAuthentication):defauthenticate(self,request):token=request.query_params.get('token')# api: GET order/?orderid=12&token=3322-333-111-111-3233ifnottokenreturnuser=models.UserInfo.objects.filter(token=token).first()ifuser:returnuser,token# request.user = user, request.token=tokenraiseAuthenticationFailed({'code':401})defauthenticate_header(self,request):return"query failure"classHeaderTokenAuth(BaseAuthentication):defauthenticate(self,request):token=request.META.get("HTTP_AUTHORIZATION")# api: GET order/?orderid=12&token=3322-333-111-111-3233ifnottokenreturnuser=models.UserInfo.objects.filter(token=token).first()ifuser:returnuser,token# request.user = user, request.token=tokenraiseAuthenticationFailed({'code':401})defauthenticate_header(self,request):return"nead failure"
- Permission
heading:: 2
desc:: Together with authentication and throttling, permissions determine whether a request should be granted or denied access.
url:: DRF: Permission
- Permissions are used to grant or deny access for different classes of users to different parts of the API.
- The simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds to the IsAuthenticated class in REST framework.
- Sample permission class
fromrest_frameworkimportpermissionsclassIsOwnerOrReadOnly(permissions.BasePermission):""" Custom permission to only allow owners of an object to edit it. """# message is used to create a response body when per check failedcode=401# used to set http codemessage={"status":"False","code":code,"data":"permission error for user","msg":"IsOwnerCheck"}defhas_permission(self,request,view):# Read permissions are allowed to any request,# so we'll always allow GET, HEAD or OPTIONS requests.ifrequest.methodinpermissions.SAFE_METHODS:returnTrue# Write permissions are only allowed to the owner of the snippet.returnFalsedefhas_object_permission(self,request,view,obj):# Read permissions are allowed to any request,# so we'll always allow GET, HEAD or OPTIONS requests.ifrequest.methodinpermissions.SAFE_METHODS:returnTrue# Write permissions are only allowed to the owner of the snippet.returnobj.owner==request.user
- One difference between ((65136fb1-b3fd-40b2-b22b-d8ea5e0908b9)) is if a list of Per-Class is add. ALL Permission check need success/True. It is AND operation
- Add permission check in view
- Check permissions override
- if you need to override default permission check mechanism, override check_permissions() function in view class 💀
- Throttling
heading:: 2
desc:: Throttling is similar to permissions, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API.
- As with permissions, multiple throttles may be used. Your API might have a restrictive throttle for unauthenticated requests, and a less restrictive throttle for authenticated requests.
- Another scenario where you might want to use multiple throttles would be if you need to impose different constraints on different parts of the API, due to some services being particularly resource-intensive.
- Settings
- Define a throttle Class
- In most case throttle class in django is good enough for 99% of the user cases. But in case you need to define a throttle of your own, here is two examples:
classRandomRateThrottle(throttling.BaseThrottle):defallow_request(self,request,view):returnrandom.randint(1,10)!=1classRandomRateThrottle2(throttling.SimpleRateThrottle):defallow_request(self,request,view):ifsuper().allow_request(request,view):returnrandom.randint(1,10)!=1classMyRateThrottle(SimpleRateThrottle):cache=default_cache# 访问记录存放在django的缓存中(需设置缓存)scope="user"# 构造缓存中的key different API can have different scopecache_format='throttle_%(scope)s_%(ident)s'# 设置访问频率,例如:1分钟允许访问10次# 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'THROTTLE_RATES={"user":"10/m"}#scope : ratedefget_cache_key(self,request,view):ifrequest.user:ident=request.user.pk# 用户IDelse:ident=self.get_ident(request)# 获取请求用户IP(去request中找请求头)# throttle_u # throttle_user_11.11.11.11ser_2returnself.cache_format%{'scope':self.scope,'ident':ident}defthrottle_failure(self):wait=self.wait()detail={"code":1005,"data":"访问频率限制",'detail':"需等待{}s才能访问".format(int(wait))}raiseThrottledException(detail)
- Versioning
heading:: 2
desc:: Versioning allows you to alter behavior between different clients. DRF provides for a number of different versioning schemes.
- Config API version
heading:: 3
- [[../assets/image-20210819154455680_1696666609261_0.png]]
- settings.py
GET something?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
- Reverse URL
heading:: 3
- [[../assets/image-20210820105543193-3386187_1696666581416_0.png]]
- [[../assets/image-20210820112152615_1696666677979_0.png]]
- Request parsing
heading:: 2
desc:: REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers
- Jsonparser
[[../assets/image-20210827081058194_1696668405368_0.jpg]]
- File parser (MultiPartParser)
- [[../assets/image-20210827083047327_1696668472683_0.jpg]]
- File uploader
- [[../assets/image-20210827084403453_1696668497009_0.jpg]]
-
-
- Content negotiation
heading:: 2
desc:: Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.
url:: Content negotiation - Django REST framework
- The client need specify content-typeand the value should be valid http media type
- the config is through parser_classes and content_negotiation_class
Global setting
- When the code refer to request.data it will trigger the parser
- Most used JSONParser and FormParserxx, to upload file FileUploaderParser, Large file MultiPartParser
- If not specifed or content does not match parser, a exception will be throw
-
-
- Serializers
heading:: 2
desc:: Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
- Declaring Serializers
heading:: 3
- In a sense, Serializers is similar to ((651cfa1b-ce5c-486b-8f45-5f3cee8f113e))
- Create a serializer for Comment
``` python
from datetime import datetime
class Comment:
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now()
comment = Comment(email='leila@example.com', content='foo bar')
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
```
Serializing object
heading:: 3
use CommentSerializer to serialize a comment, or list of comments
python
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
comments = [comment, comment] # array of objects
serializer = CommentSerializer(comments, many=True)
serializer.data # a list of objects
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
- ModelSerializer
heading:: 3
desc:: serializer classes that map closely to Django model definitions.
- The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields. It based on Serializer class and
* It will automatically generate a set of fields for you, based on the model.
* It will automatically generate validators for the serializer, such as unique_{ together} validators.
* It includes simple default implementations of .create() and .update().
- Declaring
heading:: 4
``` python
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created'] # similar to ModelForm, you can use fields = '__all__'
read_only_fields = ['account_name']
```
- `read_only` and `write_only`
- `read_only` can be used for output serializer it can be shown in response
- `write_only` used for input data serializer, e.g. password/token field
- choice fields and foreign key
heading:: 4
- e.g. gender: ((1:'male'), (2, 'female'))
depart was defined as foreign key to department table (id, name)
``` python
# model gender: ((1:'male'), (2, 'female'))
class AccountSerializer(serializers.ModelSerializer):
gender_info = serializers.CharField(source='get_gender_display', read_only=True)
depart = serializers.CharField(source='depart.title') #show department title
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created', 'gender_info', 'depart']
extra_kwargs = {'gender': {'write_only': True}}
```
- It follow conventions of Django ModelForm
- Use a new name `gender_info` because when write to DB we want a number 1|2, when read and show in API we want string of male|female
- define own field
heading:: 4
``` python
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['xxx']
def get_xxx(self, obj):
return obj.first_name + obj.last_name
```
- nested and embed
heading:: 4
- Suppose there are multiple tables with 1:1 or m:n relations
``` python
from django.db import models
class Role(models.Model):
title = models.CharField(verbose_name="标题", max_length=32)
order = models.IntegerField(verbose_name="顺序")
class Tag(models.Model):
caption = models.CharField(verbose_name="名称", max_length=32)
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名", max_length=32)
gender = models.SmallIntegerField(verbose_name="性别", choices=((1, "男"), (2, "女")))
role = models.ForeignKey(verbose_name="角色", to="Role", on_delete=models.CASCADE)
ctime = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
tags = models.ManyToManyField(verbose_name="标签", to="Tag")
```
- You can create a new ModelSerializer
``` python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Role
# fields = "__all__"
fields = ["id", 'title']
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = models.Tag
fields = "__all__"
class InfoSerializer(serializers.ModelSerializer):
role = RoleSerializer()
tags = TagSerializer(many=True)
class Meta:
model = models.UserInfo
fields = ['id', 'name', "role", "tags"]
class InfoView(APIView):
def get(self, request):
queryset = models.UserInfo.objects.all()
ser = InfoSerializer(instance=queryset, many=True)
print(type(ser.data), ser.data)
return Response(ser.data)
```
- Inheritances
heading:: 4
``` python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models
class MySerializer(serializers.Serializer):
more = serializers.SerializerMethodField()
def get_more(self, obj):
return "123"
# inherit MySerializer
class InfoSerializer(serializers.ModelSerializer, MySerializer):
class Meta:
model = models.UserInfo
fields = ["id", "name", 'more']
class InfoView(APIView):
def get(self, request):
instance = models.UserInfo.objects.all().first()
ser = InfoSerializer(instance=instance, many=False)
print(type(ser.data), ser.data)
return Response(ser.data)
```
- Save/Update data
heading:: 4
- save()/ update() method
heading:: 4
``` python
serializer = CommentModelSerializer(data=data)
serializer.save()
# for non model serializer
serializer = CommentNonModelSerializer(data=data)
serializer.validated_data.pop('confirm_password') # there are filed should not save into database
models.Comment.objects.create(**serializer .validate_data)
```
- In save(), you can add additional fields
heading:: 4
``` python
serializer.save(updated = datetime.now(), updated_by = request.user )
```
- Foreign key and many to many
heading:: 4
- When validate/save foriegn key, DRF will check if the key is valid or not
- It also apply when M2N is passed e.g. {'tags': [1, 1111]}, if `1111` not existed in M2N table, validation will fail
- Override `to_presentation`
- If you need to show something in DB in a more friendly way (beyond `display_xxx`) You can override `to_presentation`
- [[../assets/image_1696746627345_0.png]]
``` python
class SbModelSerializer(NbHookSerializer, serializers.ModelSerializer):
class Meta:
model = models.NbUserInfo
fields = ["id", "name", "age", "gender"]
extra_kwargs = {
"id": {"read_only": True}
}
def nb_gender(self, obj): # YOu can define your own getter here
return obj.get_gender_display()
def nb_name(self, obj):
return obj.get_gender_display()
class SbView(APIView):
def post(self, request, *args, **kwargs):
ser = SbModelSerializer(data=request.data) # the to_presentation was overrided
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
```
Validator
heading:: 2
desc:: validation logic into reusable component, DRF validation is performed entirely on the serializer class.
Samples
classCustomerReportRecord(models.Model):time_raised=models.DateTimeField(default=timezone.now,editable=False)reference=models.CharField(unique=True,max_length=20)description=models.TextField()# if meta set to CustomerReportRecord, reference max_len will be 20classCustomerReportModelSerializer(serializers.ModelSerializer):classMeta:model=CustomerReportRecord#This works as wellclassCustomerReportSerializer(serializers.Serializer):reference=serializers.CharField(required=True,max_length=20,min_length=4)description=serializers.CharField(required=True,max_length=20)# email = serializers.EmailField() # implemented email validationemail=serializers.CharField(validators=[EmailValidator("email format invalid")])mobile=serializers.CharField(validators=[RegexValidator(r"\d+",message="number only")])
- Model serializer validations
- You can set it up for more complicated validations schemas
``` python
class BillingRecordSerializer(serializers.ModelSerializer):
def validate(self, attrs):
# Apply custom validation either here, or in the view.
class Meta:
fields = ['client', 'date', 'amount']
validators = [
UniqueForYearValidator(
queryset=BlogPostItem.objects.all(),
field='slug',
date_field='published'
)
]
extra_kwargs = {
'client': {'required': False},
'title': {'max_length': 10},
'phone': {'validators': [RegexValidator(r'\d+', message='phone number')]},
}
# validators = [] # Remove a default "unique together" constraint.
```
Validator hook
Put inside CustomerReportSerializer
classCustomerReportSerializer(serializers.Serializer):defvalidate_phone(self,value):# validate {'phone': '02233221123', ...}iflen(value)<10:raiseexception.ValidationError("incorrect phone number length")returnvaluedefvalidate(self,attrs):# this validate all fields# api_settings.NON_FIELD_ERRORS_KEYiflen(attrs['country']=='AU'andlen(attrs['mobile'])<11:raiseexceptions.ValidationError('incorrect mobile for AU')
- Validation error exception will be captured in DRF and convert to error response
- Validate a request
Normally the csrftoken template tag will not work if CsrfViewMiddleware.processview or an equivalent like csrfprotect has not run. The view decorator ~requirescsrftoken~ can be used to ensure the template tag does work.
SESSION_ENGINE='django.contrib.sessions.backends.db'# 引擎(默认)# use 'django.contrib.sessions.backends.cached_db' for high trafficSESSION_COOKIE_NAME="sessionid"# Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)SESSION_COOKIE_PATH="/"# Session的cookie保存的路径(默认)SESSION_COOKIE_DOMAIN=None# Session的cookie保存的域名(默认)SESSION_COOKIE_SECURE=False# 是否Https传输cookie(默认)SESSION_COOKIE_HTTPONLY=True# 是否Session的cookie只支持http传输(默认)SESSION_COOKIE_AGE=1209600# Session的cookie失效日期(2周)(默认)SESSION_EXPIRE_AT_BROWSER_CLOSE=False# 是否关闭浏览器使得Session过期(默认)SESSION_SAVE_EVERY_REQUEST=False# 是否每次请求都保存Session,默认修改之后才保存(默认)
*** asgi stands for Asynchronous Server Gateway Interface and ~wsgi` stands for *Web Server Gateway Interface.*
After your development process is completed, you will move to
production and hosting. For hosting you will
use ~asgi~ or ~wsgi~ compatible servers. According to the type
of server you use, you have to import middleware accordingly.
~asgi.py~ enables ASGI compatible servers and ~wsgi.py~ enables
WSGI compatible servers to serve your Django web app.
This is the main configuration file for a Django project. This is
the main settings file and here you will configure all the apps and
middleware for your project.
This file also handles the database settings. By default Django uses
sqlite3. But if you use a different database, which you will most
probably do, you will configure it in ~settings.py~.
~settings.py~ also handles templates, static files, and media
files related settings.
URLs are different endpoints of your website. ~urls.py~ contains
the URL configurations for your website. By
default, ~urls.py~ comes with the URL pattern for the admin panel.
You will create other endpoints for your web app in this file.
This file is used to register the models in your app in the
Django administration. You will use this file to display the
models of your app in the admin panel.
It is a common configuration file for all Django apps. You can
configure the attributes for your app using this file. However,
the default configuration is sufficient for most cases. So,
adding app configuration is a rare case.
~migrations~ folder
Once you start making changes in your database,
the ~migrations~ folder will be populated with the records for
all those migrations.
models.py
You create your models in this
file. Models define
the database structure of your app. In ~models.py~ you basically
create database tables for your app with proper relationships using
Python classes.
~models.py~ is one of the most important files in your app. Django
follows the MVT (Model-View-Template) design architecture. The 'M'
represents models. So, models are one of the basic components of a
Django app.
views.py
is another important
file. Views are
the 'V' of MVT. Views provide an interface through which users
interact with a Django website. It connects models and templates
together.
In this file, you write the business logic for your app. A view
can be either function-based or class-based. You decide if you
want to write your views using functions or classes.
You can learn more about the MVT architecture from this article:
each app can have own template and the search sequence is
defined same as how different app is loaded
static
css, js, images, json..
{% raw %}{% load static %}{% endraw %} to load static files 👍
{% raw %}{% static 'css/bootstrap.css' %}{% endraw %} to refer to those files
urls.py in app
if your application is complex, use a dedicatd url.py
forms.py
If your website expects to receive user inputs you need to
use forms.
To work with forms in an app you need to create the forms.py
file in that app. Here you will write the codes to handle forms.
depart=models.ForeignKey("Department",on_delete=models.CASCADExx)# table "Department", to_field='id'# if 'id' is default (auto_field) to_field can be ignore
fromdjangoimportformsclassInputForm(forms.Form):first_name=forms.CharField(max_length=200)last_name=forms.CharField(max_length=200)roll_number=forms.IntegerField(help_text="Enter 6 digit roll number")password=forms.CharField(widget=forms.PasswordInput())
Note if field defined as auto (auto_now, auto_now_add), it may
not shown in Form
<form action = "" method = "post">{%raw%}{% csrf_token %}{%endraw%}{%raw%}{% for field in form %}{%endraw%}{{field}}{%raw%}{% endfor %}{%endraw%} <input type="submit" value=Submit"></form>
importdatetimefromdjangoimportformsfromdjango.core.exceptionsimportValidationErrorfromdjango.utils.translationimportgettext_lazyas_classRenewBookForm(forms.Form):renewal_date=forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")defclean_renewal_date(self):data=self.cleaned_data['renewal_date']# Check if a date is not in the past.ifdata<datetime.date.today():raiseValidationError(_('Invalid date - renewal in past'))# Check if a date is in the allowed range (+4 weeks from today).ifdata>datetime.date.today()+datetime.timedelta(weeks=4):raiseValidationError(_('Invalid date - renewal more than 4 weeks ahead'))# Remember to always return the cleaned data.returndata
fromdjango.dbimportmodelsclassMovie(models.Model):movie_title=models.CharField(max_length=150)release_year=models.IntegerField()director=models.CharField(max_length=100)movie_poster=models.ImageField(upload_to='images/',None=True)movie_plot=models.TextField()def__str__(self):returnself.movie_title# when print movie object it shows title. Also useful#when movie object is showed in dropdown etc
FieldValidator
django.core.validators
mobile=forms.CharField(label="mobile number"validators=[RegexValidator(r'^159[0-9]+$','mobile start with 159')],)
A disabled field
For read only field set disabled=True, e.g.
mobile = forms.CharField(disabled=True, label='mobile number')
fromdjangoimportformsfrom.modelsimportMovie# Create your forms here.classMovieForm(forms.ModelForm):classMeta:model=Moviefields=('movie_title','release_year','director','movie_poster','movie_plot')
The Meta class is used to change the behavior of the ModelForm .
Within it, specify the model your fields come from and the fields
you want to use from that model.
Key components of Meta class in ModelForm #card
model the data model class
fields: the fields will be shown in the form
widgets: used to generate HTML code that override default
behavior. e.g. inputbox with CSS styling
Explains of Meta class
model The Model class
fields It is strongly recommended that you explicitly set all
fields that should be edited in the form using the fields
attribute. Failure to do so can easily lead to security problems
when a form unexpectedly allows a user to set certain fields,
especially when new fields are added to a model. If those are
not your concerns ~fields = "[[all]{.underline}]{.underline}"
~ can easy your job
exclude Set the exclude attribute of the ModelForm’s inner
Meta class to a list of fields to be excluded from the form.
If you want to apply same attributes for all field, do this
instead by override __init__
classUserModelForm(forms.ModelForm):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)forname,fieldinself.fields.items():field.widget.attrs["class"]=styleifname=="password":field.required=False# Make the password field optionalfield.widget=forms.widgets.PasswordInput(attrs={"class":style})classMeta:model=UserInfofields="__all__"# It can be a list of all fields you want to display# password field can also be setup here# password = forms.CharField(required=False, widget=forms.PasswordInput()) # some field need special attention# can also be put here
Error messages
You can reuse the default error messages. In case the message need
to be customered for specific field
classUserModelForm(forms.ModelForm):confirm_password=forms.CharField(label="please input password again",widget=forms.PasswordInput(render_value=True))def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)forname,fieldinself.fields.items():field.widget.attrs["class"]=styleifname=="password":field.required=False# Make the password field optionalfield.widget=forms.widgets.PasswordInput(attrs={"class":style})classMeta:model=UserInfofields="__all__"
an empyt object (create a new entry) form = UserModelForm()
From a POST request (for parse form submit and save data)
form = userModelForm(request.POST)
From database instance (foir re-edit data)
form = UserModelForm(instance=models.User.objects.filter(id=id).first())
From both POST and database (normally when reedit data when form
submission failed)
form = UserModelForm(request.POST, instance=models.User.objects.filter(id=id).first())
You can either parse the POST request and get all fields, You can
Also do:
form=UserModelForm(request.POST)# POST to form classifform.is_valid():form.save()# save to DBreturnredirect("/user/list/")# invalid data auto refill the form and you can re-send againreturnrender(request,"user_add.html",{"form":form})