热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Django天天生鲜项目04】搜索(搜索引擎、分词包的使用)、购物车

关键:全文检索框架、搜索引擎、分词包、Ajax请求的使用仅作为个人笔记!目录1.搜索1.1.haystack框架和whoosh引擎安装1

关键:全文检索框架搜索引擎分词包、Ajax请求的使用...

仅作为个人笔记!

目录

1.搜索

1.1. haystack框架和whoosh引擎安装

1.2.索引文件的生成

1.3.全文检索的使用

1.4.更改分词方式 

2.购物车

2.3.购物车前端Ajax请求



 


1.搜索

在首页、详情页和列表页中,都有搜索框,如何实现搜索呢?

关键:全文检索框架搜索引擎、分词包的使用、

 

全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理。

 

搜索引擎:可以对表中的某些字段进行关键词分析,建立关键词对应的索引数据;

全文检索框架:帮助用户使用搜索引擎;

本处使用 haystack框架 和 whoosh引擎 。

 


1.1. haystack框架和whoosh引擎安装


  • haystack:全文检索的框架,支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎,点击查看官方网站。
  • whoosh:纯Python编写的全文搜索引擎,虽然性能比不上sphinx、xapian、Elasticsearc等,但是无二进制包,程序不会莫名其妙的崩溃,对于小型的站点,whoosh已经足够使用,点击查看whoosh文档。
  • jieba:一款免费的中文分词包,如果觉得不好用可以使用一些收费产品。

 

(1)在虚拟环境中依次安装需要的包

pip install django-haystack
pip install whoosh
pip install jieba

(2)在settings.py文件中注册应用haystack,并做配置

# 注册
INSTALLED_APPS = (...'haystack',
)...
# 全文检索框架配置
HAYSTACK_CONNECTIONS = {'default': {# 使用whoosh引擎(配置路径)'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',# 'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine', # 配置好jieba中文分词包后用这个# 设置索引文件生成的路径'PATH': os.path.join(BASE_DIR, 'whoosh_index'),}
}# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 指定搜索结果每页显示的条数
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 2

 


1.2.索引文件的生成

要搜索商品表中的数据,就需要搜索引擎根据表的某些字段来建立关键词对应的索引数据。然后才能让搜索引擎来搜索对应的数据。

根据模型类(如:GoodsSKU)的表的数据生成索引的数据。


  • 根据模型类新建索引类

    在goods应用目录下新建一个search_indexes.py文件(文件名固定),在其中定义一个商品索引类。

    from haystack import indexes
    # 导入你的模型类
    from goods.models import GoodsSKU# 指定对于某个类的某些数据建立索引
    # 建议的索引类名格式:模型类名+Index
    class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):# 索引字段 use_template=True:指定根据表中的哪些字段建立索引文件,这个'指定说明'放在一个文件中text = indexes.CharField(document=True, use_template=True)def get_model(self):# 返回你的模型类return GoodsSKU# 建立索引的数据def index_queryset(self, using=None):return self.get_model().objects.all()

     

  • 在文件中,指定根据表中的哪些字段建立索引文件 

    templates下面新建目录 search/indexes/模型类所在的应用名 (如:search/indexes/goods),在此目录下面新建一个文件 模型类名小写_text.txt(如:goodssku_text.txt)并编辑内容如下:

    # 指定根据表中的哪些字段建立索引数据
    {{ object.name }} # 根据商品的名称建立索引
    {{ object.desc }} # 根据商品的简介建立索引
    {{ object.goods.detail }} # 根据商品的详情建立索引

     

  • 使用命令生成索引文件。

    在虚拟环境中,cd到项目的路径,执行

    python manage.py rebuild_index

    就会按照配置,生成目录whoosh_index,并在目录下生成索引数据。

 


1.3.全文检索的使用

(1)搜索框的前端,点击进行提交时,会通过 haystack 搜索数据。

(2)action提交后的处理应该让搜索引擎来完成,会通过 haystack 搜索数据,故在项目的url中配置。注意提交的地址应该和配置的url一致。

urlpatterns = [... path('search', include('haystack.urls')), # 全文检索框架
]

(3)全文检索结果。

搜索出结果后,haystack会把搜索出的结果传递给templates/search目录下的search.html(没有这个文件可以先自己建),传递的上下文包括:


  • query:搜索关键字
  • page:当前页的page对象 –>遍历page对象,获取到的是SearchResult类的实例对象,对象的属性object才是模型类的对象。
  • paginator:分页paginator对象

通过HAYSTACK_SEARCH_RESULTS_PER_PAGE 可以控制每页显示数量。

以下可以快速的查看搜索结果:

......

搜索的关键字:{{ query }}

当前页的Page对象:{{ page }}

    {% for item in page %}
  • {{ item.object }}
  • {% endfor %}

分页paginator对象:{{ paginator }}


...浏览器显示结果如下:
搜索的关键字:草莓
当前页的Page对象:
草莓 500g
分页paginator对象:

项目中templates/search目录下的search.html关键代码:

    {% for item in page %}
  • {{ item.object.name }}

    ¥{{ item.object.price }}{{ item.object.price}}/{{ item.object.unite }}
  • {% endfor %}
{% if page.has_previous %} <上一页 {% endif %}{% for pindex in paginater.page_range %}{% if pindex &#61;&#61; page.number %}{{ pindex }}{% else %}{{ pindex }}{% endif %}{% endfor %}{% if page.has_next %}下一页>{% endif %}

 


1.4.更改分词方式 

默认的引擎在对中文进行关键词分析的时候&#xff0c;可能支持的不是很好。可以使用jieba这个分词包&#xff0c;对中文的处理更好。

&#xff08;1&#xff09;安装jieba分词模块&#xff1a;


pip install jieba


&#xff08;2&#xff09;更改whoosh引擎的默认词语分析类


  • 找到虚拟环境下的haystack目录&#xff0c;比如&#xff1a;

    /home/python/.virtualenvs/dailyfresh/lib/python3.5/site-packages/haystack/backends 
     
  • 在haystack目录中创建ChineseAnalyzer.py文件
     

    import jieba
    from whoosh.analysis import Tokenizer, Tokenclass ChineseTokenizer(Tokenizer):def __call__(self, value, positions&#61;False, chars&#61;False,keeporiginal&#61;False, removestops&#61;True,start_pos&#61;0, start_char&#61;0, mode&#61;&#39;&#39;, **kwargs):t &#61; Token(positions, chars, removestops&#61;removestops, mode&#61;mode, **kwargs)seglist &#61; jieba.cut(value, cut_all&#61;True) # 关键是这句for w in seglist:t.original &#61; t.text &#61; wt.boost &#61; 1.0if positions:t.pos &#61; start_pos &#43; value.find(w)if chars:t.startchar &#61; start_char &#43; value.find(w)t.endchar &#61; start_char &#43; value.find(w) &#43; len(w)yield tdef ChineseAnalyzer():return ChineseTokenizer()

     

  • 在haystack目录&#xff0c;复制whoosh_backend.py文件&#xff0c;改为如下名称&#xff0c;以便用来更改词语分析类&#xff1a;

    whoosh_cn_backend.py
     
  • 打开复制出来的新文件&#xff0c;引入中文分析类&#xff0c;内部采用jieba分词、更改词语分析类

    ...
    from .ChineseAnalyzer import ChineseAnalyzer
    ...# 查找词语分析类&#xff1a;analyzer&#61;StemmingAnalyzer()
    # 并改为&#xff1a; analyzer&#61;ChineseAnalyzer()
    # 如下&#xff1a;
    ...schema_fields[field_class.index_fieldname] &#61; TEXT(stored&#61;True, analyzer&#61;ChineseAnalyzer(), field_boost&#61;field_class.b oost, sortable&#61;True)
    ...

  • 修改settings.py文件中的配置项

    # 全文检索框架配置
    HAYSTACK_CONNECTIONS &#61; {&#39;default&#39;: {# 使用whoosh引擎(配置路径)# &#39;ENGINE&#39;: &#39;haystack.backends.whoosh_backend.WhooshEngine&#39;,&#39;ENGINE&#39;: &#39;haystack.backends.whoosh_cn_backend.WhooshEngine&#39;, # 配置好jieba中文分词包后用这个# 设置索引文件生成的路径&#39;PATH&#39;: os.path.join(BASE_DIR, &#39;whoosh_index&#39;),}
    }# 当添加、修改、删除数据时&#xff0c;自动生成索引
    HAYSTACK_SIGNAL_PROCESSOR &#61; &#39;haystack.signals.RealtimeSignalProcessor&#39;

     

  • 重新生成索引文件&#xff1a;在项目所在目录使用命令

    python manage.py rebuild_index

     

这样&#xff0c;使用新的分词类后&#xff0c;即使是商品详情中包含的词语&#xff0c;也能搜索到结果。

 


2.购物车

要完成购物车功能&#xff0c;要确定&#xff08;尤其是前后端分开开发时&#xff09;&#xff1a;


  • 前端是否传递数据&#xff0c;传递什么数据&#xff0c;什么格式
  • 前端访问的方式&#xff08;get  post&#xff09;
  • 返回给前端的什么数据&#xff0c;什么格式

 


2.1.商品详情页js代码

在商品的详情页&#xff0c;包含购买商品的数量、加入购物车等功能。

在js中&#xff0c;绑定相关按钮等的点击事件进行处理。比如增减商品数、计算总价格等

// 更新总价 update_goods_amount()// 计算商品的总价function update_goods_amount() {// 获取商品的单价和数量price &#61; $(&#39;.show_pirze&#39;).children(&#39;em&#39;).text()count &#61; $(&#39;.num_show&#39;).val()// 计算商品的总价price &#61; parseFloat(price)count &#61; parseInt(count)amount &#61; price*count// 设置商品的总价,设置两位小数$(&#39;.total&#39;).children(&#39;em&#39;).text(amount.toFixed(2)&#43;&#39;元&#39;)}//增商品的数量(减同理$(&#39;.add&#39;).click(function () {// 获取商品数目并&#43;1count &#61; $(&#39;.num_show&#39;).val()count &#61; parseInt(count)&#43;parseInt(&#39;1&#39;)// 重新设置商品的数目$(&#39;.num_show&#39;).val(count)update_goods_amount()})...// 手动输入商品的数量$(&#39;.num_show&#39;).blur(function () {count &#61; $(this).val()// 校验count是否合法(能否转为数字、去除空格...)if (isNaN(count) || count.trim().length&#61;&#61;0 || parseInt(count) <&#61;0){count &#61; 1}$(this).val(parseInt(count))update_goods_amount()})

 


注&#xff1a;点击事件中&#xff0c;若加1的操作结果并不对&#xff0c;检查代码也没问题。使用alert输出后发现被多次执行了。原来是出现了累加绑定的问题。解决办法可以参考这个博文试试&#xff1a;https://blog.csdn.net/GSCurry/article/details/71857127。

  • 使用前先解除绑定&#xff1a;$("#id").unbind("click")
  • 使用jQuery的one()方法。该方法为元素绑定一个一次性的事件处理函数&#xff0c;这个事件处理函数只会被执行一次。
  • 配合off()方法解除绑定。该方法为元素绑定一个的事件处理函数&#xff0c;再次给改元素添加相同事件时不会累加绑定。

 


2.2.购物车添加后台视图


购物车设计

是否传递数据、什么格式什么数据&#xff1f;

访问方式get? post?

返回给前端什么格式什么数据&#xff1f;

redis存储购物车记录&#xff1a;

  • 用户点击加入购物车时需要添加购物车记录&#xff08;添加&#xff09;&#xff1b;
  • 使用购物车中数据和访问购物车页面时需要获取购物车记录&#xff08;获取&#xff09;&#xff1b;
  • 存储购物车记录的格式&#xff1a;一个用户的购物车记录用一条数据保存&#xff0c;用hash类型&#xff08;属性&#xff1a;值&#xff0c;&#39;cart_用户id&#39;:{&#39;sku_id1&#39;:商品数目, &#39;sku_id2&#39;:商品数目, ...}&#xff09;记录skuid和数量&#xff1b;

在前端点击加入购物车之后&#xff0c;通常页面的整体是不进行刷新操作的。所以采用的方式如下


  • 采用ajax 的 post请求
  • 前端需要传递的参数:商品id(sku_id)、 商品数量(count)

附&#xff1a;传参的几种方式

  • get传参&#xff1a;cart/add?sku_id&#61;1?count&#61;3 &#xff1b;值涉及获取&#xff0c;可采用get&#xff1b;
  • post传参&#xff1a;参数会放在一个字典 {&#39;sku_id&#39;:1, &#39;count&#39;:3 } &#xff1b;若涉及到数据的修改&#xff08;增删改&#xff09;,采用post &#xff1b;
  • url传参&#xff1a;url配置时捕获参数&#xff1b;

 

cart/view.py中相关视图

...
# /cart/add
class CartAddView(View):"""购物车记录添加"""def post(self, request):user &#61; request.userif not user.is_authenticated:return JsonResponse({&#39;res&#39;: 0, &#39;errmsg&#39;: &#39;请先登录&#39;})# 接收数据sku_id &#61; request.POST.get(&#39;sku_id&#39;)count &#61; request.POST.get(&#39;count&#39;)if not all([sku_id, count]):return JsonResponse({&#39;res&#39;: 1, &#39;errmsg&#39;: &#39;数据不完整&#39;})# 校验添加的商品数量try:count &#61; int(count)except Exception as e:return JsonResponse({&#39;res&#39;: 2, &#39;errmsg&#39;: &#39;商品数目出错&#39;})try:sku &#61; GoodsSKU.objects.get(id&#61;sku_id)except GoodsSKU.DoesNotExist:return JsonResponse({&#39;res&#39;: 3, &#39;errmsg&#39;: &#39;商品不存在&#39;})# 业务处理:添加购物车记录(已经有的累加、没有的添加)conn &#61; get_redis_connection(&#39;default&#39;)cart_key &#61; &#39;cart_%d&#39; % user.id# 先尝试获取sku_id的值 : hget cart_key 属性# 如果sku_id在hash中不存在&#xff0c;hget会返回Nonecart_count &#61; conn.hget(cart_key, sku_id)if cart_count:# 累加购物车中商品的数目count &#43;&#61; int(cart_count)# 校验商品的库存if count > sku.stock:return JsonResponse({&#39;res&#39;: 4, &#39;errmsg&#39;: &#39;商品库存不足&#39;})# 设置hash中sku_id对应的值# hset:如果sku_id已经存在&#xff0c;更新数据&#xff0c; 如果sku_id不存在&#xff0c;添加数据conn.hset(cart_key, sku_id, count)# 计算用户购物车商品的条目数total_count &#61; conn.hlen(cart_key)# 返回应答return JsonResponse({&#39;res&#39;:5, &#39;total_count&#39;:total_count, &#39;message&#39;:&#39;添加成功&#39;})

 

 


2.3.购物车前端Ajax请求

购物车记录的添加在Ajax中提交&#xff0c;在刚刚的视图中进行处理后返回。


注意&#xff0c;如果是表单post提交&#xff0c;csrf验证比较好处理&#xff0c;加上&#xff5b;% csrf_token %&#xff5d;即可Ajax提交怎么处理csrf验证呢&#xff1f;

&#xff08;1&#xff09;在前端同加上&#xff5b;% csrf_token %&#xff5d;&#xff1b;

&#xff08;2&#xff09;访问页面&#xff0c;然后查看源代码&#xff0c;发现对应的隐藏域&#xff0c;类似这样 &#xff1b;

&#xff08;3&#xff09;在Ajax的js中&#xff0c;获取它的值&#xff0c;并加入到要传递的参数中

csrf &#61; $(&#39;input[name&#61;"csrfmiddlewaretoken"]&#39;).val()
params &#61; {&#39;sku_id&#39;:sku_id, &#39;count&#39;:count, &#39;csrfmiddlewaretoken&#39;:csrf}

这样&#xff0c;就可以通过验证。


// 获取add_cart div元素左上角的坐标var $add_x &#61; $(&#39;#add_cart&#39;).offset().top;var $add_y &#61; $(&#39;#add_cart&#39;).offset().left;// 获取show_count div元素左上角的坐标var $to_x &#61; $(&#39;#show_count&#39;).offset().top;var $to_y &#61; $(&#39;#show_count&#39;).offset().left;$(&#39;#add_cart&#39;).click(function(){// 获取商品的id和数量sku_id &#61; $(this).attr(&#39;sku_id&#39;) // 获取自定义属性用attrcount &#61; $(&#39;.num_show&#39;).val()// 获取csrf隐藏域csrf &#61; $(&#39;input[name&#61;"csrfmiddlewaretoken"]&#39;).val()params &#61; {&#39;sku_id&#39;:sku_id, &#39;count&#39;:count, &#39;csrfmiddlewaretoken&#39;:csrf}// 发起ajax post请求&#xff0c;访问/cart/add, 传递参数$.post(&#39;/cart/add&#39;, params, function (data) {if (data.res &#61;&#61; 5){// 添加成功,并显示动画$(".add_jump").css({&#39;left&#39;:$add_y&#43;80,&#39;top&#39;:$add_x&#43;10,&#39;display&#39;:&#39;block&#39;})$(".add_jump").stop().animate({&#39;left&#39;: $to_y&#43;7,&#39;top&#39;: $to_x&#43;7},"fast", function() {$(".add_jump").fadeOut(&#39;fast&#39;,function(){// 设置用户购物车中商品的条目数$(&#39;#show_count&#39;).html(data.total_count);});});}else {// 添加失败alert(data.errmsg)}})})

2.4.购物车页面显示

用一个独立的页面来显示购物车。

相关基本视图如下&#xff1a;

# /cart/
class CartInfoView(LoginRequiredMixin, View):"""购物车页面显示"""def get(self, request):"""显示"""# 获取登录的用户user &#61; request.user# 获取用户购物车中商品的信息(保存在redis)conn &#61; get_redis_connection(&#39;default&#39;)cart_key &#61; &#39;cart_%d&#39; % user.id# 记录的格式&#xff1a;{&#39;商品id&#39;:商品数量, ...}cart_dict &#61; conn.hgetall(cart_key)skus &#61; []# 保存用户购物车中商品的总数目和总价格total_count &#61; 0total_price &#61; 0# 遍历获取商品的信息for sku_id, count in cart_dict.items():# 根据商品的id获取商品的信息sku &#61; GoodsSKU.objects.get(id&#61;sku_id)# 计算商品的小计amount &#61; sku.price * int(count)# 动态给sku对象增加一个属性amount, 保存商品的小计sku.amount &#61; amount# 动态给sku对象增加一个属性count, 保存购物车中对应商品的数量sku.count &#61; int(count) # 注意转为int# 添加skus.append(sku)# 累加计算商品的总数目和总价格total_count &#43;&#61; int(count)total_price &#43;&#61; amount# 组织上下文context &#61; {&#39;total_count&#39;: total_count,&#39;total_price&#39;: total_price,&#39;skus&#39;: skus}# 使用模板return render(request, &#39;cart.html&#39;, context)

 


购物车商品全选

使用js实现购物车页面显示的全选、选部分商品时相应的处理。在cart.html中添加js&#xff0c;改变相应的checkbox的事件。


JQuery选择器参考&#xff1a;https://www.w3school.com.cn/jquery/jquery_ref_selectors.asp、:checkbox、:checked、



 


购物车记录更新

购物车页面中&#xff0c;可以对数量进行增减等操作。采用Ajax post请求提交给后台&#xff0c;传递的参数:商品的id(sku_id)。在后台的视图中进行处理。

相关视图跟基本视图差不多&#xff08;校验登录、接收数据、检验数据、业务处理、返回json...&#xff09;&#xff0c;注意Ajax返回值。前端购物车商品数量的增加的Ajax如下&#xff0c;减少的类似&#xff1a; 

&#xff08;注意&#xff1a;默认发起的ajax请求都是异步的&#xff0c;不会等回调函数执行&#xff0c;需要时要先设置ajax请求为同步&#xff0c;再设置回异步&#xff09;

// 计算商品的小计function update_goods_amount(sku_ul) {count &#61; sku_ul.find(&#39;.num_show&#39;).val()price &#61; sku_ul.children(&#39;.col05&#39;).text()amount &#61; parseInt(count)*parseFloat(price)// 设置商品的小计sku_ul.children(&#39;.col07&#39;).text(amount.toFixed(2)&#43;&#39;元&#39;)}
...// 更新购物车中商品的数量error_update &#61; falsetotal &#61; 0function update_remote_cart_info(sku_id, count){csrf &#61; $(&#39;input[name&#61;"csrfmiddlewaretoken"]&#39;).val()//组织参数params &#61; {&#39;sku_id&#39;: sku_id, &#39;count&#39;: count, &#39;csrfmiddlewaretoken&#39;: csrf}// 设置ajax请求为同步$.ajaxSettings.async &#61; false// 发起Ajax post请求&#xff0c;访问/cart/update, 传递参数:sku_id count// 注意&#xff1a;默认发起的ajax请求都是异步的&#xff0c;不会等回调函数执行&#xff0c;需要时要先设置ajax请求为同步&#xff0c;再设置回异步$.post(&#39;/cart/update&#39;, params, function (data) {if(data.res &#61;&#61; 5){// 更新成功error_update &#61; falsetotal &#61; data.total_count}else{error_update &#61; truealert(data.errmsg)}})// 回调函数执行结束&#xff0c;设置ajax请求为异步$.ajaxSettings.async &#61; true}// 购物车商品数量的增加$(&#39;.add&#39;).click(function () {// 获取商品的id和商品的数量sku_id &#61; $(this).next().attr(&#39;sku_id&#39;)count &#61; $(this).next().val()count &#61; parseInt(count)&#43;1// 更新购物车记录update_remote_cart_info(sku_id, count)// 判断更新是否成功if(error_update &#61;&#61; false){// 重新设置商品的数目$(this).next().val(count)// 计算商品的小计update_goods_amount($(this).parents(&#39;ul&#39;))// 获取商品对应的checkbox的选中状态&#xff0c;如果被选中&#xff0c;更新页面信息is_checked &#61; $(this).parents(&#39;ul&#39;).find(&#39;:checkbox&#39;).prop(&#39;checked&#39;)if (is_checked){// 更新页面信息update_page_info()}// 更新页面上购物车商品的总件数$(&#39;.total_count&#39;).children(&#39;em&#39;).text(total)}})// 购物车商品数量的减少......// 记录用户输入之前商品的数量pre_count &#61; 0$(&#39;.num_show&#39;).focus(function () {pre_count &#61; $(this).val()})// 手动输入购物车中的商品数量$(&#39;.num_show&#39;).blur(function () {sku_id &#61; $(this).attr(&#39;sku_id&#39;)count &#61; $(this).val()if (isNaN(count) || count.trim().length&#61;&#61;0 || parseInt(count)<&#61;0){// 设置商品的数目为用户输入之前的数目$(this).val(pre_count)return}update_remote_cart_info(sku_id, count)if(error_update &#61;&#61; false){$(this).val(count)update_goods_amount($(this).parents(&#39;ul&#39;))// 获取商品对应的checkbox的选中状态&#xff0c;如果被选中&#xff0c;更新页面信息is_checked &#61; $(this).parents(&#39;ul&#39;).find(&#39;:checkbox&#39;).prop(&#39;checked&#39;)if (is_checked){update_page_info()}$(&#39;.total_count&#39;).children(&#39;em&#39;).text(total)}else {// 设置商品的数目为用户输入之前的数目$(this).val(pre_count)}})

 


购物车记录删除 

点击删除将购物车商品删除。

同样采用ajax post请求、 前端需要传递的参数:商品的id(sku_id)。

view.py视图关键code&#xff1a;

...# 业务处理:删除购物车记录conn &#61; get_redis_connection(&#39;default&#39;)cart_key &#61; &#39;cart_%d&#39; % user.id# 删除 hdelconn.hdel(cart_key, sku_id)。。。

cart.html提交的相关Ajax请求&#xff0c;关键是回调成功后&#xff0c;执行.remove()&#xff1a;

// 删除购物车中的记录$(&#39;.cart_list_td&#39;).children(&#39;.col08&#39;).children(&#39;a&#39;).click(function () {// 获取对应商品的idsku_id &#61; $(this).parents(&#39;ul&#39;).find(&#39;.num_show&#39;).attr(&#39;sku_id&#39;)csrf &#61; $(&#39;input[name&#61;"csrfmiddlewaretoken"]&#39;).val()params &#61; {&#39;sku_id&#39;:sku_id, &#39;csrfmiddlewaretoken&#39;:csrf}// 获取商品所在的ul元素sku_ul &#61; $(this).parents(&#39;ul&#39;)// 发起ajax post请求&#xff0c; 访问/cart/delete, 传递参数:sku_id$.post(&#39;/cart/delete&#39;, params, function (data) {if (data.res &#61;&#61; 3){// 删除成功&#xff0c;移除页面上商品所在的ul元素sku_ul.remove()// 获取sku_ul中商品的选中状态is_checked &#61; sku_ul.find(&#39;:checkbox&#39;).prop(&#39;checked&#39;)if (is_checked){update_page_info()}// 重新设置页面上购物车中商品的总件数$(&#39;.total_count&#39;).children(&#39;em&#39;).text(data.total_count)}else{alert(data.errmsg)}})})

 

01 框架、数据表设计、项目框架笔记

02 注册、登录、用户中心 &#xff08;itsdangerous模块加密、celery异步、 Django 的验证系统、redis作为缓存等&#xff09;

03 FastDFS文件存储-首页-详情页-列表页

04 搜索&#xff08;搜索引擎、分词包的使用&#xff09;、购物车

05 订单&#xff08;Mysql事务、并发处理、支付宝支付、评论&#xff09;

06 项目部署&#xff08;uwsgi服务器、Nginx服务器&#xff09;

仅作为个人笔记 &#xff01;

-----end-----

 

 


推荐阅读
author-avatar
愛攝影的新胖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有