-
Notifications
You must be signed in to change notification settings - Fork 0
/
readme
283 lines (211 loc) · 10.8 KB
/
readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# Django ORM
1. to start up a local first thing we need to do `pipenv install` to create virtual environment and install all the app
2. active virtual env , `pipenv shell`
3. check sql connection config, create database in mysql
4. run migration
### Query_set
1. Query_set encalsulate the query, it will only execute when
- we iterate it
- when we convert it into list(query_set)
- when we slice it, or access specific element
2. The reason for doing this, is because we can use queryset to build complex queries, to save the memories
```
query_set = Product.objects.all()
query_set.filter().filter().order_by()
```
3. There are some method we will directly get the query. For example `count = Product.objects.count()` return number
## Retrieve Objects
1. `product = Product.objects.get(pk=1)`
## Filter
1. `keyword=value`
2. `product = Product.objecs.filter(pk=1)`, we filter product based on id
3. We can use lookup type also, `product = Product.objects.filter(unit_price__gt=5)`, we also have `gte, lte, lt`
4. There are some lookups type that require more than 2 valus, `product= Product.objects.range(20, 30)`
5. for more lookup type can refer to Django ORM website
## Q Objects
1. Some we want to execute some complex query like AND, OR, therefore we can use Q object and use the bitwise operator
2. Q objects will encapsulate the keyword argument
3. Example `query_set = Product.objects.filter(Q(title__icontains='coffee') & ~Q(title__icontains='oz'))`
4. `~` represents NOT operator
## F Objects
1. Sometimes, we want to refer to the field, for example
- inventory = price
## Sorting
1. `query_set = Product.objects.order_by('unit_price','-title')`, `-` sign indicates in descending order, we can sort by 2 keywords
2. add `reverse()`, will reverse the order
3. we can get the first object by using `earliest()`, whereas we can get the latest object by using `latest`
## Limiting Results
1. `queryset = Product.objects.all()[:5]`, will return the first 5 objects, `[5:10]`, skipping the first 5 objects, and return subsequent object before 10
## Selecting Field for Query
1. Sometimes, we need to only query specific fields, `queryset = Product.objects.values('id', 'title','collection__title')`, by using values(), instead of getting a bunch of instances, we will get a bunch of dictionary, whereas, `values_list()` will return a bunch of tuples
## Defering Field
1. `queryset = Product.objects.only('id', 'title')`, we will get the product instance which only have id and title field
2. difference between `only` and `values`, which former get the product instances, and the later get dictionary of product list
3. `defer`, we want to query all the field, except some selected filed
## select_related
1. When we want to access the related table data, we need to use `select_related(collection__someOtherField)`
2. we use `select_related` when the other end of relationship has only one object, whereas we use `prefetch_related` when the other end of relationship has many objects8
## Aggregate
1. `result = product.objects.aggregate(count=Count('id'), min_price=Min('unit_price'))`
## Anotate
1. Need to understand the query expression object
## Database Functions
1. `queryset = Customer.objects.annotate(full_name=Concat('first_name',' ', 'last_name'))`
2. `queryset = Customer.objects.annnotate(full_name=Func(F('first_name'), Value(' '), F('last_name'), funtion='CONCAT'))`
## Generic Relationships Query
1. First, we need to query the content type id based on the model, in this case we need to find the contenttype id of Product Model in database table (django_content_type)
2. After that, we can query the generic item based on the content type, in this case we want to find product type taggedItem which product id is 1.
## Create Objects
1. ```
collection = Collection()
collection.name = 'Video Games'
collection.featured_product = Product(pk=1)
collection.save()
```
```
collection = Collection.objects.create(name='a', featured_product_id=1)
collection.id
// you can retrieve the collection id after creation
```
2. Code above demonstrated how to create a new object
## Update Objects
1. ```
Collection.objects.filter(pk=11).update(featured_product=None)
```
## Transaction
1. Sometimes, we want the code to run in on times, if one of the code is error, the previous code will roll back.
```
from django.db import transaction
// @transaction.atomic()
//this will wrap the entire function, in this transaction
def say_hello(request):
#...
// this return the context manager
with transaction.atomic():
order = Order()
order.customer_id = 1
order.save()
item = OrderItem()
item.order = order
item.product_id = 1
item.quantity = 1
item.unit_price = 10
item.save()
```
2. When there is error inside the code, the whole code wont excuted and will return an error
## DjangoModelAdmin
1. We can see what can django admin do by searching ModelAdmin options
## AdminSite - Providing Links to Other Pages
1. In this case, we want to get the admin page of Product, in this case, we can use reverse method
2. `reverse('admin:app_model_page')`, in this case, we use `reverse('admin:store_collection_changelist')`
3. for the url, we need to add the querystring '?' in order to go into specific page
## Install DjangoRestFramework
1. `pipenv install djangorestframework`
## Serializer
1. use to convert python model into dictionary
## Serialzing relationship
1. to serialize the select_related object, in this case we can get all the collection primary key
```
collection = serializers.PrimaryKeyRelatedField(
queryset = Collection.objects.all()
)
```
## Model Serializer
1. In order to keep code dry, we need to use model serializer, to avoid repeating validation
2. If we want to customize the serializer, we can use the method we used as before
## Deserializer
1. Deserializer - opposite way of serializer, we use when we create object
2. Before sending request, we should do data validation
3. if valid, we will save the validated data
## ClassBasedView
1. provide cleaner code, and more reuse ability
## GenericView
1. ListCreateAPIView
2. In this case, we no need to use method as we no need to implement logic for the queryset and serializer
For example, when we want to some user to use different queryset
```
def get_queryset(self):
return Product.objects.select_related('collection').all()
def get_serializer(self, *args, **kwargs):
return ProductSerializer
```
## Router
## Custom Generic View
1. In this case, we need to keep the delete method as we want to keep the custom delete message
## ViewSet
1. As you can see the queryset and serializer_class are duplicated in generic view, in order to solve this problem, we can use ModelViewSet
2. We can also inherit `ReadOnlyModelViewSet`, which we can only execute readOnly method
## Pagination
1. There is various type of pagination provided by restframework, it will show out next, previous
2. Type of Pagination can refer https://www.django-rest-framework.org/api-guide/pagination/
3. We can set default Pagination in settings.py
```
REST_FRAMEWORK = {
'COERCE_DECIMAL_TO_STRING': False,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
```
## Redefine our Cart Model
1. In CartItem Model, we need to make sure that there is only one type of product inside one cart
2. Therefore, we can do it by adding a meta class and define inside the Meta class
```
class Meta:
unique_together = [['cart', 'product']]
```
## Customizing the UserModel
1. There is 2 types of customzing a UserModel, Inheritance and Composition
2. Inheritance - for storing attributes related to authentication
3. Composition - for storing non-auth related attributes
## Adding Authentication Endpoints
## Register User
1. Inside settings.py, there is AUTH_PASSWORD_VALIATORS, there are a bunch of validators, for password
## Create Profile
1. We can make it 2 seperate endpoints, 1. create account 2. create profile
2. 2 seperate calls, more reusable, easier to maintain
## Logging In
1. 'refresh_token_lifetime' by default is 1 day, and access token by default is 5 minutes
## Getting Current User Profile (customise action)
1. new endpoint 'store/customer/me'
2. we create a new method under CustomerViewSet, basically, the mixins that we inherit for the viewset are actually an action
```
@action(detail=FALSE)
def me(self, request):
```
3. detail indicates whether we want it in list view or detail view
4. In this case, we want to get the user id, how to get it? We have the middleware that will help to get the user information from the request, if the user is not logged in, it will be set as an anonymousUser instance
## Permissions
1. https://www.django-rest-framework.org/api-guide/permissions/
2. 2 ways to implement, first we can set it in global way , in settings.py
```
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
```
3. 2nd way, we can do permissions in particular ViewSet, `permission_classes = [IsAuthenticated]`,
4. If we want to customise the permission, we can create a method too, `def get_permissions(self)`
## Custom Permissions
1. For product viewset, we want only admin can access create method, and andmin and others can only access read only method
## Model Permissions
1. In order to access the viewset, the user must be authenticated and also have the relevant model permissions
2. previously, kaixuan user is inside the customer service group
## Model Permissions
1. We create a customer history, and it can only be used for the particular custome
2. So we need to create an action named history and receive pk, detail is True
## Creating an Order
1. Everyone can create an order, we only need to create an order id, and post the cart id
## Create Order Items
1. We need to get the cartItem from the cart id, and for each cart item, we need to create an order item and save it into database, lastly we want to delete the cart
## Return Created Order
1. When create order, we serialize the request data, and save it to the database, after that, we need to deserialize the data, the data and return as response
2. for the get_serializer_context, it is used for mixins, in this case, we customize the create, so it is not so usefult so this
## Data Validation
1. In this case, there is 2 scenario, invalid cartId, empty cart
## Signals
1. In django, we use signals to decouple or apps and prevent them from stepping on each other toes
2. pre_save, before the model is saved
3. post_save, after a model is saved
4. pre_delete, post_delete
5. For example, CORE - Create User, Listen to User..post_save, STORE - create customer
## Custom Signals
1. When we successfully create an order, we can fire a signal like order created, with this other app interested in this event can subscribe to this signal and get notified