做一個Django項目(2.4、商品和首頁廣告模塊並對接fastdfs用於保存文件)

  1. 創建子應用
    1. goods 商品模塊
      python ../../manage.py startapp goods

       

    2. contents 首頁廣告模塊
      python ../../manage.py startapp contents
  2. 模型類創建並遷移
    1. goods模型類
      from django.db import models
      
      from md.utils.models import BaseModel
      # Create your models here.
      
      
      class GoodsCategory(BaseModel):
          """
          商品類別
          """
          name = models.CharField(max_length=10, verbose_name='名稱')
          parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父類別')
      
          class Meta:
              db_table = 'tb_goods_category'
              verbose_name = '商品類別'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.name
      
      
      class GoodsChannel(BaseModel):
          """
          商品頻道
          """
          group_id = models.IntegerField(verbose_name='組號')
          category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, verbose_name='頂級商品類別')
          url = models.CharField(max_length=50, verbose_name='頻道頁面鏈接')
          sequence = models.IntegerField(verbose_name='組內順序')
      
          class Meta:
              db_table = 'tb_goods_channel'
              verbose_name = '商品頻道'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.category.name
      
      
      class Brand(BaseModel):
          """
          品牌
          """
          name = models.CharField(max_length=20, verbose_name='名稱')
          logo = models.ImageField(verbose_name='Logo圖片')
          first_letter = models.CharField(max_length=1, verbose_name='品牌首字母')
      
          class Meta:
              db_table = 'tb_brand'
              verbose_name = '品牌'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.name
      
      
      class Goods(BaseModel):
          """
          商品SPU
          """
          name = models.CharField(max_length=50, verbose_name='名稱')
          brand = models.ForeignKey(Brand, on_delete=models.PROTECT, verbose_name='品牌')
          category1 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat1_goods', verbose_name='一級類別')
          category2 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat2_goods', verbose_name='二級類別')
          category3 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat3_goods', verbose_name='三級類別')
          sales = models.IntegerField(default=0, verbose_name='銷量')
          comments = models.IntegerField(default=0, verbose_name='評價數')
      
          class Meta:
              db_table = 'tb_goods'
              verbose_name = '商品'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.name
      
      
      class GoodsSpecification(BaseModel):
          """
          商品規格
          """
          goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品')
          name = models.CharField(max_length=20, verbose_name='規格名稱')
      
          class Meta:
              db_table = 'tb_goods_specification'
              verbose_name = '商品規格'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return '%s: %s' % (self.goods.name, self.name)
      
      
      class SpecificationOption(BaseModel):
          """
          規格選項
          """
          spec = models.ForeignKey(GoodsSpecification, on_delete=models.CASCADE, verbose_name='規格')
          value = models.CharField(max_length=20, verbose_name='選項值')
      
          class Meta:
              db_table = 'tb_specification_option'
              verbose_name = '規格選項'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return '%s - %s' % (self.spec, self.value)
      
      
      class SKU(BaseModel):
          """
          商品SKU
          """
          name = models.CharField(max_length=50, verbose_name='名稱')
          caption = models.CharField(max_length=100, verbose_name='副標題')
          goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品')
          category = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, verbose_name='從屬類別')
          price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='單價')
          cost_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='進價')
          market_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='市場價')
          stock = models.IntegerField(default=0, verbose_name='庫存')
          sales = models.IntegerField(default=0, verbose_name='銷量')
          comments = models.IntegerField(default=0, verbose_name='評價數')
          is_launched = models.BooleanField(default=True, verbose_name='是否上架銷售')
          default_image_url = models.CharField(max_length=200, default='', null=True, blank=True, verbose_name='默認圖片')
      
          class Meta:
              db_table = 'tb_sku'
              verbose_name = '商品SKU'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return '%s: %s' % (self.id, self.name)
      
      
      class SKUImage(BaseModel):
          """
          SKU圖片
          """
          sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name='sku')
          image = models.ImageField(verbose_name='圖片')
      
          class Meta:
              db_table = 'tb_sku_image'
              verbose_name = 'SKU圖片'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return '%s %s' % (self.sku.name, self.id)
      
      
      class SKUSpecification(BaseModel):
          """
          SKU具體規格
          """
          sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name='sku')
          spec = models.ForeignKey(GoodsSpecification, on_delete=models.PROTECT, verbose_name='規格名稱')
          option = models.ForeignKey(SpecificationOption, on_delete=models.PROTECT, verbose_name='規格值')
      
          class Meta:
              db_table = 'tb_sku_specification'
              verbose_name = 'SKU規格'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return '%s: %s - %s' % (self.sku, self.spec.name, self.option.value)
      

       

    2. contents模型類
      from django.db import models
      
      from md.utils.models import BaseModel
      # Create your models here.
      
      
      class ContentCategory(BaseModel):
          """
          廣告內容類別
          """
          name = models.CharField(max_length=50, verbose_name='名稱')
          key = models.CharField(max_length=50, verbose_name='類別鍵名')
      
          class Meta:
              db_table = 'tb_content_category'
              verbose_name = '廣告內容類別'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.name
      
      
      class Content(BaseModel):
          """
          廣告內容
          """
          category = models.ForeignKey(ContentCategory, on_delete=models.PROTECT, verbose_name='類別')
          title = models.CharField(max_length=100, verbose_name='標題')
          url = models.CharField(max_length=300, verbose_name='內容鏈接')
          image = models.ImageField(null=True, blank=True, verbose_name='圖片')
          text = models.TextField(null=True, blank=True, verbose_name='內容')
          sequence = models.IntegerField(verbose_name='排序')
          status = models.BooleanField(default=True, verbose_name='是否展示')
      
          class Meta:
              db_table = 'tb_content'
              verbose_name = '廣告內容'
              verbose_name_plural = verbose_name
      
          def __str__(self):
              return self.category.name + ': ' + self.title
      
    3. 註冊應用
      INSTALLED_APPS = [
          """"""
          'contents.apps.ContentsConfig', # 主頁模塊
          'goods.apps.GoodsConfig', # 商品模塊
      ]
      

       

    4. 實現遷移
      python manage.py makemigrations
      python manage.py migrate

       

  3. 對接fastdfs
    1. 導入模塊fdfs_client-py github地址
      """
      fdfs_client-py 使用源碼安裝直接從 github 下載 
      
      """
      
      pip install fdfs_client-py-master.zip
      pip install mutagen
      pip isntall requests

       

    2. 在utils下創建fastdfs目錄(python package)然後添加client.conf配置文件
    3. 更改django配置
      # FastDFS配置信息
      FDFS_CLIENT_CONF = os.path.join(BASE_DIR, 'utils/fastdfs/client.conf')

       

    4. 更改client.conf配置
      # FastDFS客戶端存放日誌文件的目錄
      base_path=/home/python/Downloads
      
      # tracker的ip和端口
      
      tracker_server=192.168.1.102:22122
  4. 自定義文件存儲系統
    1. 在fastdfs創建file_storage.py 實現官方文檔django自定義文件存儲中文翻譯
    2. 實現
      from django.core.files.storage import Storage
      from fdfs_client.client import Fdfs_client
      from django.conf import settings
      
      
      class FastDFSStorage(Storage):
          """自定義文件存儲系統"""
      
          def __init__(self, client_conf=None, base_url=None):
              """初始化文件存儲對象的構造方法"""
              # if client_conf == None:
              #     self.client_conf = settings.FDFS_CLIENT_CONF
      
              # 如果client_conf參數爲None,就讀取or後面的值
              self.client_conf = client_conf or settings.FDFS_CLIENT_CONF
              self.base_url = base_url or settings.FDFS_BASE_URL
      
          def _open(self, name, mode='rb'):
              """
              儲存類用於打開文件:因爲必須實現,但是此處是文件存儲不需要打開文件,所以重寫沒用到,所以pass
              :param name: 要打開的文件的名字
              :param mode: 打開的模式,read bytes
              :return: None
              """
              pass
      
          def _save(self, name, content):
              """
              實現文件存儲:在這個方法裏面將文件轉存到FastDFS服務器
              :param name: 要存儲的文件的名字
              :param content: 要存儲的文件對象,File類型的對象,將來使用content.read()讀取對象中的文件二進制
              :return: file_id
              """
              # 創建對接fdfs的客戶端對象
              # client = Fdfs_client('md/utils/fastdfs/client.conf')
              # client = Fdfs_client(settings.FDFS_CLIENT_CONF)
              client = Fdfs_client(self.client_conf)
      
              # 將文件轉存到fdfs
              # ret = client.upload_by_filename('/Users/zhangjie/Desktop/01.jpeg')
              ret = client.upload_by_buffer(content.read())
      
              # 判斷文件上傳是否成功
              if ret.get('Status') != 'Upload successed.':
                  raise Exception('upload file failed')
      
              # 能夠執行到這裏說明上傳成功
              file_id = ret.get('Remote file_id')
              # 在自定義了文件存儲系統之後,我們只需要返回file_id即可
              # 將來文件存儲系統會"自動的"將file_id存儲到對應的ImageFiled字段中
              # file_id == 'group1/M00/00/00/wKhnhluSuYeAIc39AAC4j90Tziw56.jpeg'
              return file_id
      
          def exists(self, name):
              """
              判斷文件是否存在,判斷本地是否存儲了該文件,如果存儲了就不會再存儲,如果沒有存儲就調用_save()
              :param name: 要判斷的文件的名字
              :return: True(文件存在) / False(文件不存在)
              """
              return False
      
          def url(self, name):
              """
              返回文件的絕對路徑的,下載圖片時使用的
              :param name: 是要讀取的文件的名字,name==file_id
              :return: 文件絕對路徑 http://192.168.1.102:8888/group1/M00/00/00/wKhnhluTuniAezl6AAC4j90Tziw02.jpeg
              """
              # return 'http://192.168.1.102:8888/' +  name
              return self.base_url + name
      
      
              """
              {
               'Group name': 'group1',
               'Remote file_id': 'group1/M00/00/00/wKhnhluSuYeAIc39AAC4j90Tziw56.jpeg',
               'Status': 'Upload successed.',
               'Local file name': '****/Desktop/01.jpeg',
               'Uploaded size': '46.00KB',
               'Storage IP': '192.168.1.102'
               }
              """

       

    3.  添加配置
      # django文件存儲
      DEFAULT_FILE_STORAGE = 'meiduo_mall.utils.fastdfs.file_storage.FastDFSStorage'
      
      # FastDFS配置信息
      FDFS_BASE_URL = 'http://192.168.103.132:8888/'
      FDFS_CLIENT_CONF = os.path.join(BASE_DIR, 'utils/fastdfs/client.conf')

       

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章