django 問題綜合

 

orm部分

 

本篇文章我會持續更新,把開發中遇到的一切orm相關的問題都放在這裏前端

 

mysql索引報錯

 

使用django 的orm,數據庫用的mysql,在使用makemigrations和migrate生成數據庫表時,報以下錯誤:mysql

Traceback (most recent call last):
  File "manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\__init__.py", line 381, in execute_from
_command_line
    utility.execute()
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\base.py", line 316, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\base.py", line 353, in execute
    output = self.handle(*args, **options)
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "C:\Program Files\Python37\lib\site-packages\django\core\management\commands\migrate.py", line 203, in hand
le
    fake_initial=fake_initial,
  File "C:\Program Files\Python37\lib\site-packages\django\db\migrations\executor.py", line 117, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "C:\Program Files\Python37\lib\site-packages\django\db\migrations\executor.py", line 147, in _migrate_all_f
orwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "C:\Program Files\Python37\lib\site-packages\django\db\migrations\executor.py", line 244, in apply_migratio
n
    state = migration.apply(state, schema_editor)
  File "C:\Program Files\Python37\lib\site-packages\django\db\migrations\migration.py", line 124, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "C:\Program Files\Python37\lib\site-packages\django\db\migrations\operations\models.py", line 514, in datab
ase_forwards
    getattr(new_model._meta, self.option_name, set()),
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\base\schema.py", line 360, in alter_unique_
together
    self.execute(self._create_unique_sql(model, columns))
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\base\schema.py", line 133, in execute
    cursor.execute(sql, params)
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\utils.py", line 100, in execute
    return super().execute(sql, params)
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappe
rs
    return executor(sql, params, many, context)
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Program Files\Python37\lib\site-packages\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Program Files\Python37\lib\site-packages\django\db\backends\mysql\base.py", line 71, in execute
    return self.cursor.execute(query, args)
  File "C:\Program Files\Python37\lib\site-packages\pymysql\cursors.py", line 170, in execute
    result = self._query(query)
  File "C:\Program Files\Python37\lib\site-packages\pymysql\cursors.py", line 328, in _query
    conn.query(q)
  File "C:\Program Files\Python37\lib\site-packages\pymysql\connections.py", line 516, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "C:\Program Files\Python37\lib\site-packages\pymysql\connections.py", line 727, in _read_query_result
    result.read()
  File "C:\Program Files\Python37\lib\site-packages\pymysql\connections.py", line 1066, in read
    first_packet = self.connection._read_packet()
  File "C:\Program Files\Python37\lib\site-packages\pymysql\connections.py", line 683, in _read_packet
    packet.check_error()
  File "C:\Program Files\Python37\lib\site-packages\pymysql\protocol.py", line 220, in check_error
    err.raise_mysql_exception(self._data)
  File "C:\Program Files\Python37\lib\site-packages\pymysql\err.py", line 109, in raise_mysql_exception
    raise errorclass(errno, errval)
django.db.utils.InternalError: (1071, 'Specified key was too long; max key length is 767 bytes')

 

 

解決方法

 

1.檢查CharField字段的max_length,是否超過最大值

 

2.mysql修改默認編碼爲utf8,出現以上問題多是mysql默認的編碼是utf8mb4

 

使用 如下命令能夠查看默認編碼sql

 

 到mysql的配置文件裏把編碼改成utf8便可,修改步驟具體百度解決數據庫

 

3.修改mysql默認最大索引

 

配置文件裏修改django

default-storage-engine=INNODB
innodb_large_prefix=on

 

4.奇葩問題解決 

 

我遇到的問題和以上的方法都沒有關係,就把定義的字段,從新審查了一遍,把choices字段,能用SmallIntergerField或者PositiveIntegerField都由以前的IntegerField改爲前者兩個,把CharField的max_length超過1024的字段都換成TextField,把DateTimeField能換成DateField都改爲DateField。就這樣,問題奇蹟般的解決後端

 

 

外鍵查詢時報錯

 

在orm操做裏,作外鍵查詢時,反向查詢按表名時報錯,好比一個課程對象 course,須要去拿與course作一對一關聯的coursedetail數據,發現報錯course no attribute "coursedetail"restful

 

反覆檢查查詢字段,沒有問題,就是報錯,最後發現是由於一對一的兩個表數據量不統一,有的爲空,因此在一對一查詢時有NoneType對象,因此會報錯沒有coursedetail屬性。添加上匹配的字段後,正常返回數據app

 

 

跨表查詢時,沒法去重

 

首先,場景是這樣的,有個課程系統,課程表由於不一樣使用時間有不一樣的價格, 因此使用django的ccontent_type表把價格策略放進去,而後在作數據提取時,前端有個價格排行,以下:框架

 

後端接口,提取數據部分ssh

 

前端請求的結果:

 

 

數據庫用的mysql。遵循了restful規範,因此用了djangorestframwork框架

 

其餘可有可無的就不展現了

 

其實我整個數據庫的課程表就只有十五個,可是產生了重複的部分,由於數據庫表有價格策略數據,以下:

 

課程表:

 

價格策略表:

 

由於相同課程有不一樣的價格,因此致使出現了一個課程有多個數據

 

可是,我明明使用了distinct仍是沒法去重啊

 

而後網上查閱了不少資料,看django的官方文檔,有以下說法:

 

1.distinct()方法里加限制參數

我加了:distinct('id') 

 

報錯:DISTINCT ON fields is not supported by this database backend

 

意思是當前的數據庫不支持在distinct里加參數

 

2.使用values()取值以後再去重

這個方法是網上找到的最多的方法,我想說,老弟啊,我就是要取數據庫的對象啊,你這用values是把字段的值取出來啊,這個方法我想都沒想,直接放棄這個方法

 

固然是能夠用values的,方法是可行的,主要是什麼,我須要的是把數據庫的對象取出來,交給restframework去序列化,而後傳給前端的:

 

 

因此此法不行

 

 

如下是我想的方法,最後一個方法才能完美解決去重問題

 

3.用djagno自帶的API

用django的annotate()方法,原理就是先分組,就能夠把有重複數據的分組出來,而後再處理篩選便可,這方法已試,沒用

 

4.對取出的數據庫對象拆分去重

 就在以下位置寫差費去重代碼

 

可是,由於取出來的數據是QuerySet對象,這個是django自帶的對象,咱們熟悉的Python的操做都不太好完成,怎麼去重嘛,想了不少,碼了不少種方法都不行,有點難度

由於什麼,你去重,是否是要先所有遍歷一遍,另外放進一個對象裏,而後當第二次遍歷相同數據時就再也不存進去就好了,提及來簡單,你另外建立的變量最終也得是QuerySet對象,而後QuerySet對象沒有  in 的判斷,像列表,字典,就有 if  XXX  in dict/list/tuple...,QuerySet就不支持這個if  XXX in QuerySet的寫法

 

 並且就算支持也沒有把數據存進去的方法,不存在append方法

 

在QuerySet源碼中找了兩個update,update_or_create()方法,不行,會報錯,因此這個方法也放棄 

 

5.對最後拿到的結果進行去重

 

首先,看res.data裏的數據的對象是什麼類型:

 

這裏你要是用OrderedDict來進行後續操做你就大錯特錯了,我都是慢慢摸索出的,最後serializer序列化獲得的res.data是ReturnList對象,而並非OrederedDict對象

 

因此這裏建立一個ReturnList跟res.data進行拆分去重

 

 發現仍是報錯,看了源碼,貌似要傳入一個serializer對象才行,這裏又沒辦法了,最後仍是看源碼,在ReturnList源碼裏,找到幾個方法:

 

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'serializer', 'sort']

 

魔法方法就忽略了,看那幾個比較熟悉的方法名,看着是否是就是list的一些方法啊?因此,最後的代碼:

 

 

# 針對mysql數據庫數據去重
        if query:
            temp = res.data
            temp.clear()
            for item in res.data:
                if item not in temp:
                    temp.append(item)
                else:
                    continue
            return Response(temp)

 

前端展現,正確返回,完成去重

 

這個問題耗了我幾個小時,終於找到了解決方法。

 

可是,此法並非通用的,由於結合了djagnorestframework才完成的,若是你沒用這個框架,那就不用考慮取到的數據必定得是數據庫對象了,使用values('xxxx')以後,再用用distinct('XX')傳參去重就好了。 

 

 

 

ur部分

報以下錯誤:

 

 

RuntimeError: You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/XXXX (note the trailing slash), or set APPEND_SLASH=False in your Django settings.

 

 發現是由於在url定義的時候給結束符 【/】,而在請求測試的時候沒有給【/】:

 

 

 

因此二者統一就行。

相關文章
相關標籤/搜索