Skip to content

kaixuannnn/storefront2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

# 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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published