Django loaddata命令出现问题

时间:2018-10-08 19:46:49

标签: django django-models

我正在写一些基于Django的免费软件。

我有一个Item类,描述了一个定价计划(例如“订阅,每周10美元,没有试用期”)。

我的代码经常基于现有代码创建新项目。例如,基于上述项目创建的新项目为:“订阅,每周10美元,试用期为10天”(如果客户已经付款10天)。

现在有两种项目:

  • 预定义的项目(如第一个示例);
  • 修改后的项目(基于另一个项目,如第二个示例所示)。

现在麻烦了

  • 我使用./manage.py loaddata ...命令创建了预定义的项目,该命令从JSON文件加载了这些项目。
  • 我在Python代码中创建了修改后的项目。
  • 如果我将新项目添加到JSON代码中并再次运行./manage.py loaddata ...,那么loaddata命令(根据我的理解)可能会覆盖其中一个修改过的项目(稍后由我的Python创建)代码)。

如何避免用新的预定义项目覆盖修改的项目?更笼统地说,如何使预定义项目和修改后的项目保持不同,以确保代码可以区分哪些项目是预定义的,哪些不是?

2 个答案:

答案 0 :(得分:0)

转储数据和Loaddata不应用于创建“修改后的项目”。也许将这些命令更像是“备份”和“还原”。如果要从json文件加载新创建的项目,请编写自定义管理命令:

Custom Management Commands

答案 1 :(得分:0)

首先声明一个抽象模型:

import os
import os.path
import sys
import datetime
import webbrowser
import argparse
import time
import traceback
import selenium
import selenium.webdriver.chrome.options
import pathlib

# ======== Command args singleton

class CommandArgs:
    def __init__ (self):
        self.argParser = argparse.ArgumentParser ()

        self.argParser.add_argument ('-de', '--dextex', help = "show extended exception reports", action = 'store_true')
        self.argParser.add_argument ('-f', '--fcall', help = 'test fast calls', action = 'store_true')

        self.argParser.add_argument ('-i', '--inst', help = 'installed version rather than new one', action = 'store_true')
        self.argParser.add_argument ('-b', '--blind', help = 'don\'t start browser', action = 'store_true')

        self.argParser.add_argument ('-u', '--unattended', help = 'unattended mode', action = 'store_true')

        self.__dict__.update (self.argParser.parse_args () .__dict__)

commandArgs = CommandArgs ()

# ========  Browser controller singleton

class BrowserController:
    def __init__ (self):
        self.options = selenium.webdriver.chrome.options.Options ()

        self.options.add_argument ('start-maximized') 

        if commandArgs.unattended:
            self.options.add_argument ('--headless')          # Runs Chrome in headless mode.
            self.options.add_argument ('--no-sandbox')        # Bypass OS security model
            self.options.add_argument ('--disable-gpu')       # Applicable to windows OS only
            self.options.add_argument ('disable-infobars')
            self.options.add_argument ('--disable-extensions')    

        self.webDriver = selenium.webdriver.Chrome (chrome_options = self.options)
        self.browserIsRunning = False

    def open (self, url):
        print (f'Browser controller is opening URL: {url}')

        if self.browserIsRunning:

            if commandArgs.unattended:

                # ---- Show in existing tab

                self.webDriver.execute_script (f'window.location.href = "{url}";') 
            else:

                # ---- Open new tab

                self.webDriver.execute_script (f'window.open ("{url}","_blank");') 
        else:

            # ---- Open browser and default tab

            self.webDriver.get (url)
            self.browserIsRunning = True  

        try:
            self.message = self.webDriver.find_element_by_id ('message')
            print (f'Back to back autotest, result: {self.message.text.upper ()}')
            if 'succeeded' in self.message.text:
                return True
            else:
                return False
        except:
            print ('No back to back autotest')
            return True

browserController = BrowserController ()

# ======== Preparations

relSourcePrepathsOfErrors = []

nodeServerUrl = 'http://localhost:8090'
pythonHttpServerUrl = 'http://localhost:8000'
transpileCommand = 'transcrypt' if commandArgs.inst else 'run_transcrypt'

shipDir = os.path.dirname (os.path.abspath (__file__)) .replace ('\\', '/')
appRootDir = '/'.join  (shipDir.split ('/')[ : -2])

print (f'\nApplication root directory: {appRootDir}\n')


def getAbsPath (relPath):
    return '{}/{}'.format (appRootDir, relPath)

os.system ('cls' if os.name == 'nt' else 'clear')

# ---- Start an http server in the Transcryp/transcrypt directory

if not commandArgs.blind:
    if commandArgs.unattended:
        os.system (f'python -m http.server --directory {appRootDir} &')
    else:
        os.system (f'start python -m http.server --directory {appRootDir}')

# ---- Allow visual check of all command line options

os.system (f'{transpileCommand} -h')

# ======== Individual test function

def test (relSourcePrepath, run, extraSwitches, messagePrename = '', nodeJs = False, build = True, pause = 0, needsAttention = False):
    if commandArgs.unattended and needsAttention:
        return  # This test shouldn't be done, since it can't run unattended

    print (f'\n\n******** BEGIN TEST {relSourcePrepath} ********\n')

    time.sleep (pause)

    # ---- Compute some slugs

    sourcePrepath = getAbsPath (relSourcePrepath)
    sourcePrepathSplit = relSourcePrepath.split ("/")

    relTargetDir = f'{"/".join (sourcePrepathSplit [:-1])}/__target__'
    targetDir = getAbsPath (relTargetDir)

    moduleName = sourcePrepathSplit [-1]
    targetPrepath = f'{targetDir}/{moduleName}'

    relMessagePrepath = f'{relTargetDir}/{messagePrename}'
    messagePrepath = getAbsPath (relMessagePrepath)

    # ---- If there are relevant console messages of the compilation process,
    #       like with the static typechecking tests, write them into a file that can be served for a visual check

    if not os.path.exists (targetDir):
        os.makedirs (targetDir) # Transcrypt will make targetDir too late, so it has to happen here
    redirect = f' > {messagePrepath}.out' if messagePrename else ''

    # ---- Default switches

    defaultSwitches = '-da -sf -de -m -n '
    if commandArgs.dextex:
        defaultSwitches += '-de '
    if build:
        defaultSwitches += '-b '

    # ---- Compile with Transcrypt

    os.system (f'{transpileCommand} {defaultSwitches}{extraSwitches}{sourcePrepath}{redirect}')

    # ---- Run with CPython to generate HTML file with back to back reference info

    if run:
        os.system (f'{transpileCommand} -r {defaultSwitches}{extraSwitches}{sourcePrepath}')

    # ---- Apply rollup to obtain monolith, since node doesn't support named imports and exports

    if nodeJs:
        os.system (f'rollup {targetPrepath}.js --o {targetPrepath}.bundle.js --f cjs')

    if not commandArgs.blind:
        if nodeJs:
            os.system (f'start cmd /k node {targetPrepath}.bundle.js'.format (moduleName))
            time.sleep (5)
            url = nodeServerUrl
        else:
            url = f'{pythonHttpServerUrl}/{relSourcePrepath}.html'

        success = browserController.open (url)

    if commandArgs.unattended and not success:
        relSourcePrepathsOfErrors.append (relSourcePrepath)

    print (f'\n******** END TEST {relSourcePrepath} ********\n\n')

# ======== Perform individual tests

for switches in (('', '-f ') if commandArgs.fcall else ('',)):
    test ('development/automated_tests/hello/autotest', True, switches)
    test ('development/automated_tests/transcrypt/autotest', True, switches + '-c -xr -xg ')
    test ('development/automated_tests/time/autotest', True, switches, needsAttention = True)
    test ('development/automated_tests/re/autotest', True, switches)

    test ('development/manual_tests/module_random/module_random', False, switches)
    test ('development/manual_tests/transcrypt_only/transcrypt_only', False, switches)
    test ('development/manual_tests/transcrypt_and_python_results_differ/results', False, switches)
    test ('development/manual_tests/static_types/static_types', False, switches + '-ds -dc ', messagePrename = 'static_types')
    test ('development/manual_tests/async_await/test', False, switches)

    test ('demos/nodejs_demo/nodejs_demo', False, switches, nodeJs = True)
    test ('demos/terminal_demo/terminal_demo', False, switches, needsAttention = True)  
    test ('demos/hello/hello', False, switches, needsAttention = False)
    test ('demos/jquery_demo/jquery_demo', False, switches)
    test ('demos/d3js_demo/d3js_demo', False, switches)
    test ('demos/ios_app/ios_app', False, switches)
    test ('demos/react_demo/react_demo', False, switches)
    test ('demos/riot_demo/riot_demo', False, switches)
    test ('demos/plotly_demo/plotly_demo', False, switches)
    test ('demos/three_demo/three_demo', False, switches)
    test ('demos/pong/pong', False, switches)
    test ('demos/pysteroids_demo/pysteroids', False, switches)

    test ('demos/turtle_demos/star', False, switches, pause = 2)
    test ('demos/turtle_demos/snowflake', False, switches, pause = 2)
    test ('demos/turtle_demos/mondrian', False, switches, pause = 2)
    test ('demos/turtle_demos/mandala', False, switches, pause = 2)

    test ('demos/cyclejs_demo/cyclejs_demo', False, switches)
    test ('demos/cyclejs_demo/cyclejs_http_demo', False, switches, build = False)
    test ('demos/cyclejs_demo/component_demos/isolated_bmi_slider/bmi', False, switches)
    test ('demos/cyclejs_demo/component_demos/labeled_slider/labeled_slider', False, switches)

    test ('tutorials/baseline/bl_010_hello_world/hello_world', False, switches)
    test ('tutorials/baseline/bl_020_assign/assign', False, switches)
    test ('tutorials/baseline/bl_030_if_else_prompt/if_else_prompt', False, switches, needsAttention = True)
    test ('tutorials/baseline/bl_035_if_else_event/if_else_event', False, switches, needsAttention = True)
    test ('tutorials/baseline/bl_040_for_simple/for_simple', False, switches)
    test ('tutorials/baseline/bl_042_for_nested/for_nested', False, switches)
    test ('tutorials/baseline/bl_045_while_simple/while_simple', False, switches, needsAttention = True)

    test ('tutorials/static_typing/static_typing', False, switches + '-c -ds ', messagePrename = 'static_typing')

    if relSourcePrepathsOfErrors:
        print ('\n\n!!!!!!!!!!!!!!!!!!!!\n')
        for relSourcePrepathOfError in relSourcePrepathsOfErrors:
            print (f'SHIPMENT TEST ERROR: {relSourcePrepathOfError}')
        print ('\n!!!!!!!!!!!!!!!!!!!!\n\n')

        print ('\nSHIPMENT TEST FAILED\n')
        sys.exit (1)

    else:

        # ---- Make docs, the resulting files are untracked

        if not commandArgs.unattended:
            origDir = os.getcwd ()
            sphinxDir = '/'.join ([appRootDir, 'docs/sphinx'])
            os.chdir (sphinxDir)
            os.system ('touch *.rst')
            os.system ('make html')
            os.chdir (origDir)

        # ---- Terminate

        print ('\nSHIPMENT TEST SUCCEEDED\n')
        sys.exit (0)

然后声明:

class ItemBase(models.Model):
    class Meta:
        abstract = True
    name = models.CharField(max_length=100)
    # ...

class PredefinedItem(ItemBase): pass class ModifiedItem(ItemBase): base = models.OneToOneField(PredefinedItem, null=True) @atomic @staticmethod def obtain_predefined(id): try: return ModifiedItem.objects.get(base_id=id) except ModifiedItem.DoesNotExist: predefined = PredefinedItem.objects.get(pk=id) return ModifiedItem.objects.create(base=id, **model_to_dict( predefined, fields=[f.name for f in ItemBase._meta.fields])) 允许创建预定义对象的副本,使用该副本代替预定义对象本身。因此,我们不必担心预定义的对象会覆盖已修改的对象。

注意:已使用https://stackoverflow.com/a/52787554/856090个答案。