Vue+Django REST framework
Using Python 3.6 and Django 2.0.2 (Django-rest-framework) and front-end vue to develop front-end and back-end separated mall website
The project supports Alipay payment (temporarily does not support WeChat payment), supports mobile phone SMS verification code registration, supports third party login. sentry error monitoring system is integrated.
Online demo address: http://vueshop.mtianyan.cn/
github source code address: https://github.com/mtianyan/VueDjangoFrameWorkShop
Content of this section: permission validation of drf
Permission verification of drf
It seems that users have completed the function of adding and deleting collections. But the normal business logic should be that users can only delete their collections.
http://www.django-rest-framework.org/api-guide/permissions/
auth and permission are two things. Auh is used for user authentication and permission is used for permission judgment.
AllowAny: Accessible regardless of permissions.
IsAuthenticated: Determine whether you have logged in
IsAdminUser: Determine whether the user is an administrator. user.is_staff
The first step is to determine whether the user is logged in.
Implementation code:
from rest_framework.permissions import IsAuthenticated permission_classes = (IsAuthenticated,)
User not logged in to access the list of userfav will throw us 401 errors.
Official examples of whether ip is on the whitelist
Implementation code:
from rest_framework import permissions class BlacklistPermission(permissions.BasePermission): """ Global permission check for blacklisted IPs. """ def has_permission(self, request, view): ip_addr = request.META['REMOTE_ADDR'] blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() return not blacklisted
Take the model and do the filtering implementation
- Official example: Is it the owner or is it just readable?
Implementation code:
class IsOwnerOrReadOnly(permissions.BasePermission): """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """ def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True # Instance must have an attribute named `owner`. return obj.owner == request.user
Create new permissions in utils. This is our custom permissions, and paste the IsOwner OrReadOnly above.
This custom permission class inherits our BasePermission. It has a method called has_object_permission, with or without object permissions.
It checks whether the owner of obj we pulled out of the database is equal to request.
This obj is the table in our database, so the owner here should be changed to the foreign key user in our database.
A secure method is one that does not alter the database and always gives everyone access.
Add the custom permission authentication class in views
Implementation code:
from utils.permissions import IsOwnerOrReadOnly permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
This will validate permissions when deleting.
You can't get all the collection relational data. So we need to overload the get_queryset method
Implementation code:
def get_queryset(self): return UserFav.objects.filter(user=self.request.user)
After overloading, the parameter configuration of queryset can be commented out.
In model design. Our str method returns a value of name. This name is probably null.
So report a mistake.
__str__ return non-string(type NoneType)
When we return. Change name to username
When we go to the database and change the userid of the collection relationship to a non-current login user, we will find that we can only view our collection.
When deleting a collection record that does not belong to itself, it will be prompted that it does not exist.
Entering a username password when using other tools can also be used for login, because we configure a variety of auth classes.
token authentication is best configured in view, not globally.
If each request request in the front end is added to our token, the token will expire and the data will not be available when the user visits the goods list page and other pages that do not require token authentication.
Delete'rest_framework. authentication. Session Authentication'from setting s.
Then import and configure in the specific view
Implementation code in user_operation/views.py:
from rest_framework_jwt.authentication import JSONWebTokenAuthentication authentication_classes = (JSONWebTokenAuthentication, )
At this point in our api console and unable to use login to enter userfav, because our class auth does not contain session auth
Implementation code:
from rest_framework.authentication import SessionAuthentication authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
User collection function and vue debugging
Some problems of vue and back-end co-ordination:
Unregistered status, the collection status of goods should be not collected, and login status we need to set up a good interface, dynamic display.
/userfavs/5/ Get details of a collection, where id is the ID of the collection relationship in the data table
In fact, we don't know what Id this item is stored in the database. We want to use the existing interface, and we don't want to pass this ID. If the front-end requests, can you pass goods_id of the current product instead of this id?
The back end finds out whether it has been collected by passing in goods_id and the current user.
When we add RetrieveModel Mixin, we can pass
http://127.0.0.1:8000/userfavs/5/ Get details of a relationship.
Understanding the principles of retrieve
Implementation code:
def retrieve(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data)
Call the get_object function, which is in GenericAPIView in rest_framework/generics.py
Implementation code:
def get_object(self): """ Returns the object the view is displaying. You may want to override this if you need to provide non-standard queryset lookups. Eg if objects are referenced using multiple keyword arguments in the url conf. """ queryset = self.filter_queryset(self.get_queryset()) # Perform the lookup filtering. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field assert lookup_url_kwarg in self.kwargs, ( 'Expected view %s to be called with a URL keyword argument ' 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 'attribute on the view correctly.' % (self.__class__.__name__, lookup_url_kwarg) ) filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} obj = get_object_or_404(queryset, **filter_kwargs) # May raise a permission denied self.check_object_permissions(self.request, obj) return obj
By default, the primary key, i.e. the ID field, is searched based on the ID we passed in. We want it to search not for the field id, but for the field goods. Which fields lookup_field receives is actually configurable.
stay http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview
There is this parameter.
lookup_field = 'pk'
The default value of this field in the apiview is pk, which we can change to goods_id.
Because the actual field name stored by goods in the database table is goods_id
created () { this.productId = this.$route.params.productId; var productId = this.productId if(cookie.getCookie('token')){ getFav(productId).then((response)=> { this.hasFav = true }).catch(function (error) { console.log(error); }); } this.getDetails(); },
When creating in src/views/productDetail/productDetail.vue, the id of the product is obtained first.
Token is found in cookie s, and if there is token, getFav is executed through the product id
//Judging whether to collect or not export const getFav = goodsId => { return axios.get(`${host}/userfavs/`+goodsId+'/') }
If the response state is 200, then we can assign hasfav to true
If hasfav is true.
<a v-if="hasFav" id="fav-btn" class="graybtn" @click="deleteCollect"> <i class="iconfont"> </i>Collected </a> <a v-else class="graybtn" @click="addCollect"> <i class="iconfont"> </i > Collection </a >
If true, v-if displays the collection, clicking in the collection state will execute the deletion of the collection.
The collection is executed by clicking on it when it is not collected.
deleteCollect () { //Delete collection delFav(this.productId).then((response)=> { console.log(response.data); this.hasFav = false }).catch(function (error) { console.log(error); }); },
Deleting collection calls is the delfav interface.
//Cancel collection export const delFav = goodsId => { return axios.delete(`${host}/userfavs/`+goodsId+'/') } //Collection export const addFav = params => { return axios.post(`${host}/userfavs/`, params) }
Adding collection calls is the addFav interface.
Change the host that adds collections, cancels collections, and acquires a collection relationship to a local host. getalllfav will only be implemented in a personal Center
Login's url needs to be changed to localhost (I've changed it before), and the reason for the change is local login encryption.
The key to decryption is that the SECRET_KEY online decryption in setting s will fail.
This key is different every time a project is generated.
If lookup_fields is goods, will it query the relationship of other users'collections?
In fact, lookupfield operations are done in the result of get_queryset. It has been filtered.
Personal centers use auth and permission extensively