解決vim對django中的models類欄位自動補全失效的問題

來源:互聯網
上載者:User

    首先我使用了pythoncomplete的最新的0.9版,在環境變數裡面添加了DJANGO_SETTINGS_MODULE=settings,設定export PYTHONPATH=~/workspace/my_project/src。這時候我編寫一個model類比如:

# file: ~/workspace/my_project/src/main/models.py

class Book(models.Model):

    name = models.CharField(max_length=100)

    title = 'book title'

 

然後在同一目錄裡面建立一個tt.py檔案在裡面建立這個類的執行個體

from main.models import *

 

b = Book()

b.<C-x><C-o>

 

這時候只能提示title這個欄位而不會出現name欄位,這個問題我反覆實驗了多次,發現和PYTHONPATH,tags都設定都沒有關係。而是pythoncomplete這個外掛程式自身編寫有問題,如果你不讓Book繼承models.Model而是普通的object是可以提示出name欄位,看了它的代碼不是很明白所以我只是用一種補丁的方式來解決這個問題。開啟$VIM/vim72/autoload/pythoncomplete.vim檔案編輯其中的get_completions函數在

 

match = stmt[ridx+1:]

stmt = _sanitize(stmt[:ridx])

result = eval(stmt, self.compldict)

all = dir(result)

 

 

後面加入:

 

if result.__class__.__name__ == 'ModelBase':

                    module_name = result.__module__

                    class_name = result.__name__

                    module_instance = __import__(module_name, {}, {}, [class_name])

                    class_instance = getattr(module_instance, class_name)

                    instance = class_instance()

                    result = instance

                    all = dir(instance)

 

 

這裡面的result就是b這個對象執行個體,all是它的所有屬性。在上面的代碼中我首先判斷result的基類是否為django.db.models.base.ModelBase然後根據Book的__module__再重新動態建立一個執行個體出來,這樣就可以得到所有的欄位了。你可以把親手修改以下看看是不是真的有效果了,如果起作用了你也不要太高興,因為這隻完成了第一步,不信你把b = Book()放到一個函數裡面比如我們views.py中經常定義的函數中去你就發現改了上面的代碼也沒有什麼作用,經過反覆使用print絕技,終於定位到問題了,在evalsource函數的這段代碼身上:

 

 for l in sc.locals:

            try:               

                exec(l) in self.compldict

            except:

                print "locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)

                dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))

 

 

print這句是我加的,方便查看具體錯誤。應該報錯的錯誤是NameError,使用了未定義的Book。經過實驗發現在一個函數裡面如果加入import就會正常,比如:

def index(request):

 

    from main.models import *

    b = Book()

這是因為exec在執行的時候是要結合內容相關的,如果你不在index函數中匯入需要的module,Book肯定是未定義,所以解決這個問題其實很簡單,將上面這段改為:

 

namespace = []

 

 

def evalsource(self,text,line=0):

        sc = self.parser.parse(text,line)

        src = sc.get_code()

        dbg("source: %s" % src)

        try: exec(src) in self.compldict

        except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))

        # patch for Model SubClass in fuction

        if not namespace:

            for item in src.split('/n'):

                if item.startswith('from') or item.startswith('import'):

                    namespace.append(item)

 

        for l in sc.locals:

            try: 

                namespace.append(l)    

                l = '/n'.join(namespace)

                exec(l) in self.compldict

            except:

                print "locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)

                dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))

 

 

 

因為在src這個變數已經包含了前面的源碼,所以可以簡單的過濾出來你源檔案中的所有import,from語句,然後再在每次exec的時候把namespace加到它的前面就大功告成了。

 

說起來簡單,做起來難。就這兩個小問題折騰了我兩天還好是搞定了,看上面的代碼應該是有效能問題,好在neocomplcache外掛程式有緩衝不會讓vim反應過慢。最後還要說個問題就是現在的index函數是在太簡單了,因為正常的編碼都會從資料庫中取值比如:

b = Book.object.get(id = 1)

這時候是肯定沒有任何提示了,當然有一個弱點的解決方案就是為了提示在定義一個b = Book() 先把代碼寫完了,然後在把這句刪除了。不過更好的方發應該是根據django的源碼想辦法讓pythoncomplete可以動態得到query後的執行個體對象,這個問題就等我以後有熱情和精力再解決把。現在的這個提示功能我已經很滿足了。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.