标签归档:Django

如何更改Django应用的名称?

问题:如何更改Django应用的名称?

我通过重命名应用程序的文件夹,导入及其所有引用(模板/索引)来更改了Django中应用程序的名称。但是现在当我尝试运行时出现此错误python manage.py runserver

Error: Could not import settings 'nameofmynewapp.settings' (Is it on sys.path?): No module named settings

如何调试和解决此错误?有什么线索吗?

I have changed the name of an app in Django by renaming its folder, imports and all its references (templates/indexes). But now I get this error when I try to run python manage.py runserver

Error: Could not import settings 'nameofmynewapp.settings' (Is it on sys.path?): No module named settings

How can I debug and solve this error? Any clues?


回答 0

请按照以下步骤在Django中更改应用的名称:

  1. 重命名项目根目录中的文件夹
  2. 更改为您的应用程序的任何引用他们的依赖关系,即应用程序的views.pyurls.py“manage.py”,和settings.py文件。
  3. django_content_type使用以下命令编辑数据库表:UPDATE django_content_type SET app_label='<NewAppName>' WHERE app_label='<OldAppName>'
  4. 另外,如果您有模型,则必须重命名模型表。供postgres使用ALTER TABLE <oldAppName>_modelName RENAME TO <newAppName>_modelName。对于MySQL我也认为它是相同的(如@null_radix所提到的)
  5. (对于Django> = 1.7),更新django_migrations表以避免重新运行以前的迁移:UPDATE django_migrations SET app='<NewAppName>' WHERE app='<OldAppName>'注意:对于Django 1.8+是否需要执行此步骤,存在一些参数(在注释中)。如果有人知道,请在这里更新。
  6. 如果您models.py的的元类已app_name列出,请确保也将其重命名(由@will提及)。
  7. 如果您已在应用程序中为statictemplates文件夹命名空间,则还需要重命名它们。例如,重命名old_app/static/old_appnew_app/static/new_app
  8. 要重命名django models,您需要更改django_content_type.nameDB中的条目。对于PostgreSQL使用UPDATE django_content_type SET name='<newModelName>' where name='<oldModelName>' AND app_label='<OldAppName>'

元点(如果使用virtualenv):值得注意的是,如果要重命名包含virtualenv的目录,则env中可能有几个文件包含绝对路径,并且也需要更新。如果您遇到诸如此类的错误,ImportError: No module named ...可能是罪魁祸首。(感谢@danyamachine提供此功能)。

其他参考:您可能还想参考以下链接以获得更完整的图片

  1. 使用Django和South重命名应用程序
  2. 如何将模型从一个django应用程序迁移到新的模型中?
  3. 如何更改Django应用的名称?
  4. 使用Django South向后迁移
  5. 使用Django / South重命名模型的最简单方法?
  6. Python代码(感谢A.Raouf)可以自动完成上述步骤(未经测试的代码。已警告您!)
  7. Python代码(感谢rafaponieman)可以自动完成上述步骤(未经测试的代码。已警告您!)

Follow these steps to change an app’s name in Django:

  1. Rename the folder which is in your project root
  2. Change any references to your app in their dependencies, i.e. the app’s views.py, urls.py , ‘manage.py’ , and settings.py files.
  3. Edit the database table django_content_type with the following command: UPDATE django_content_type SET app_label='<NewAppName>' WHERE app_label='<OldAppName>'
  4. Also if you have models, you will have to rename the model tables. For postgres use ALTER TABLE <oldAppName>_modelName RENAME TO <newAppName>_modelName. For mysql too I think it is the same (as mentioned by @null_radix)
  5. (For Django >= 1.7) Update the django_migrations table to avoid having your previous migrations re-run: UPDATE django_migrations SET app='<NewAppName>' WHERE app='<OldAppName>'. Note: there is some debate (in comments) if this step is required for Django 1.8+; If someone knows for sure please update here.
  6. If your models.py ‘s Meta Class has app_name listed, make sure to rename that too (mentioned by @will).
  7. If you’ve namespaced your static or templates folders inside your app, you’ll also need to rename those. For example, rename old_app/static/old_app to new_app/static/new_app.
  8. For renaming django models, you’ll need to change django_content_type.name entry in DB. For postgreSQL use UPDATE django_content_type SET name='<newModelName>' where name='<oldModelName>' AND app_label='<OldAppName>'

Meta point (If using virtualenv): Worth noting, if you are renaming the directory that contains your virtualenv, there will likely be several files in your env that contain an absolute path and will also need to be updated. If you are getting errors such as ImportError: No module named ... this might be the culprit. (thanks to @danyamachine for providing this).

Other references: you might also want to refer the below links for a more complete picture

  1. Renaming an app with Django and South
  2. How do I migrate a model out of one django app and into a new one?
  3. How to change the name of a Django app?
  4. Backwards migration with Django South
  5. Easiest way to rename a model using Django/South?
  6. Python code (thanks to A.Raouf) to automate the above steps (Untested code. You have been warned!)
  7. Python code (thanks to rafaponieman) to automate the above steps (Untested code. You have been warned!)

回答 1

Django 1.7中的新功能是一个应用程序注册表,它存储配置并提供自省功能。通过这种机制,您可以更改几个应用程序属性。

我要提出的主要观点是,重命名应用程序并非总是必要的:通过应用程序配置,可以解决冲突的应用程序。但是,如果您的应用需要友好的命名方式,这也是可行的方法。

例如,我想将民意调查应用命名为“用户反馈”。它是这样的:

apps.pypolls目录中创建一个文件:

from django.apps import AppConfig

class PollsConfig(AppConfig):
    name = 'polls'
    verbose_name = "Feedback from users"

将默认应用配置添加到您的polls/__init__.py

default_app_config = 'polls.apps.PollsConfig'

有关更多应用程序配置:https : //docs.djangoproject.com/zh-CN/1.7/ref/applications/

New in Django 1.7 is a app registry that stores configuration and provides introspection. This machinery let’s you change several app attributes.

The main point I want to make is that renaming an app isn’t always necessary: With app configuration it is possible to resolve conflicting apps. But also the way to go if your app needs friendly naming.

As an example I want to name my polls app ‘Feedback from users’. It goes like this:

Create a apps.py file in the polls directory:

from django.apps import AppConfig

class PollsConfig(AppConfig):
    name = 'polls'
    verbose_name = "Feedback from users"

Add the default app config to your polls/__init__.py:

default_app_config = 'polls.apps.PollsConfig'

For more app configuration: https://docs.djangoproject.com/en/1.7/ref/applications/


回答 2

好玩的问题!我很快将不得不重命名许多应用程序,所以我做了一次试运行。

此方法允许逐步执行进度,以最大程度地减少对正在重命名的应用程序上工作的其他开发人员的干扰。

有关有效的示例代码,请参见此答案底部的链接。

  1. 准备移动的现有代码
    • 创建一个应用程序配置(设置namelabel为默认值)。
    • 将应用程序配置添加到中INSTALLED_APPS
    • 在所有模型上,将其显式设置db_table为当前值。
    • 医生迁移,因此db_table“总是”被明确定义。
    • 确保不需要迁移(请检查上一步)。
  2. 更改应用标签

    • label在应用程序配置中设置为新的应用程序名称。
    • 更新迁移和外键以引用新的应用标签。
    • 更新基于类的通用视图的模板(默认路径为<app_label>/<model_name>_<suffix>.html
    • 运行原始SQL来修复迁移和content_types应用(不幸的是,某些原始SQL是不可避免的)。您不能在迁移中运行它。

      UPDATE django_migrations
         SET app = 'catalogue'
       WHERE app = 'shop';
      
      UPDATE django_content_type
         SET app_label = 'catalogue'
       WHERE app_label = 'shop';
      
    • 确保不需要迁移(请检查上一步)。

  3. 重命名表
    • 删除“ custom” db_table
    • 运行,makemigrations以便django可以将表重命名为“默认”。
  4. 移动文件
    • 重命名模块目录。
    • 修复导入。
    • 更新应用程序的配置name
    • 更新INSTALLED_APPS引用应用程序配置的位置。
  5. 整理
    • 如果不再需要自定义应用程序配置,请删除它。
    • 如果应用程序配置消失了,别忘了也将其从中删除INSTALLED_APPS

示例解决方案:我创建了app-rename-example这个示例项目,您可以在其中看到如何重命名应用,一次提交一次。

该示例使用Python 2.7和Django 1.8,但我相信相同的过程至少可以在Python 3.6和Django 2.1上运行。

Fun problem! I’m going to have to rename a lot of apps soon, so I did a dry run.

This method allows progress to be made in atomic steps, to minimise disruption for other developers working on the app you’re renaming.

See the link at the bottom of this answer for working example code.

  1. Prepare existing code for the move:
    • Create an app config (set name and label to defaults).
    • Add the app config to INSTALLED_APPS.
    • On all models, explicitly set db_table to the current value.
    • Doctor migrations so that db_table was “always” explicitly defined.
    • Ensure no migrations are required (checks previous step).
  2. Change the app label:

    • Set label in app config to new app name.
    • Update migrations and foreign keys to reference new app label.
    • Update templates for generic class-based views (the default path is <app_label>/<model_name>_<suffix>.html)
    • Run raw SQL to fix migrations and content_types app (unfortunately, some raw SQL is unavoidable). You can not run this in a migration.

      UPDATE django_migrations
         SET app = 'catalogue'
       WHERE app = 'shop';
      
      UPDATE django_content_type
         SET app_label = 'catalogue'
       WHERE app_label = 'shop';
      
    • Ensure no migrations are required (checks previous step).

  3. Rename the tables:
    • Remove “custom” db_table.
    • Run makemigrations so django can rename the table “to the default”.
  4. Move the files:
    • Rename module directory.
    • Fix imports.
    • Update app config’s name.
    • Update where INSTALLED_APPS references the app config.
  5. Tidy up:
    • Remove custom app config if it’s no longer required.
    • If app config gone, don’t forget to also remove it from INSTALLED_APPS.

Example solution: I’ve created app-rename-example, an example project where you can see how I renamed an app, one commit at a time.

The example uses Python 2.7 and Django 1.8, but I’m confident the same process will work on at least Python 3.6 and Django 2.1.


回答 3

如果您使用的是PyCharm,并且项目在重命名后停止工作:

  1. 编辑运行/调试配置并更改环境变量DJANGO_SETTINGS_MODULE,因为它包含您的项目名称。
  2. 转到设置/语言和框架/ Django并更新设置文件位置。

In case you are using PyCharm and project stops working after rename:

  1. Edit Run/Debug configuration and change environment variable DJANGO_SETTINGS_MODULE, since it includes your project name.
  2. Go to Settings / Languages & Frameworks / Django and update the settings file location.

回答 4

重新迁移清洁板的方法。

如果其他应用程序没有要重命名的应用程序中的外键模型,则可以轻松完成此操作。检查并确保其迁移文件未列出此迁移中的任何迁移。

  1. 备份数据库。转储所有具有a)数据+架构的表,以获取可能的循环依赖关系,以及b)仅重新加载数据。
  2. 运行测试。
  3. 将所有代码检入VCS。
  4. 删除要重命名的应用程序的数据库表。
  5. 删除权限: delete from auth_permission where content_type_id in (select id from django_content_type where app_label = '<OldAppName>')
  6. 删除内容类型: delete from django_content_type where app_label = '<OldAppName>'
  7. 重命名应用程序的文件夹。
  8. 更改为您的应用程序的任何引用他们的依赖关系,即应用程序的views.pyurls.py“manage.py”,和settings.py文件。
  9. 删除迁移: delete from django_migrations where app = '<OldAppName>'
  10. 如果您models.py的的元类已app_name列出,请确保也将其重命名(由@will提及)。
  11. 如果您已在应用程序中为statictemplates文件夹命名空间,则还需要重命名它们。例如,重命名old_app/static/old_appnew_app/static/new_app
  12. 如果您在apps.py中定义了应用程序配置;重命名它们,然后在设置中重命名它们的引用。INSTALLED_APPS
  13. 删除迁移文件。
  14. 重新进行迁移,然后进行迁移。
  15. 从备份加载表数据。

Re-migrate approach for a cleaner plate.

This can painlessly be done IF other apps do not foreign key models from the app to be renamed. Check and make sure their migration files don’t list any migrations from this one.

  1. Backup your database. Dump all tables with a) data + schema for possible circular dependencies, and b) just data for reloading.
  2. Run your tests.
  3. Check all code into VCS.
  4. Delete the database tables of the app to be renamed.
  5. Delete the permissions: delete from auth_permission where content_type_id in (select id from django_content_type where app_label = '<OldAppName>')
  6. Delete content types: delete from django_content_type where app_label = '<OldAppName>'
  7. Rename the folder of the app.
  8. Change any references to your app in their dependencies, i.e. the app’s views.py, urls.py , ‘manage.py’ , and settings.py files.
  9. Delete migrations: delete from django_migrations where app = '<OldAppName>'
  10. If your models.py ‘s Meta Class has app_name listed, make sure to rename that too (mentioned by @will).
  11. If you’ve namespaced your static or templates folders inside your app, you’ll also need to rename those. For example, rename old_app/static/old_app to new_app/static/new_app.
  12. If you defined app config in apps.py; rename those, and rename their references in settings.INSTALLED_APPS
  13. Delete migration files.
  14. Re-make migrations, and migrate.
  15. Load your table data from backups.

回答 5

如果您使用Pycharm,则通过重构所有项目文件(Shift+ F6默认值)非常容易重命名应用程序。
但是,请确保删除__pycache__项目目录及其子目录中的文件夹。也要小心,因为它也会重命名注释,您可以在重构预览窗口中将其排除在注释之外,它会向您显示。
而且,您还必须重命名您已重apps.py命名的应用程序中的OldNameConfig(AppConfig):。

如果您不想丢失数据库的数据,则必须使用上述查询中的数据库查询手动进行操作。

If you use Pycharm, renaming an app is very easy with refactoring(Shift+F6 default) for all project files.
But make sure you delete the __pycache__ folders in the project directory & its sub-directories. Also be careful as it also renames comments too which you can exclude in the refactor preview window it will show you.
And you’ll have to rename OldNameConfig(AppConfig): in apps.py of your renamed app in addition.

If you do not want to lose data of your database, you’ll have to manually do it with query in database like the aforementioned answer.


回答 6

为什么不只使用选项“查找并替换”。(每个代码编辑器都有)吗?

例如,Visual Studio代码(在“编辑”选项下):

您只需键入旧名称和新名称,然后单击一下即可替换项目中的所有内容。

注意:这仅重命名文件内容,而不重命名文件和文件夹名称。不要忘记重命名文件夹,例如。templates/my_app_name/重命名为templates/my_app_new_name/

Why not just use the option Find and Replace. (every code editor has it)?

For example Visual Studio Code (under Edit option):

You just type in old name and new name and replace everyhting in the project with one click.

NOTE: This renames only file content, NOT file and folder names. Do not forget renaming folders, eg. templates/my_app_name/ rename it to templates/my_app_new_name/


如何建立多个提交按钮Django表单?

问题:如何建立多个提交按钮Django表单?

我有一个带有一个电子邮件输入和两个提交按钮的表单,用于订阅和取消订阅新闻通讯:

<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>

我也有上课表格:

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = ('email',)

我必须编写自己的clean_email方法,并且我需要知道表单是通过哪个按钮提交的。但是提交按钮的值不在self.cleaned_data字典中。否则我可以获取按钮的值吗?

I have form with one input for email and two submit buttons to subscribe and unsubscribe from newsletter:

<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>

I have also class form:

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = ('email',)

I must write my own clean_email method and I need to know by which button was form submited. But the value of submit buttons aren’t in self.cleaned_data dictionary. Could I get values of buttons otherwise?


回答 0

您可以self.dataclean_email方法中使用来在验证之前访问POST数据。它应包含一个称为newsletter_subnewsletter_unsub取决于所按下按钮的键。

# in the context of a django.forms form

def clean(self):
    if 'newsletter_sub' in self.data:
        # do subscribe
    elif 'newsletter_unsub' in self.data:
        # do unsubscribe

You can use self.data in the clean_email method to access the POST data before validation. It should contain a key called newsletter_sub or newsletter_unsub depending on which button was pressed.

# in the context of a django.forms form

def clean(self):
    if 'newsletter_sub' in self.data:
        # do subscribe
    elif 'newsletter_unsub' in self.data:
        # do unsubscribe

回答 1

例如:

if 'newsletter_sub' in request.POST:
    # do subscribe
elif 'newsletter_unsub' in request.POST:
    # do unsubscribe

Eg:

if 'newsletter_sub' in request.POST:
    # do subscribe
elif 'newsletter_unsub' in request.POST:
    # do unsubscribe

回答 2

你也可以这样

 <form method='POST'>
    {{form1.as_p}}
    <button type="submit" name="btnform1">Save Changes</button>
    </form>
    <form method='POST'>
    {{form2.as_p}}
    <button type="submit" name="btnform2">Save Changes</button>
    </form>


if request.method=='POST' and 'btnform1' in request.POST:
    do something...
if request.method=='POST' and 'btnform2' in request.POST:
    do something...

You can also do like this,

 <form method='POST'>
    {{form1.as_p}}
    <button type="submit" name="btnform1">Save Changes</button>
    </form>
    <form method='POST'>
    {{form2.as_p}}
    <button type="submit" name="btnform2">Save Changes</button>
    </form>

CODE

if request.method=='POST' and 'btnform1' in request.POST:
    do something...
if request.method=='POST' and 'btnform2' in request.POST:
    do something...

回答 3

现在这是一个老问题,但是我遇到了同样的问题,并找到了一个对我有用的解决方案:我写了MultiRedirectMixin。

from django.http import HttpResponseRedirect

class MultiRedirectMixin(object):
    """
    A mixin that supports submit-specific success redirection.
     Either specify one success_url, or provide dict with names of 
     submit actions given in template as keys
     Example: 
       In template:
         <input type="submit" name="create_new" value="Create"/>
         <input type="submit" name="delete" value="Delete"/>
       View:
         MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
             success_urls = {"create_new": reverse_lazy('create'),
                               "delete": reverse_lazy('delete')}
    """
    success_urls = {}  

    def form_valid(self, form):
        """ Form is valid: Pick the url and redirect.
        """

        for name in self.success_urls:
            if name in form.data:
                self.success_url = self.success_urls[name]
                break

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        """
        Returns the supplied success URL.
        """
        if self.success_url:
            # Forcing possible reverse_lazy evaluation
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                _("No URL to redirect to. Provide a success_url."))
        return url

It’s an old question now, nevertheless I had the same issue and found a solution that works for me: I wrote MultiRedirectMixin.

from django.http import HttpResponseRedirect

class MultiRedirectMixin(object):
    """
    A mixin that supports submit-specific success redirection.
     Either specify one success_url, or provide dict with names of 
     submit actions given in template as keys
     Example: 
       In template:
         <input type="submit" name="create_new" value="Create"/>
         <input type="submit" name="delete" value="Delete"/>
       View:
         MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
             success_urls = {"create_new": reverse_lazy('create'),
                               "delete": reverse_lazy('delete')}
    """
    success_urls = {}  

    def form_valid(self, form):
        """ Form is valid: Pick the url and redirect.
        """

        for name in self.success_urls:
            if name in form.data:
                self.success_url = self.success_urls[name]
                break

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        """
        Returns the supplied success URL.
        """
        if self.success_url:
            # Forcing possible reverse_lazy evaluation
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                _("No URL to redirect to. Provide a success_url."))
        return url

回答 4

一个网址到同一视图!像这样!

urls.py

url(r'^$', views.landing.as_view(), name = 'landing'),

views.py

class landing(View):
        template_name = '/home.html'
        form_class1 = forms.pynamehere1
        form_class2 = forms.pynamehere2
            def get(self, request):
                form1 = self.form_class1(None)
                form2 = self.form_class2(None)
                return render(request, self.template_name, { 'register':form1, 'login':form2,})

             def post(self, request):
                 if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
                        ## do what ever you want to do for first function ####
                 if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
                         ## do what ever you want to do for second function ####
                        ## return def post###  
                 return render(request, self.template_name, {'form':form,})
/home.html
    <!-- #### form 1 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ register.as_p }}
    <button type="submit" name="htmlsubmitbutton1">Login</button>
    </form>
    <!--#### form 2 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ login.as_p }}
    <button type="submit" name="htmlsubmitbutton2">Login</button>
    </form>

one url to the same view! like so!

urls.py

url(r'^$', views.landing.as_view(), name = 'landing'),

views.py

class landing(View):
        template_name = '/home.html'
        form_class1 = forms.pynamehere1
        form_class2 = forms.pynamehere2
            def get(self, request):
                form1 = self.form_class1(None)
                form2 = self.form_class2(None)
                return render(request, self.template_name, { 'register':form1, 'login':form2,})

             def post(self, request):
                 if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
                        ## do what ever you want to do for first function ####
                 if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
                         ## do what ever you want to do for second function ####
                        ## return def post###  
                 return render(request, self.template_name, {'form':form,})
/home.html
    <!-- #### form 1 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ register.as_p }}
    <button type="submit" name="htmlsubmitbutton1">Login</button>
    </form>
    <!--#### form 2 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ login.as_p }}
    <button type="submit" name="htmlsubmitbutton2">Login</button>
    </form>

在Django模板中格式化数字

问题:在Django模板中格式化数字

我正在尝试格式化数字。例子:

1     => 1
12    => 12
123   => 123
1234  => 1,234
12345 => 12,345

它很常见,但是我无法弄清楚应该使用哪个过滤器。

编辑:如果您有通用的Python方法可以执行此操作,则很高兴在模型中添加格式化的字段。

I’m trying to format numbers. Examples:

1     => 1
12    => 12
123   => 123
1234  => 1,234
12345 => 12,345

It strikes as a fairly common thing to do but I can’t figure out which filter I’m supposed to use.

Edit: If you’ve a generic Python way to do this, I’m happy adding a formatted field in my model.


回答 0

Django的贡献人性化应用程序执行以下操作:

{% load humanize %}
{{ my_num|intcomma }}

确保将文件添加'django.contrib.humanize'INSTALLED_APPS列表中settings.py

Django’s contributed humanize application does this:

{% load humanize %}
{{ my_num|intcomma }}

Be sure to add 'django.contrib.humanize' to your INSTALLED_APPS list in the settings.py file.


回答 1

在其他答案的基础上,要将其扩展到浮点数,可以执行以下操作:

{% load humanize %}
{{ floatvalue|floatformat:2|intcomma }}

文档:floatformatintcomma

Building on other answers, to extend this to floats, you can do:

{% load humanize %}
{{ floatvalue|floatformat:2|intcomma }}

Documentation: floatformat, intcomma.


回答 2

关于Ned Batchelder的解决方案,此处为2个小数点和一个美元符号。这就像my_app/templatetags/my_filters.py

from django import template
from django.contrib.humanize.templatetags.humanize import intcomma

register = template.Library()

def currency(dollars):
    dollars = round(float(dollars), 2)
    return "$%s%s" % (intcomma(int(dollars)), ("%0.2f" % dollars)[-3:])

register.filter('currency', currency)

那么你就可以

{% load my_filters %}
{{my_dollars | currency}}

Regarding Ned Batchelder’s solution, here it is with 2 decimal points and a dollar sign. This goes somewhere like my_app/templatetags/my_filters.py

from django import template
from django.contrib.humanize.templatetags.humanize import intcomma

register = template.Library()

def currency(dollars):
    dollars = round(float(dollars), 2)
    return "$%s%s" % (intcomma(int(dollars)), ("%0.2f" % dollars)[-3:])

register.filter('currency', currency)

Then you can

{% load my_filters %}
{{my_dollars | currency}}

回答 3

尝试在settings.py中添加以下行:

USE_THOUSAND_SEPARATOR = True

这应该工作。

请参阅文档


更新于2018-04-16:

还有一种执行此操作的python方法:

>>> '{:,}'.format(1000000)
'1,000,000'

Try adding the following line in settings.py:

USE_THOUSAND_SEPARATOR = True

This should work.

Refer to documentation.


update at 2018-04-16:

There is also a python way to do this thing:

>>> '{:,}'.format(1000000)
'1,000,000'

回答 4

如果您不想参与语言环境,则可以使用以下函数来格式化数字:

def int_format(value, decimal_points=3, seperator=u'.'):
    value = str(value)
    if len(value) <= decimal_points:
        return value
    # say here we have value = '12345' and the default params above
    parts = []
    while value:
        parts.append(value[-decimal_points:])
        value = value[:-decimal_points]
    # now we should have parts = ['345', '12']
    parts.reverse()
    # and the return value should be u'12.345'
    return seperator.join(parts)

从此函数创建自定义模板过滤器很简单。

If you don’t want to get involved with locales here is a function that formats numbers:

def int_format(value, decimal_points=3, seperator=u'.'):
    value = str(value)
    if len(value) <= decimal_points:
        return value
    # say here we have value = '12345' and the default params above
    parts = []
    while value:
        parts.append(value[-decimal_points:])
        value = value[:-decimal_points]
    # now we should have parts = ['345', '12']
    parts.reverse()
    # and the return value should be u'12.345'
    return seperator.join(parts)

Creating a custom template filter from this function is trivial.


回答 5

人文化的解决方案是好的,如果你的网站是英文的。对于其他语言,您需要另一种解决方案:我建议使用Babel。一种解决方案是创建一个自定义模板标签以正确显示数字。方法如下:只需在中创建以下文件your_project/your_app/templatetags/sexify.py

# -*- coding: utf-8 -*-
from django import template
from django.utils.translation import to_locale, get_language
from babel.numbers import format_number

register = template.Library()

def sexy_number(context, number, locale = None):
    if locale is None:
        locale = to_locale(get_language())
    return format_number(number, locale = locale)

register.simple_tag(takes_context=True)(sexy_number)

然后,您可以像下面这样在模板中使用此模板标记:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • 对于美国用户(语言环境为en_US),显示为1,234.56。
  • 对于法语用户(语言环境fr_FR),这将显示1 234,56。

当然,您可以改用变量:

{% sexy_number some_variable %}

注意:context参数当前未在我的示例中使用,但我将其放在此处表明您可以轻松地调整此模板标签以使其使用模板上下文中的任何内容。

The humanize solution is fine if your website is in English. For other languages, you need another solution: I recommend using Babel. One solution is to create a custom template tag to display numbers properly. Here’s how: just create the following file in your_project/your_app/templatetags/sexify.py:

# -*- coding: utf-8 -*-
from django import template
from django.utils.translation import to_locale, get_language
from babel.numbers import format_number

register = template.Library()

def sexy_number(context, number, locale = None):
    if locale is None:
        locale = to_locale(get_language())
    return format_number(number, locale = locale)

register.simple_tag(takes_context=True)(sexy_number)

Then you can use this template tag in your templates like this:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • For an american user (locale en_US) this displays 1,234.56.
  • For a french user (locale fr_FR), this displays 1 234,56.

Of course you can use variables instead:

{% sexy_number some_variable %}

Note: the context parameter is currently not used in my example, but I put it there to show that you can easily tweak this template tag to make it use anything that’s in the template context.


回答 6

人文化的应用程序提供了一个很好和格式化号码的快捷方式,但如果你需要使用一个分离器不同于逗号,它的简单,只是重复使用从人文化的应用程序的代码,则更换分隔字符,并创建一个自定义过滤器。例如,使用空格作为分隔符:

@register.filter('intspace')
def intspace(value):
    """
    Converts an integer to a string containing spaces every three digits.
    For example, 3000 becomes '3 000' and 45000 becomes '45 000'.
    See django.contrib.humanize app
    """
    orig = force_unicode(value)
    new = re.sub("^(-?\d+)(\d{3})", '\g<1> \g<2>', orig)
    if orig == new:
        return new
    else:
        return intspace(new)

The humanize app offers a nice and a quick way of formatting a number but if you need to use a separator different from the comma, it’s simple to just reuse the code from the humanize app, replace the separator char, and create a custom filter. For example, use space as a separator:

@register.filter('intspace')
def intspace(value):
    """
    Converts an integer to a string containing spaces every three digits.
    For example, 3000 becomes '3 000' and 45000 becomes '45 000'.
    See django.contrib.humanize app
    """
    orig = force_unicode(value)
    new = re.sub("^(-?\d+)(\d{3})", '\g<1> \g<2>', orig)
    if orig == new:
        return new
    else:
        return intspace(new)

回答 7

稍微偏离主题:

我在寻找一种将数字格式化为货币的方法时发现了这个问题,如下所示:

$100
($50)  # negative numbers without '-' and in parens

我最终做了:

{% if   var >= 0 %} ${{ var|stringformat:"d" }}
{% elif var <  0 %} $({{ var|stringformat:"d"|cut:"-" }})
{% endif %}

您也可以这样做,例如{{ var|stringformat:"1.2f"|cut:"-" }}显示为$50.00(如果要的话, 2位小数。

也许稍微有点怪癖,但也许其他人会发现它很有用。

Slightly off topic:

I found this question while looking for a way to format a number as currency, like so:

$100
($50)  # negative numbers without '-' and in parens

I ended up doing:

{% if   var >= 0 %} ${{ var|stringformat:"d" }}
{% elif var <  0 %} $({{ var|stringformat:"d"|cut:"-" }})
{% endif %}

You could also do, e.g. {{ var|stringformat:"1.2f"|cut:"-" }} to display as $50.00 (with 2 decimal places if that’s what you want.

Perhaps slightly on the hacky side, but maybe someone else will find it useful.


回答 8

好吧,我找不到Django方式,但确实从模型内部找到了python方式:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)

Well I couldn’t find a Django way, but I did find a python way from inside my model:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)

回答 9

请注意,更改区域设置是在整个进程范围内进行的,并且不是线程安全的(现在,可能会有副作用,或者可能影响在同一进程中执行的其他代码)。

我的主张:检查Babel软件包。提供了一些与Django模板集成的方法。

Be aware that changing locale is process-wide and not thread safe (iow., can have side effects or can affect other code executed within the same process).

My proposition: check out the Babel package. Some means of integrating with Django templates are available.


回答 10

不知道为什么还没有提到:

{% load l10n %}

{{ value|localize }}

https://docs.djangoproject.com/zh-CN/1.11/topics/i18n/formatting/#std:templatefilter-localize

您还可以通过调用在Django代码(外部模板)中使用此代码localize(number)

Not sure why this has not been mentioned, yet:

{% load l10n %}

{{ value|localize }}

https://docs.djangoproject.com/en/1.11/topics/i18n/formatting/#std:templatefilter-localize

You can also use this in your Django code (outside templates) by calling localize(number).


回答 11

基于muhuk的答案,我做了这个简单的标记封装python string.format方法。

  • 创建一个 templatetags在您的应用程序文件夹中。
  • format.py在其上创建一个文件。
  • 添加到它:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • 将其加载到模板中 {% load format %}
  • 用它。 {{ some_value|format:"{:0.2f}" }}

Based on muhuk answer I did this simple tag encapsulating python string.format method.

  • Create a templatetags at your’s application folder.
  • Create a format.py file on it.
  • Add this to it:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
    
  • Load it in your template {% load format %}
  • Use it. {{ some_value|format:"{:0.2f}" }}

回答 12

万一有人偶然发现了这个,Django 2.0.2你可以用这个

千位分隔符。确保还阅读格式本地化

In case someone stumbles upon this, in Django 2.0.2 you can use this

Thousand separator. Be sure to read format localization as well.


无法比较幼稚和知道的datetime.now()<= Challenge.datetime_end

问题:无法比较幼稚和知道的datetime.now()<= Challenge.datetime_end

我正在尝试使用比较运算符将当前日期和时间与模型中指定的日期和时间进行比较:

if challenge.datetime_start <= datetime.now() <= challenge.datetime_end:

脚本错误如下:

TypeError: can't compare offset-naive and offset-aware datetimes

这些模型如下所示:

class Fundraising_Challenge(models.Model):
    name = models.CharField(max_length=100)
    datetime_start = models.DateTimeField()
    datetime_end = models.DateTimeField()

我也有使用区域设置日期和时间的django。

我找不到的是django用于DateTimeField()的格式。天真还是知道?以及如何获取datetime.now()来识别语言环境datetime?

I am trying to compare the current date and time with dates and times specified in models using comparison operators:

if challenge.datetime_start <= datetime.now() <= challenge.datetime_end:

The script errors out with:

TypeError: can't compare offset-naive and offset-aware datetimes

The models look like this:

class Fundraising_Challenge(models.Model):
    name = models.CharField(max_length=100)
    datetime_start = models.DateTimeField()
    datetime_end = models.DateTimeField()

I also have django using locale date and times.

What I haven’t been able to find is the format django uses for DateTimeField(). Is it naive or aware? And how do I get datetime.now() to recognize locale datetime?


回答 0

默认情况下,该datetime对象naive位于Python中,因此您需要将它们都设为天真或感知datetime对象。可以使用以下方法完成:

import datetime
import pytz

utc=pytz.UTC

challenge.datetime_start = utc.localize(challenge.datetime_start) 
challenge.datetime_end = utc.localize(challenge.datetime_end) 
# now both the datetime objects are aware, and you can compare them

注意:这将引发一个ValueErrorif tzinfo值。如果您不确定,请使用

start_time = challenge.datetime_start.replace(tzinfo=utc)
end_time = challenge.datetime_end.replace(tzinfo=utc)

顺便说一句,您可以在带有时区信息的datetime.datetime对象中格式化UNIX时间戳,如下所示

d = datetime.datetime.utcfromtimestamp(int(unix_timestamp))
d_with_tz = datetime.datetime(
    year=d.year,
    month=d.month,
    day=d.day,
    hour=d.hour,
    minute=d.minute,
    second=d.second,
    tzinfo=pytz.UTC)

By default, the datetime object is naive in Python, so you need to make both of them either naive or aware datetime objects. This can be done using:

import datetime
import pytz

utc=pytz.UTC

challenge.datetime_start = utc.localize(challenge.datetime_start) 
challenge.datetime_end = utc.localize(challenge.datetime_end) 
# now both the datetime objects are aware, and you can compare them

Note: This would raise a ValueError if tzinfo is already set. If you are not sure about that, just use

start_time = challenge.datetime_start.replace(tzinfo=utc)
end_time = challenge.datetime_end.replace(tzinfo=utc)

BTW, you could format a UNIX timestamp in datetime.datetime object with timezone info as following

d = datetime.datetime.utcfromtimestamp(int(unix_timestamp))
d_with_tz = datetime.datetime(
    year=d.year,
    month=d.month,
    day=d.day,
    hour=d.hour,
    minute=d.minute,
    second=d.second,
    tzinfo=pytz.UTC)

回答 1

datetime.datetime.now 不了解时区。

Django为此提供了一个帮助程序,它需要 pytz

from django.utils import timezone
now = timezone.now()

你应该能够比较nowchallenge.datetime_start

datetime.datetime.now is not timezone aware.

Django comes with a helper for this, which requires pytz

from django.utils import timezone
now = timezone.now()

You should be able to compare now to challenge.datetime_start


回答 2

一行代码解决方案

if timezone_aware_var <= datetime.datetime.now(timezone_aware_var.tzinfo):
    pass #some code

解释版

# Timezone info of your timezone aware variable
timezone = your_timezone_aware_variable.tzinfo

# Current datetime for the timezone of your variable
now_in_timezone = datetime.datetime.now(timezone)

# Now you can do a fair comparison, both datetime variables have the same time zone
if your_timezone_aware_variable <= now_in_timezone:
    pass #some code

摘要

您必须将时区信息添加到now()日期时间。
但是,您必须添加参考变量的相同时区。这就是为什么我首先阅读该tzinfo属性的原因。

One line of code solution

if timezone_aware_var <= datetime.datetime.now(timezone_aware_var.tzinfo):
    pass #some code

Explained version

# Timezone info of your timezone aware variable
timezone = your_timezone_aware_variable.tzinfo

# Current datetime for the timezone of your variable
now_in_timezone = datetime.datetime.now(timezone)

# Now you can do a fair comparison, both datetime variables have the same time zone
if your_timezone_aware_variable <= now_in_timezone:
    pass #some code

Summary

You must add the timezone info to your now() datetime.
However, you must add the same timezone of the reference variable; that is why I first read the tzinfo attribute.


回答 3

禁用时区。用challenge.datetime_start.replace(tzinfo=None);

您还可以将其replace(tzinfo=None)用于其他datetime

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):

Disable time zone. Use challenge.datetime_start.replace(tzinfo=None);

You can also use replace(tzinfo=None) for other datetime.

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):

回答 4

因此,我要解决此问题的方法是确保两个日期时间在正确的时区中。

我可以看到您正在使用datetime.now()它将返回系统的当前时间,而未设置tzinfo。

tzinfo是附加在日期时间上的信息,以使其知道它所在的时区。如果使用的是朴素的日期时间,则需要在整个系统中保持一致。我强烈建议只使用datetime.utcnow()

看到您正在创建与tzinfo相关联的日期时间,您需要做的是确保将它们本地化(与tzinfo相关联)到正确的时区。

看一下Delorean,它使处理这种事情变得更加容易。

So the way I would solve this problem is to make sure the two datetimes are in the right timezone.

I can see that you are using datetime.now() which will return the systems current time, with no tzinfo set.

tzinfo is the information attached to a datetime to let it know what timezone it is in. If you are using naive datetime you need to be consistent through out your system. I would highly recommend only using datetime.utcnow()

seeing as somewhere your are creating datetime that have tzinfo associated with them, what you need to do is make sure those are localized (has tzinfo associated) to the correct timezone.

Take a look at Delorean, it makes dealing with this sort of thing much easier.


回答 5

这是我的工作。在这里,我对创建的日期时间的表进行geet,并在日期时间上添加10分钟。稍后根据当前时间,完成到期操作。

from datetime import datetime, time, timedelta
import pytz

在数据库日期时间增加了10分钟

table_datetime =’2019-06-13 07:49:02.832969’(示例)

# Added 10 minutes on database datetime
# table_datetime = '2019-06-13 07:49:02.832969' (example)

table_expire_datetime = table_datetime + timedelta(minutes=10 )

# Current datetime
current_datetime = datetime.now()


# replace the timezone in both time
expired_on = table_expire_datetime.replace(tzinfo=utc)
checked_on = current_datetime.replace(tzinfo=utc)


if expired_on < checked_on:
    print("Time Crossed)
else:
    print("Time not crossed ")

它为我工作。

It is working form me. Here I am geeting the table created datetime and adding 10 minutes on the datetime. later depending on the current time, Expiry Operations are done.

from datetime import datetime, time, timedelta
import pytz

Added 10 minutes on database datetime

table_datetime = ‘2019-06-13 07:49:02.832969’ (example)

# Added 10 minutes on database datetime
# table_datetime = '2019-06-13 07:49:02.832969' (example)

table_expire_datetime = table_datetime + timedelta(minutes=10 )

# Current datetime
current_datetime = datetime.now()


# replace the timezone in both time
expired_on = table_expire_datetime.replace(tzinfo=utc)
checked_on = current_datetime.replace(tzinfo=utc)


if expired_on < checked_on:
    print("Time Crossed)
else:
    print("Time not crossed ")

It worked for me.


回答 6

只是:

dt = datetimeObject.strftime(format) # format = your datetime format ex) '%Y %d %m'
dt = datetime.datetime.strptime(dt,format)

这样做:

start_time = challenge.datetime_start.strftime('%Y %d %m %H %M %S')
start_time = datetime.datetime.strptime(start_time,'%Y %d %m %H %M %S')

end_time = challenge.datetime_end.strftime('%Y %d %m %H %M %S')
end_time = datetime.datetime.strptime(end_time,'%Y %d %m %H %M %S')

然后使用start_timeend_time

Just:

dt = datetimeObject.strftime(format) # format = your datetime format ex) '%Y %d %m'
dt = datetime.datetime.strptime(dt,format)

So do this:

start_time = challenge.datetime_start.strftime('%Y %d %m %H %M %S')
start_time = datetime.datetime.strptime(start_time,'%Y %d %m %H %M %S')

end_time = challenge.datetime_end.strftime('%Y %d %m %H %M %S')
end_time = datetime.datetime.strptime(end_time,'%Y %d %m %H %M %S')

and then use start_time and end_time


类没有对象成员

问题:类没有对象成员

def index(request):
   latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
   template = loader.get_template('polls/index.html')
   context = {'latest_question_list':latest_question_list}
   return HttpResponse(template.render(context, request))

该函数的第一行在出现错误Question.objects.all()

E1101:类“问题”没有对象“成员”

我正在阅读Django文档教程,并且它们具有相同的代码并正在运行。

我尝试调用实例。

Question = new Question()
and using MyModel.objects.all()

我的models.py类代码也是这个…

class Question(models.Model):
question_text = models.CharField(max_length = 200)
pub_date = models.DateTimeField('date published') 

def was_published_recently(self):
    return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

def __str__(self):
    return self.question_text

无济于事,我仍然有此错误。

我已经读过有关pylint的文章,并进行了…

pylint --load-plugins pylint_django

这没有帮助,即使github自述文件说…

防止有关Django生成的属性(例如Model.objects或Views.request)的警告。

我在我的virtualenv中运行了命令,但是什么也没有。

因此,任何帮助都会很棒。

def index(request):
   latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
   template = loader.get_template('polls/index.html')
   context = {'latest_question_list':latest_question_list}
   return HttpResponse(template.render(context, request))

The first line of that function gets an error on Question.objects.all():

E1101: Class ‘Question’ has no objects ‘member’

I’m following the Django documentation tutorial and they have the same code up and running.

I have tried calling an instance.

Question = new Question()
and using MyModel.objects.all()

Also my models.py code for that class is this…

class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published') 

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def __str__(self):
        return self.question_text

To no avail I still have this error.

I have read about pylint and ran this…

pylint --load-plugins pylint_django

Which didn’t help, even tho the github readme file says…

Prevents warnings about Django-generated attributes such as Model.objects or Views.request.

I ran the command within my virtualenv, and yet nothing.

So any help would be great.


回答 0

pylint-django使用pip如下安装

pip install pylint-django

然后在Visual Studio Code中转到:用户设置Ctrl+ ,或文件>首选项>设置(如果可用))放入以下内容(请注意VSC中自定义用户设置所需的花括号):

{"python.linting.pylintArgs": [
     "--load-plugins=pylint_django"
],}

Install pylint-django using pip as follows

pip install pylint-django

Then in Visual Studio Code goto: User Settings (Ctrl + , or File > Preferences > Settings if available ) Put in the following (please note the curly braces which are required for custom user settings in VSC):

{"python.linting.pylintArgs": [
     "--load-plugins=pylint_django"
],}

回答 1

@ tieuminh2510的答案是完美的。但是在较新版本的VSC中,您将找不到在用户设置中编辑或粘贴该命令的选项。现在以较新的版本添加该代码,请按照以下步骤操作

ctr + sft + P打开“ 命令面板”。现在,在命令面板中键入首选项:配置特定语言的设置。现在选择Python。在右侧粘贴此代码

"python.linting.pylintArgs": [
        "--load-plugins=pylint_django",
    ]

里面第一个大括号。确保pylint-django

希望这会有所帮助!

@tieuminh2510 answer is perfect. But in newer versions of VSC you will not find thhe option to edit or paste that command in User Settings. Now in newer version to add that code follow this steps :

Press ctr+sft+P to open the the Command Palette. Now in command palette type Preferences: Configure Language Specific Settings. Now select Python. Here in right side paste this code

"python.linting.pylintArgs": [
        "--load-plugins=pylint_django",
    ]

Inside the first curly braces. Make sure that pylint-django.

Hope this will help!


回答 2

安装Django pylint:

pip install pylint-django

ctrl + shift + p>首选项:配置特定于语言的设置> Python

适用于python语言的settings.json应该如下所示:

{
    "python.linting.pylintArgs": [
        "--load-plugins=pylint_django"
    ],

    "[python]": {

    }
}

Install Django pylint:

pip install pylint-django

ctrl+shift+p > Preferences: Configure Language Specific Settings > Python

The settings.json available for python language should look like the below:

{
    "python.linting.pylintArgs": [
        "--load-plugins=pylint_django"
    ],

    "[python]": {

    }
}

回答 3

这是答案。从我的reddit帖子中获得… https://www.reddit.com/r/django/comments/6nq0bq/class_question_has_no_objects_member/

这不是错误,只是来自VSC的警告。Django会动态地将该属性添加到所有模型类中(它在幕后使用了很多魔法),因此IDE不会通过查看类声明来了解该属性,因此会警告您可能存在的错误(不是)。对象实际上是一个帮助查询数据库的Manager实例。如果您真的想摆脱该警告,则可以转到所有模型并添加object = models.Manager()现在,VSC将看到声明的对象,并且不会再次抱怨。

Heres the answer. Gotten from my reddit post… https://www.reddit.com/r/django/comments/6nq0bq/class_question_has_no_objects_member/

That’s not an error, it’s just a warning from VSC. Django adds that property dynamically to all model classes (it uses a lot of magic under the hood), so the IDE doesn’t know about it by looking at the class declaration, so it warns you about a possible error (it’s not). objects is in fact a Manager instance that helps with querying the DB. If you really want to get rid of that warning you could go to all your models and add objects = models.Manager() Now, VSC will see the objects declared and will not complain about it again.


回答 4

我已经尝试了所有可能的解决方案,但不幸的是,我的vscode设置不会更改其linter路径。因此,我尝试在设置>用户设置> python中探索vscode设置。找到Linting:Pylint路径并将其更改为“ pylint_django”。别忘了在设置>用户设置> python配置中将linter更改为“ pylint_django”,从“ pyLint”更改为“ pylint_django”。

I’ve tried all possible solutions offered but unluckly my vscode settings won’t changed its linter path. So, I tride to explore vscode settings in settings > User Settings > python. Find Linting: Pylint Path and change it to “pylint_django”. Don’t forget to change the linter to “pylint_django” at settings > User Settings > python configuration from “pyLint” to “pylint_django”.


回答 5

VS CODE 1.40.0的更新

完成后:

$ pip install pylint-django

请点击以下链接:https : //code.visualstudio.com/docs/python/linting#_default-pylint-rules

请注意,要pylint考虑的方法pylint-django是通过指定:

"python.linting.pylintArgs": ["--load-plugins", "pylint_django"]

settings.jsonVS Code中。

但是之后,您会发现很多新的掉毛错误。然后,阅读此处的内容:

只要将python.linting.pylintUseMinimalCheckers设置为true(默认值),就会传递这些参数。如果在中指定值pylintArgs或使用Pylint配置文件(请参阅下一节),则将pylintUseMinimalCheckers其隐式设置为false

我所做的就是.pylintrc按照链接中的描述创建一个文件,然后在文件中配置以下参数(不影响文件的其余部分):

load-plugins=pylint_django

disable=all

enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode

现在pylint可以正常工作了。

UPDATE FOR VS CODE 1.40.0

After doing:

$ pip install pylint-django

Follow this link: https://code.visualstudio.com/docs/python/linting#_default-pylint-rules

Notice that the way to make pylint have into account pylint-django is by specifying:

"python.linting.pylintArgs": ["--load-plugins", "pylint_django"]

in the settings.json of VS Code.

But after that, you will notice a lot of new linting errors. Then, read what it said here:

These arguments are passed whenever the python.linting.pylintUseMinimalCheckers is set to true (the default). If you specify a value in pylintArgs or use a Pylint configuration file (see the next section), then pylintUseMinimalCheckers is implicitly set to false.

What I have done is creating a .pylintrc file as described in the link, and then, configured the following parameters inside the file (leaving the rest of the file untouched):

load-plugins=pylint_django

disable=all

enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode

Now pylint works as expected.


回答 6

您可以将linter for Python扩展更改为Visual Studio Code。

在VS中,打开命令面板Ctrl + Shift + P并键入以下命令之一:

Python:选择Linter

当您选择短绒时,它将被安装。我尝试了flake8,看来问题已解决。

You can change the linter for Python extension for Visual Studio Code.

In VS open the Command Palette Ctrl+Shift+P and type in one of the following commands:

Python: Select Linter

when you select a linter it will be installed. I tried flake8 and it seems issue resolved for me.


回答 7

只需添加@ Mallory-Erik所说的话:您可以将objects = models.Manager()其放在模式中:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # ...
    def __str__(self):
        return self.question_text
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')
    objects = models.Manager()

Just adding on to what @Mallory-Erik said: You can place objects = models.Manager() it in the modals:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # ...
    def __str__(self):
        return self.question_text
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')
    objects = models.Manager()

回答 8

首先使用以下命令安装pylint-django

$ pip install pylint-django

然后运行第二条命令,如下所示:

$ pylint test_file.py --load-plugins pylint_django

–load-plugins pylint_django是正确检查django代码所必需的

First install pylint-django using following command

$ pip install pylint-django

Then run the second command as follows:

$ pylint test_file.py --load-plugins pylint_django

–load-plugins pylint_django is necessary for correctly review a code of django


回答 9

如果您使用python 3

python3 -m pip install pylint-django

如果python <3

python -m pip install pylint-django==0.11.1

注意:2.0版要求pylint> = 2.0,该版本不再支持Python 2!(https://pypi.org/project/pylint-django/

If you use python 3

python3 -m pip install pylint-django

If python < 3

python -m pip install pylint-django==0.11.1

NOTE: Version 2.0, requires pylint >= 2.0 which doesn’t support Python 2 anymore! (https://pypi.org/project/pylint-django/)


回答 10

通过执行操作Question = new Question()(我假设new是错字),您将用的实例覆盖Question模型Question。就像Sayse在评论中所说:不要为变量使用与模型名称相同的名称。因此,将其更改为类似my_question = Question()

By doing Question = new Question() (I assume the new is a typo) you are overwriting the Question model with an intance of Question. Like Sayse said in the comments: don’t use the same name for your variable as the name of the model. So change it to something like my_question = Question().


回答 11

如何抑制特定于每个错误的每一行上的错误?

像这样的东西:https : //pylint.readthedocs.io/en/latest/user_guide/message-control.html

错误:[pylint]类’class_name’没有’member_name’成员可以通过以下方法在该行上取消显示:

  # pylint: disable=no-member

How about suppressing errors on each line specific to each error?

Something like this: https://pylint.readthedocs.io/en/latest/user_guide/message-control.html

Error: [pylint] Class ‘class_name’ has no ‘member_name’ member It can be suppressed on that line by:

  # pylint: disable=no-member

回答 12

将您的linter更改为-flake8,问题将消失。

Change your linter to – flake8 and problem will go away.


回答 13

当我使用pylint_runner时发生此问题

所以我要做的是打开.pylintrc文件并将其添加

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=objects

This issue happend when I use pylint_runner

So what I do is open .pylintrc file and add this

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=objects

回答 14

我能够更新用户settings.json

在我的Mac上,它存储在:

~/Library/Application Support/Code/User/settings.json

在其中设置以下内容:

{
    "python.linting.pycodestyleEnabled": true,
    "python.linting.pylintEnabled": true,
    "python.linting.pylintPath": "pylint",
    "python.linting.pylintArgs": ["--load-plugins", "pylint_django"]
}

那为我解决了这个问题。

I was able to update the user settings.json

On my mac it was stored in:

~/Library/Application Support/Code/User/settings.json

Within it, I set the following:

{
    "python.linting.pycodestyleEnabled": true,
    "python.linting.pylintEnabled": true,
    "python.linting.pylintPath": "pylint",
    "python.linting.pylintArgs": ["--load-plugins", "pylint_django"]
}

That solved the issue for me.


如何通过Django发送电子邮件?

问题:如何通过Django发送电子邮件?

在我的中settings.py,我具有以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

# Host for sending e-mail.
EMAIL_HOST = 'localhost'

# Port for sending e-mail.
EMAIL_PORT = 1025

# Optional SMTP authentication information for EMAIL_HOST.
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False

我的电子邮件代码:

from django.core.mail import EmailMessage
email = EmailMessage('Hello', 'World', to=['user@gmail.com'])
email.send()

当然,如果通过设置调试服务器python -m smtpd -n -c DebuggingServer localhost:1025,则可以在终端中看到该电子邮件。

但是,实际上我该如何将电子邮件发送到user@gmail.com而不是发送到调试服务器?

阅读您的答案后,让我弄明白一点:

  1. 您不能使用localhost(简单的ubuntu pc)发送电子邮件吗?

  2. 我以为在django 1.3中send_mail()已经过时了,EmailMessage.send()取而代之的是?

In my settings.py, I have the following:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

# Host for sending e-mail.
EMAIL_HOST = 'localhost'

# Port for sending e-mail.
EMAIL_PORT = 1025

# Optional SMTP authentication information for EMAIL_HOST.
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False

My email code:

from django.core.mail import EmailMessage
email = EmailMessage('Hello', 'World', to=['user@gmail.com'])
email.send()

Of course, if I setup a debugging server via python -m smtpd -n -c DebuggingServer localhost:1025, I can see the email in my terminal.

However, how do I actually send the email not to the debugging server but to user@gmail.com?

After reading your answers, let me get something straight:

  1. Can’t you use localhost(simple ubuntu pc) to send e-mails?

  2. I thought in django 1.3 send_mail() is somewhat deprecated and EmailMessage.send() is used instead?


回答 0

将电子邮件发送到真实的SMTP服务器。如果您不想建立自己的公司,则可以找到可以为您经营公司的公司,例如Google自己。

Send the email to a real SMTP server. If you don’t want to set up your own then you can find companies that will run one for you, such as Google themselves.


回答 1

我将Gmail用作Django的SMTP服务器。比处理postfix或任何其他服务器容易得多。我不从事电子邮件服务器的管理。

在settings.py中:

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'me@gmail.com'
EMAIL_HOST_PASSWORD = 'password'

注意:默认情况下,2016年Gmail不再允许这样做。您可以使用Sendgrid之类的外部服务,也可以按照Google的本教程来降低安全性,但可以选择以下选项:https : //support.google.com/accounts/answer/6010255

I use Gmail as my SMTP server for Django. Much easier than dealing with postfix or whatever other server. I’m not in the business of managing email servers.

In settings.py:

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'me@gmail.com'
EMAIL_HOST_PASSWORD = 'password'

NOTE: In 2016 Gmail is not allowing this anymore by default. You can either use an external service like Sendgrid, or you can follow this tutorial from Google to reduce security but allow this option: https://support.google.com/accounts/answer/6010255


回答 2

  1. 创建一个项目: django-admin.py startproject gmail
  2. 使用以下代码编辑settings.py:

    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_USE_TLS = True
    EMAIL_HOST = 'smtp.gmail.com'
    EMAIL_HOST_USER = 'youremail@gmail.com'
    EMAIL_HOST_PASSWORD = 'email_password'
    EMAIL_PORT = 587
  3. 运行交互模式: python manage.py shell

  4. 导入EmailMessage模块:

    from django.core.mail import EmailMessage
  5. 发送电子邮件:

    email = EmailMessage('Subject', 'Body', to=['your@email.com'])
    email.send()

有关更多信息,请检查send_mail文档中的EmailMessage功能。

Gmail更新

另外,如果您在通过gmail发送电子邮件时遇到问题,请记住从Google 查看本指南

在您的Google帐户设置中,转到 Security > Account permissions > Access for less secure apps并启用此选项。

启用两步验证后,还要为您的gmail创建一个应用专用密码

然后,您应该在设置中使用应用专用密码。因此,更改以下行:

    EMAIL_HOST_PASSWORD = 'your_email_app_specific_password'

另外,如果您有兴趣发送HTML电子邮件,请检查此

  1. Create a project: django-admin.py startproject gmail
  2. Edit settings.py with code below:

    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_USE_TLS = True
    EMAIL_HOST = 'smtp.gmail.com'
    EMAIL_HOST_USER = 'youremail@gmail.com'
    EMAIL_HOST_PASSWORD = 'email_password'
    EMAIL_PORT = 587
    
  3. Run interactive mode: python manage.py shell

  4. Import the EmailMessage module:

    from django.core.mail import EmailMessage
    
  5. Send the email:

    email = EmailMessage('Subject', 'Body', to=['your@email.com'])
    email.send()
    

For more informations, check send_mail and EmailMessage features in documents.

UPDATE for Gmail

Also if you have problems sending email via gmail remember to check this guides from google.

In your Google account settings, go to Security > Account permissions > Access for less secure apps and enable this option.

Also create an App specific password for your gmail after you’ve turned on 2-step-verification for it.

Then you should use app specific password in settings. So change the following line:

    EMAIL_HOST_PASSWORD = 'your_email_app_specific_password'

Also if you’re interested to send HTML email, check this out.


回答 3

我的网站位于Godaddy,我在同一网站上注册了一封私人电子邮件。这些是对我有用的设置:

在settings.py中:

EMAIL_HOST = 'mail.domain.com'
EMAIL_HOST_USER = 'abc@domain.com'
EMAIL_HOST_PASSWORD = 'abcdef'
DEFAULT_FROM_EMAIL = 'abc@domain.com'
SERVER_EMAIL = 'abc@domain.com'
EMAIL_PORT = 25
EMAIL_USE_TLS = False

在外壳中:

from django.core.mail import EmailMessage
email = EmailMessage('Subject', 'Body', to=['def@domain.com'])
email.send()

然后我得到“ 1”作为O / P,即成功。而且我也收到了邮件。:)

  • domain.com是什么意思?

My site is hosted on Godaddy and I have a private email registered on the same. These are the settings which worked for me:

In settings.py:

EMAIL_HOST = 'mail.domain.com'
EMAIL_HOST_USER = 'abc@domain.com'
EMAIL_HOST_PASSWORD = 'abcdef'
DEFAULT_FROM_EMAIL = 'abc@domain.com'
SERVER_EMAIL = 'abc@domain.com'
EMAIL_PORT = 25
EMAIL_USE_TLS = False

In shell:

from django.core.mail import EmailMessage
email = EmailMessage('Subject', 'Body', to=['def@domain.com'])
email.send()

Then I got “1” as the O/P i.e. Success. And I received the mail too. :)

  • What is the meaning of domain.com?

回答 4

对于Django 1.7版,如果上述解决方案不起作用,请尝试以下操作

settings.py中添加

#For email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

EMAIL_USE_TLS = True

EMAIL_HOST = 'smtp.gmail.com'

EMAIL_HOST_USER = 'sender@gmail.com'

#Must generate specific password for your app in [gmail settings][1]
EMAIL_HOST_PASSWORD = 'app_specific_password'

EMAIL_PORT = 587

#This did the trick
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

最后一行完成了Django 1.7的技巧

For Django version 1.7, if above solutions dont work then try the following

in settings.py add

#For email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

EMAIL_USE_TLS = True

EMAIL_HOST = 'smtp.gmail.com'

EMAIL_HOST_USER = 'sender@gmail.com'

#Must generate specific password for your app in [gmail settings][1]
EMAIL_HOST_PASSWORD = 'app_specific_password'

EMAIL_PORT = 587

#This did the trick
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

The last line did the trick for django 1.7


回答 5

您需要使用smtp作为 settings.py中的后端

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

如果将后端用作控制台,则将在控制台中接收输出

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

还有下面的设置

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'urusername@gmail.com'
EMAIL_HOST_PASSWORD = 'password'

如果您为此使用gmail,请设置两步验证特定应用程序的密码,然后将该密码复制并粘贴到上面的EMAIL_HOST_PASSWORD值中。

You need to use smtp as backend in settings.py

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

If you use backend as console, you will receive output in console

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

And also below settings in addition

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'urusername@gmail.com'
EMAIL_HOST_PASSWORD = 'password'

If you are using gmail for this, setup 2-step verification and Application specific password and copy and paste that password in above EMAIL_HOST_PASSWORD value.


回答 6

我发现使用SendGrid是设置使用Django发送电子邮件的最简单方法。运作方式如下:

  1. 创建一个SendGrid帐户(并验证您的电子邮件)
  2. 将以下内容添加到您的settings.py EMAIL_HOST = 'smtp.sendgrid.net' EMAIL_HOST_USER = '<your sendgrid username>' EMAIL_HOST_PASSWORD = '<your sendgrid password>' EMAIL_PORT = 587 EMAIL_USE_TLS = True

一切准备就绪!

发送电子邮件:

from django.core.mail import send_mail
send_mail('<Your subject>', '<Your message>', 'from@example.com', ['to@example.com'])

如果您希望Django在出现500个内部服务器错误时向您发送电子邮件,请将以下内容添加到您的中settings.py

DEFAULT_FROM_EMAIL = 'your.email@example.com'
ADMINS = [('<Your name>', 'your.email@example.com')]

使用SendGrid发送电子邮件每月最多免费获得1.2万封电子邮件。

I found using SendGrid to be the easiest way to set up sending email with Django. Here’s how it works:

  1. Create a SendGrid account (and verify your email)
  2. Add the following to your settings.py: EMAIL_HOST = 'smtp.sendgrid.net' EMAIL_HOST_USER = '<your sendgrid username>' EMAIL_HOST_PASSWORD = '<your sendgrid password>' EMAIL_PORT = 587 EMAIL_USE_TLS = True

And you’re all set!

To send email:

from django.core.mail import send_mail
send_mail('<Your subject>', '<Your message>', 'from@example.com', ['to@example.com'])

If you want Django to email you whenever there’s a 500 internal server error, add the following to your settings.py:

DEFAULT_FROM_EMAIL = 'your.email@example.com'
ADMINS = [('<Your name>', 'your.email@example.com')]

Sending email with SendGrid is free up to 12k emails per month.


回答 7

我实际上是在Django之前完成的。打开一个合法的GMail帐户,然后在此处输入凭据。这是我的代码-

from email import Encoders
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart

def sendmail(to, subject, text, attach=[], mtype='html'):
    ok = True
    gmail_user = settings.EMAIL_HOST_USER
    gmail_pwd  = settings.EMAIL_HOST_PASSWORD

    msg = MIMEMultipart('alternative')

    msg['From']    = gmail_user
    msg['To']      = to
    msg['Cc']      = 'you@gmail.com'
    msg['Subject'] = subject

    msg.attach(MIMEText(text, mtype))

    for a in attach:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(open(attach, 'rb').read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition','attachment; filename="%s"' % os.path.basename(a))
        msg.attach(part)

    try:
        mailServer = smtplib.SMTP("smtp.gmail.com", 687)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmail_user, gmail_pwd)
        mailServer.sendmail(gmail_user, [to,msg['Cc']], msg.as_string())
        mailServer.close()
    except:
        ok = False
    return ok

I had actually done this from Django a while back. Open up a legitimate GMail account & enter the credentials here. Here’s my code –

from email import Encoders
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart

def sendmail(to, subject, text, attach=[], mtype='html'):
    ok = True
    gmail_user = settings.EMAIL_HOST_USER
    gmail_pwd  = settings.EMAIL_HOST_PASSWORD

    msg = MIMEMultipart('alternative')

    msg['From']    = gmail_user
    msg['To']      = to
    msg['Cc']      = 'you@gmail.com'
    msg['Subject'] = subject

    msg.attach(MIMEText(text, mtype))

    for a in attach:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(open(attach, 'rb').read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition','attachment; filename="%s"' % os.path.basename(a))
        msg.attach(part)

    try:
        mailServer = smtplib.SMTP("smtp.gmail.com", 687)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmail_user, gmail_pwd)
        mailServer.sendmail(gmail_user, [to,msg['Cc']], msg.as_string())
        mailServer.close()
    except:
        ok = False
    return ok

回答 8

晚了,但是:

除了DEFAULT_FROM_EMAIL其他人提到的修复程序,允许安全性较低的应用访问该帐户外,我还必须以相关帐户的身份登录到https://accounts.google.com/DisplayUnlockCaptcha,以使Django最终通过身份验证。

我通过SSH隧道到达Web服务器的URL,以确保IP地址相同。我不确定这是否必要,但不会造成伤害。您可以这样操作:ssh -D 8080 -fN <username>@<host>,然后将Web浏览器设置localhost:8080为用作SOCKS代理。

Late, but:

In addition to the DEFAULT_FROM_EMAIL fix others have mentioned, and allowing less-secure apps to access the account, I had to navigate to https://accounts.google.com/DisplayUnlockCaptcha while signed in as the account in question to get Django to finally authenticate.

I went to that URL through a SSH tunnel to the web server to make sure the IP address was the same; I’m not totally sure if that’s necessary but it can’t hurt. You can do that like so: ssh -D 8080 -fN <username>@<host>, then set your web browser to use localhost:8080 as a SOCKS proxy.


回答 9

您可以使用“测试邮件服务器工具”来测试在您的计算机或本地主机上发送的电子邮件。Google并下载“测试邮件服务器工具”并进行设置。

然后在您的settings.py中:

EMAIL_BACKEND= 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 25

从外壳:

from django.core.mail import send_mail
send_mail('subject','message','sender email',['receipient email'],    fail_silently=False)

You could use “Test Mail Server Tool” to test email sending on your machine or localhost. Google and Download “Test Mail Server Tool” and set it up.

Then in your settings.py:

EMAIL_BACKEND= 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 25

From shell:

from django.core.mail import send_mail
send_mail('subject','message','sender email',['receipient email'],    fail_silently=False)

回答 10

对于 SendGrid-Django具体而言:

SendGrid Django文档在这里

在以下位置设置这些变量

settings.py

EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'sendgrid_username'
EMAIL_HOST_PASSWORD = 'sendgrid_password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True

在views.py中

from django.core.mail import send_mail
send_mail('Subject here', 'Here is the message.', 'from@example.com', ['to@example.com'], fail_silently=False)

For SendGrid – Django Specifically:

SendGrid Django Docs here

Set these variables in

settings.py

EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'sendgrid_username'
EMAIL_HOST_PASSWORD = 'sendgrid_password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True

in views.py

from django.core.mail import send_mail
send_mail('Subject here', 'Here is the message.', 'from@example.com', ['to@example.com'], fail_silently=False)

将views.py拆分为多个文件

问题:将views.py拆分为多个文件

我的views.py体积太大了,很难找到正确的视图。

如何将其拆分为多个文件,然后导入?是否涉及速度损失?

我可以这样models.py吗?

My views.py has become too big and it’s hard to find the right view.

How do I split it in several files and then import it? Does it involve any speed loss?

Can I do the same with models.py?


回答 0

在Django中,所有内容都是Python模块(* .py)。您可以创建一个带有__init__.py内部视图的文件夹,并且仍然可以导入视图,因为这也实现了Python模块。但是一个例子会更好。

您的原始图片views.py可能如下所示:

def view1(arg):
    pass

def view2(arg):
   pass

使用以下文件夹/文件结构,它将起到相同的作用:

views/
   __init__.py
   viewsa.py
   viewsb.py

viewsa.py

def view1(arg):
    pass

viewsb.py

def view2(arg):
    pass

__init__.py

from viewsa import view1
from viewsb import view2

快速的解释是:当你写from views import view1的Python会寻找在厂景

  1. views.py,这就是第一种(原始)情况

  2. views/__init__.py,这是第二种情况。在这里,__init__.py能够提供view1方法,因为它可以导入它。

使用这种解决方案,您可能无需更改import或更改urlpattern参数urls.py

如果每个新视图文件中都有很多方法,那么views/__init__.py使用导入可能会很有用*,如下所示:

from viewsa import *
from viewsb import *

我实际上不了解速度问题(但我怀疑是否有任何问题)。

对于模型而言,可能有点困难。

In Django everything is a Python module (*.py). You can create a view folder with an __init__.py inside and you still will be able to import your views, because this also implements a Python module. But an example would be better.

Your original views.py might look like this :

def view1(arg):
    pass

def view2(arg):
   pass

With the following folder/file structure it will work the same :

views/
   __init__.py
   viewsa.py
   viewsb.py

viewsa.py :

def view1(arg):
    pass

viewsb.py :

def view2(arg):
    pass

__init__.py :

from viewsa import view1
from viewsb import view2

The quick explanation would be: when you write from views import view1 Python will look for view1 in

  1. views.py, which is what happens in the first (original) case

  2. views/__init__.py, which is what happens in the second case. Here, __init__.py is able to provide the view1 method because it imports it.

With this kind of solution, you might have no need to change import or urlpatterns arguments in urls.py

If you have many methods in each new view file, you might find it useful to make the imports in views/__init__.py use *, like this:

from viewsa import *
from viewsb import *

I actually don’t know about speed issues (but I doubt there are any).

For Models it might be a bit difficult.


回答 1

我之前必须这样做(为了清楚起见)

我这样做的方法是创建一个views目录,然后创建一个名为__init__.py

现在,当您呼叫时urls.py,您只需要添加另一部分

例如,以前,您可能打电话给:-

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year_by_user')

您现在可以按照

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year.index')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year.user')

当然,这是假定您已views/year.py包含indexuser;)

I’ve had to do this before (for clarities sake)

The way I did this was to create a views directory, then, in that, create a file called __init__.py

Now, when you’re calling in your urls.py, you simply need to add another part

For example, previously, you may have called:-

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year_by_user')

You can now call something along the lines of

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year.index')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year.user')

This is, of course, assuming that you had views/year.py containing the functions index and user ;)


回答 2

基本上,您可以将代码放在任意位置。只需确保您相应地更改了导入语句,例如针对中的视图即可urls.py

不知道您的实际代码很难提出有意义的建议。也许你可以使用某种类型的文件名前缀,例如views_helper.pyviews_fancy.pyviews_that_are_not_so_often_used.py或使…

另一个选择是创建一个views目录__init__.py,其中要导入所有子视图。如果您需要大量文件,则可以随着视图的增长而创建更多的嵌套子视图。

Basically, you can put your code, whereever you wish. Just make sure, you change the import statements accordingly, e.g. for the views in the urls.py.

Not knowing your actual code its hard to suggest something meaningful. Maybe you can use some kind of filename prefix, e.g. views_helper.py, views_fancy.py, views_that_are_not_so_often_used.py or so …

Another option would be to create a views directory with an __init__.py, where you import all subviews. If you have a need for a large number of files, you can create more nested subviews as your views grow …


回答 3

只是为了分享,文森特·德梅斯特(Vincent Demeester)的回答有点问题。除了init .py文件外,一切都很好,我必须这样写:

__init__.py

from .viewsa import *
from .viewsb import *

这样,我仍然不需要import在urls.py中更改我的方法。我正在使用Python 3.6.1Django 1.11.4

Just for sharing, I had a bit of issues with Vincent Demeester’s answer. Everything is fine except in init.py file, I have to write in this way:

__init__.py:

from .viewsa import *
from .viewsb import *

This way I still don’t need to change my import method in urls.py. I am on Python 3.6.1 and Django 1.11.4.


回答 4

简单的答案:是的。

最好是创建一个名为views的目录,然后在您的urls.py中执行以下操作:

import views
...
url(r'^classroom$', views.school.klass, name="classroom"),

Simple answer: Yes.

Best is to make a directory called views and then in your urls.py do:

import views
...
url(r'^classroom$', views.school.klass, name="classroom"),

回答 5

我将应用程序中的几乎所有视图都拆分为一个views文件夹(当然还有一个init .py)。但是,我不像某些答案所建议的那样将所有子视图导入init .py中。似乎工作正常。

I split almost all views in my apps into a views folder (with an init.py of course). I do not, however, import all of the subviews in the init.py like some of the answers have suggested. It seems to work just fine.


回答 6

由于Django只希望视图是可调用的对象,因此您可以将其放置在PYTHONPATH中的任何位置。因此,您可以例如仅创建一个新程序包myapp.views并将视图放入那里的多个模块中。自然,您将不得不更新urls.py和其他引用这些视图可调用对象的模块。

Since Django just expects a view to be a callable object, you can put then wherever you like in your PYTHONPATH. So you could for instance just make a new package myapp.views and put views into multiple modules there. You will naturally have to update your urls.py and other modules that reference these view callables.


回答 7

我一直在把它放在我的init .py中玩:

import os

currPath = os.path.realpath(os.path.dirname(__file__))

dirFiles = []
for root, dirs, files in os.walk(currPath):
    for name in files:
        if name.endswith('.py') and not name.startswith('_'): 
            dirFiles.append(name.strip('.py'))

for f in dirFiles:
    exec("from %s import %s" % (f,f))

我还是python新手,所以我仍在研究它对速度/安全性/易用性有什么影响。

I’ve been playing with putting this in my init.py:

import os

currPath = os.path.realpath(os.path.dirname(__file__))

dirFiles = []
for root, dirs, files in os.walk(currPath):
    for name in files:
        if name.endswith('.py') and not name.startswith('_'): 
            dirFiles.append(name.strip('.py'))

for f in dirFiles:
    exec("from %s import %s" % (f,f))

I’m still new to python, so I’m still looking at what effect it has on speed/security/ease of use.


回答 8

假设您有一个名为:的文件,password_generator.py然后在其中views.py添加:from password_generator import *

然后,您可以从调用该模块的功能views.py

Suppose if you have a file named: password_generator.py then inside views.py add: from password_generator import *

Then you can call that module’s function from views.py.


回答 9

文森特·德梅斯特Vincent Demeester)的回答太棒了!但是对我来说,瘾君子的回答就像一个魅力。我在迁移数据库时遇到困难。该错误指示导入了第一个模型的行,并指出无法识别我的应用程序模块。搜索了很多,但是找不到解决方案,但是后来我导入了这样的模型:

from ..models import ModelName

有效!!

Vincent Demeester‘s answer is superb! but for me addicted‘s answer worked like a charm. I faced difficulties in migrating database. The error indicates the line where the first model is imported and says could not recognize my app module. Searched a lot but could not find a solution but later on I imported the model like this:

from ..models import ModelName

It worked!!


如何使用Django Rest Framework包含相关的模型字段?

问题:如何使用Django Rest Framework包含相关的模型字段?

假设我们有以下模型:

class Classroom(models.Model):
    room_number = [....]

class Teacher(models.Model):
    name = [...]
    tenure = [...]
    classroom = models.ForeignKey(Classroom)

假设不是通过ManyRelatedPrimaryKeyField函数获得这样的结果:

{
    "room_number": "42", 
    "teachers": [
        27, 
        24, 
        7
    ]
},

让它返回包含完整相关模型表示的内容,例如:

{
    "room_number": "42", 
    "teachers": [
        {
           'id':'27,
           'name':'John',
           'tenure':True
        }, 
        {
           'id':'24,
           'name':'Sally',
           'tenure':False
        }, 
    ]
},

这可能吗?如果是这样,怎么办?这是一个坏主意吗?

Let’s say that we have the following model:

class Classroom(models.Model):
    room_number = [....]

class Teacher(models.Model):
    name = [...]
    tenure = [...]
    classroom = models.ForeignKey(Classroom)

Let’s say that instead of getting a result like this per the ManyRelatedPrimaryKeyField function:

{
    "room_number": "42", 
    "teachers": [
        27, 
        24, 
        7
    ]
},

have it return something that includes the full related model representation like:

{
    "room_number": "42", 
    "teachers": [
        {
           'id':'27,
           'name':'John',
           'tenure':True
        }, 
        {
           'id':'24,
           'name':'Sally',
           'tenure':False
        }, 
    ]
},

Is this possible? If so, how? And is this a bad idea?


回答 0

最简单的方法是使用depth参数

class ClassroomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Classroom
        depth = 1

但是,这仅包括前向关系的关系,在这种情况下,这并不是您真正需要的,因为教师字段是反向关系。

如果您有更复杂的要求(例如,包括反向关系,嵌套某些字段,但不嵌套其他字段,或者仅嵌套字段的特定子集),则可以嵌套序列化程序,例如…

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set')

    class Meta:
        model = Classroom

请注意,我们在序列化器字段上使用source参数来指定用作字段源的属性。我们可以通过使用模型上的related_name选项source来确保teachers属性存在,从而删除参数。Teacherclassroom = models.ForeignKey(Classroom, related_name='teachers')

要记住的一件事是,嵌套的序列化程序当前不支持写操作。对于可写表示形式,应使用常规的平面表示形式,例如pk或超链接。

The simplest way is to use the depth argument

class ClassroomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Classroom
        depth = 1

However, that will only include relationships for forward relationships, which in this case isn’t quite what you need, since the teachers field is a reverse relationship.

If you’ve got more complex requirements (eg. include reverse relationships, nest some fields, but not others, or nest only a specific subset of fields) you can nest serializers, eg…

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set')

    class Meta:
        model = Classroom

Note that we use the source argument on the serializer field to specify the attribute to use as the source of the field. We could drop the source argument by instead making sure the teachers attribute exists by using the related_name option on your Teacher model, ie. classroom = models.ForeignKey(Classroom, related_name='teachers')

One thing to keep in mind is that nested serializers do not currently support write operations. For writable representations, you should use regular flat representations, such as pk or hyperlinking.


回答 1

谢谢@TomChristie !!!你帮了我很多忙!我想稍微更新一下(由于遇到错误)

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set', many=True)

    class Meta:
        model = Classroom
        field = ("teachers",)

Thank you @TomChristie!!! You helped me a lot! I would like to update that a little (because of a mistake I ran into)

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set', many=True)

    class Meta:
        model = Classroom
        field = ("teachers",)

回答 2

这也可以通过使用打包为drf-flex-fields的非常方便的dandy django来完成。我们使用它,它非常棒。您只需安装它pip install drf-flex-fields,将其通过序列化器,添加expandable_fields并宾果游戏(下面的示例)。它还允许您使用点表示法指定深层嵌套关系。

from rest_flex_fields import FlexFieldsModelSerializer

class ClassroomSerializer(FlexFieldsModelSerializer):
    class Meta:
        model = Model
        fields = ("teacher_set",)
        expandable_fields = {"teacher_set": (TeacherSerializer, {"source": "teacher_set"})}

然后,将其添加?expand=teacher_set到您的URL中,并返回扩展的响应。希望有一天能对某人有所帮助。干杯!

This can also be accomplished by using a pretty handy dandy django packaged called drf-flex-fields. We use it and it’s pretty awesome. You just install it pip install drf-flex-fields, pass it through your serializer, add expandable_fields and bingo (example below). It also allows you to specify deep nested relationships by using dot notation.

from rest_flex_fields import FlexFieldsModelSerializer

class ClassroomSerializer(FlexFieldsModelSerializer):
    class Meta:
        model = Model
        fields = ("teacher_set",)
        expandable_fields = {"teacher_set": (TeacherSerializer, {"source": "teacher_set"})}

Then you add ?expand=teacher_set to your URL and it returns an expanded response. Hope this helps someone, someday. Cheers!


用于重命名模型和关系字段的Django迁移策略

问题:用于重命名模型和关系字段的Django迁移策略

我打算重命名现有Django项目中的多个模型,在该项目中,还有许多其他模型与我要重命名的模型具有外键关系。我相当确定这将需要多次迁移,但是我不确定确切的过程。

假设我从Django应用程序中的以下模型开始myapp

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

我想重命名该Foo模型,因为该名称实际上没有意义,并且会导致代码混乱,并且Bar会使名称更清晰。

根据我在Django开发文档中阅读的内容,我假设采用以下迁移策略:

第1步

修改models.py

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()

注意,的AnotherModel字段名称foo没有更改,但是关系已更新为Bar模型。我的理由是,我不应一次更改太多,并且如果将该字段名称更改为,则bar可能会丢失该列中的数据。

第2步

创建一个空迁移:

python manage.py makemigrations --empty myapp

第三步

编辑Migration在步骤2中创建的迁移文件中的类,RenameModel以将该操作添加到操作列表中:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

第4步

应用迁移:

python manage.py migrate

第5步

在中编辑相关字段名称models.py

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

第6步

创建另一个空迁移:

python manage.py makemigrations --empty myapp

步骤7

编辑Migration在步骤6中创建的迁移文件中的类,以将RenameField任何相关字段名称的操作添加到操作列表中:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

步骤8

应用第二次迁移:

python manage.py migrate

除了更新其余代码(视图,表单等)以反映新的变量名之外,这基本上是新的迁移功能如何起作用的吗?

另外,这似乎需要很多步骤。迁移操作可以某种方式压缩吗?

谢谢!

I’m planning to rename several models in an existing Django project where there are many other models that have foreign key relationships to the models I would like to rename. I’m fairly certain this will require multiple migrations, but I’m not sure of the exact procedure.

Let’s say I start out with the following models within a Django app called myapp:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

I want to rename the Foo model because the name doesn’t really make sense and is causing confusion in the code, and Bar would make for a much clearer name.

From what I have read in the Django development documentation, I’m assuming the following migration strategy:

Step 1

Modify models.py:

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()

Note the AnotherModel field name for foo doesn’t change, but the relation is updated to the Bar model. My reasoning is that I shouldn’t change too much at once and that if I changed this field name to bar I would risk losing the data in that column.

Step 2

Create an empty migration:

python manage.py makemigrations --empty myapp

Step 3

Edit the Migration class in the migration file created in step 2 to add the RenameModel operation to the operations list:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Step 4

Apply the migration:

python manage.py migrate

Step 5

Edit the related field names in models.py:

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

Step 6

Create another empty migration:

python manage.py makemigrations --empty myapp

Step 7

Edit the Migration class in the migration file created in step 6 to add the RenameField operation(s) for any related field names to the operations list:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

Step 8

Apply the 2nd migration:

python manage.py migrate

Aside from updating the rest of the code (views, forms, etc.) to reflect the new variable names, is this basically how the new migration functionality would work?

Also, this seems like a lot of steps. Can the migration operations be condensed in some way?

Thanks!


回答 0

因此,当我尝试此操作时,您似乎可以将步骤3-7压缩:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

如果不更新导入名称,例如admin.py甚至更旧的迁移文件(!),则可能会遇到一些错误。

更新:正如ceasaro所提到的,较新版本的Django通常能够检测并询问是否重命名了模型。因此,请先尝试manage.py makemigrations,然后检查迁移文件。

So when I tried this, it seems you can condense Step 3 – 7:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

You may get some errors if you don’t update the names where it’s imported e.g. admin.py and even older migration files (!).

Update: As ceasaro mentions, newer versions of Django are usually able to detect and ask if a model is renamed. So try manage.py makemigrations first and then check the migration file.


回答 1

最初,我认为Fiver的方法很适合我,因为迁移在第4步之前都可以正常进行。但是,在任何迁移中,从“ ForeignKeyField(Foo)”到“ ForeignKeyField(Bar)”的隐式更改均不相关。这就是为什么当我想重命名关系字段时迁移失败(步骤5-8)。这可能是由于我的案例中我的“ AnotherModel”和“ YetAnotherModel”是在其他应用中分派的。

因此,我设法按照以下步骤重命名我的模型和关系字段:

我改编自方法和otranzer的特别的特技。

因此,就像Fiver一样,我们在myapp中拥有

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

myotherapp中

class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

第1步:

将每个OneToOneField(Foo)或ForeignKeyField(Foo)转换为IntegerField()。(这会将相关Foo对象的ID保留为integerfield的值)。

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()

然后

python manage.py makemigrations

python manage.py migrate

第2步:(类似于Fiver的第2-4步)

更改型号名称

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

创建一个空迁移:

python manage.py makemigrations --empty myapp

然后像这样编辑它:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

最终

python manage.py migrate

第三步:

将您的IntegerField()转换回其先前的ForeignKeyField或OneToOneField,但使用新的Bar模型。(以前的整型字段存储的是id,因此django理解了这一点并重新建立了连接,这很酷。)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()

然后做:

python manage.py makemigrations 

非常重要的是,在这一步中,您必须修改每个新的迁移,并在RenameModel Foo-> Bar迁移上添加依赖项。因此,如果AnotherModel和YetAnotherModel都在myotherapp中,则在myotherapp中创建的迁移必须如下所示:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
        ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
    ]

    operations = [
        migrations.AlterField(
            model_name='anothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar'),
        ),
        migrations.AlterField(
            model_name='yetanothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar')
        ),
    ]

然后

python manage.py migrate

第4步:

最终,您可以重命名字段

class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_ridonkulous = models.BooleanField()

然后自动重命名

python manage.py makemigrations

(django应该询问您是否实际重命名了模型名称,请说是)

python manage.py migrate

就是这样!

这适用于Django1.8

At first, I thought that Fiver’s method worked for me because the migration worked well until step 4. However, the implicit changes ‘ForeignKeyField(Foo)’ into ‘ForeignKeyField(Bar)’ was not related in any migrations. This is why migration failed when I wanted to rename relationship fields (step 5-8). This might be due to the fact that my ‘AnotherModel’ and ‘YetAnotherModel’ are dispatched in other apps in my case.

So I managed to rename my models and relationship fields doing following below steps:

I adapted the method from this and particularly the trick of otranzer.

So like Fiver let’s say we have in myapp:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

And in myotherapp:

class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

Step 1:

Transform every OneToOneField(Foo) or ForeignKeyField(Foo) into IntegerField(). (This will keep the id of related Foo object as value of the integerfield).

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()

Then

python manage.py makemigrations

python manage.py migrate

Step 2: (Like step 2-4 from Fiver)

Change the model name

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

Create an empty migration:

python manage.py makemigrations --empty myapp

Then edit it like:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Eventually

python manage.py migrate

Step 3:

Transform Back your IntegerField() into their previous ForeignKeyField or OneToOneField but with the new Bar Model. (The previous integerfield was storing the id, so django understand that and reestablish the connection, which is cool.)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()

Then do:

python manage.py makemigrations 

Very importantly, at this step you have to modify every new migrations and add the dependency on the RenameModel Foo-> Bar migrations. So if both AnotherModel and YetAnotherModel are in myotherapp the created migration in myotherapp must look like this:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
        ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
    ]

    operations = [
        migrations.AlterField(
            model_name='anothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar'),
        ),
        migrations.AlterField(
            model_name='yetanothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar')
        ),
    ]

Then

python manage.py migrate

Step 4:

Eventually you can rename your fields

class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_ridonkulous = models.BooleanField()

and then do automatic renaming

python manage.py makemigrations

(django should ask you if you actually renamed the modelname, say yes)

python manage.py migrate

And that’s it!

This works on Django1.8


回答 2

我需要做同样的事情并遵循。我一次更改了模型(Fiver回答中的步骤1和5)。然后创建模式迁移,但将其编辑为:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

这工作得很好。我所有的现有数据都显示出来,其他所有表都引用了Bar fine。

从这里开始:https : //hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/

I needed to do the same thing and follow. I changed the model all at once (Steps 1 and 5 together from Fiver’s answer). Then created a schema migration but edited it to be this:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

This worked perfectly. All my existing data showed up, all the other tables referenced Bar fine.

from here: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/


回答 3

对于Django 1.10,我仅通过运行Makemigrations,然后为该应用程序迁移,就设法更改了两个模型类名称(包括ForeignKey和数据)。对于Makemigrations步骤,我必须确认我想更改表名称。迁移更改表的名称没有问题。

然后,我更改了ForeignKey字段的名称以使其匹配,然后Makemigrations再次要求我确认要更改名称。迁移比进行更改。

因此,我分两步进行了此操作,而无需进行任何特殊的文件编辑。起初我确实得到了错误,因为我忘记更改admin.py文件,如@wasibigeek所述。

For Django 1.10, I managed to change two model class names (including a ForeignKey, and with data) by simply running Makemigrations, and then Migrate for the app. For the Makemigrations step, I had to confirm that I wanted to change the table names. Migrate changed the names of the tables without a problem.

Then I changed the name of the ForeignKey field to match, and again was asked by Makemigrations to confirm that I wanted to change the name. Migrate than made the change.

So I took this in two steps without any special file editing. I did get errors at first because I forgot to change the admin.py file, as mentioned by @wasibigeek.


回答 4

我也遇到了v.thorey所描述的问题,发现他的方法非常有用,但可以凝结为更少的步骤,实际上是步骤5至8,如Fiver所描述的,而没有步骤1-4,只是步骤7需要更改为在步骤3之下。总体步骤如下:

步骤1:在models.py中编辑相关字段名称

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

步骤2:建立一个空的迁移

python manage.py makemigrations --empty myapp

步骤3:在步骤2中创建的迁移文件中编辑Migration类

class Migration(migrations.Migration):

dependencies = [
    ('myapp', '0001_initial'), 
]

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]

步骤4:套用迁移

python manage.py migrate

完成了

PS我已经在Django 1.9上尝试过这种方法

I also faced the problem as v.thorey described and found that his approach is very useful but can be condensed into fewer steps which are actually step 5 to 8 as Fiver described without step 1 to 4 except that step 7 needs to be changed as my below step 3. The overall steps are as follow:

Step 1: Edit the related field names in models.py

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

Step 2: Create an empty migration

python manage.py makemigrations --empty myapp

Step 3: Edit the Migration class in the migration file created in Step 2

class Migration(migrations.Migration):

dependencies = [
    ('myapp', '0001_initial'), 
]

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]

Step 4: Apply the migration

python manage.py migrate

Done

P.S. I’ve tried this approach on Django 1.9


回答 5

我正在使用Django版本1.9.4

我已按照以下步骤操作:

我刚刚将模型oldName重命名为NewName Run python manage.py makemigrations。它将要求您 Did you rename the appname.oldName model to NewName? [y/N]选择Y

运行python manage.py migrate,它将要求您

以下内容类型是陈旧的,需要删除:

appname | oldName
appname | NewName

通过外键与这些内容类型相关的任何对象也将被删除。您确定要删除这些内容类型吗?如果不确定,请回答“否”。

Type 'yes' to continue, or 'no' to cancel: Select No

它为我重命名并将所有现有数据迁移到新的命名表。

I am using Django version 1.9.4

I have follow the following steps:-

I have just rename the model oldName to NewName Run python manage.py makemigrations. It will ask you for Did you rename the appname.oldName model to NewName? [y/N] select Y

Run python manage.py migrate and it will ask you for

The following content types are stale and need to be deleted:

appname | oldName
appname | NewName

Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you’re unsure, answer ‘no’.

Type 'yes' to continue, or 'no' to cancel: Select No

It rename and migrate all existing data to new named table for me.


回答 6

不幸的是,我发现了重命名迁移的问题(每个django 1.x),这些问题将旧表名保留在数据库中。

Django甚至没有在旧表上尝试任何操作,只是重命名了自己的模型。外键和索引通常存在相同的问题-Django无法正确跟踪那里的更改。

最简单的解决方案(解决方法):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only

真正的解决方案(一种在2次提交中切换所有索引,约束,触发器,名称等的简便方法,而对于较小的表则如此):

提交A:

  1. 创建旧模型相同的模型
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. 切换代码以Bar仅与新模型一起使用。(包括架构上的所有关系)

在迁移准备中RunPython,它将数据从Foo复制到Bar(包括idFoo)

  1. 可选的优化(如果需要更大的表)

提交B :(不要着急,整个团队迁移后都要做)

  1. 旧型号的安全降落 Foo

进一步清理:

  • 壁球迁徙

Django中的错误:

Unfortunately, I found problems (each django 1.x) with rename migration which leave old table names in the database.

Django doesn’t even try anything on the old table, just rename his own model. The same problem with foreign keys, and indices in general – changes there are not tracked properly by Django.

The simplest solution (workaround):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only

The real solution (an easy way to switch all indices, constraints, triggers, names, etc in 2 commits, but rather for smaller tables):

commit A:

  1. create the same model as the old one
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. switch code to work with new model Bar only. (including all relations on the schema)

In migration prepare RunPython, which copy data from Foo to Bar (including id of Foo)

  1. optional optimization (if needed for greater tables)

commit B: (no rush, do it when an entire team is migrated)

  1. safe drop of the old model Foo

further cleanup:

  • squash on migrations

bug in Django:


回答 7

只是想确认并添加ceasaro评论。Django 2.0现在似乎可以自动执行此操作。

我在Django 2.2.1上,我所要做的只是重命名模型并运行makemigrations

在这里,它询问我是否已将特定的类从重命名AB,我选择是,然后进行了迁移,并且一切似乎都可以正常工作。

注意我没有在project / migrations文件夹内的任何文件中重命名旧模型名称。

Just wanted to confirm and add upon ceasaro comment. Django 2.0 seems to do this automatically now.

I’m on Django 2.2.1, all I had to do what to rename the model and run makemigrations.

Here it asks if I had renamed the specific class from A to B, i chose yes and ran migrate and all seems to work.

Note I did not rename the old model name in any files inside the project/migrations folder.


回答 8

我需要重命名几个表。但是Django仅注意到一种模型重命名。发生这种情况是因为Django反复遍历添加的模型,然后删除了模型。对于每一对,它会检查它们是否属于同一应用,并且具有相同的字段。只有一个表没有要重命名的表的外键(您记得,外键包含模型类名称)。换句话说,只有一个表没有字段更改。这就是为什么它被注意到。

因此,解决方案是一次重命名一个表,在中更改模型类名称models.py,可能是views.py,然后进行迁移。之后,检查您的代码是否有其他引用(模型类名称,相关(查询)名称,变量名称)。如果需要,请进行迁移。然后,有选择地将所有这些迁移合并为一个(确保也复制导入)。

I needed to rename a couple of tables. But only one model rename was noticed by Django. That happened because Django iterates over added, then removed models. For each pair it checks if they’re of the same app and have identical fields. Only one table had no foreign keys to tables to be renamed (foreign keys contain model class name, as you remember). In other words, only one table had no field changes. That’s why it was noticed.

So, the solution is to rename one table at a time, changing model class name in models.py, possibly views.py, and making a migration. After that inspect your code for other references (model class names, related (query) names, variable names). Make a migration, if needed. Then, optionally combine all these migrations into one (make sure to copy imports as well).


回答 9

我会用@ceasaro的话,对他对这个答案的评论。

较新版本的Django可以检测到更改并询问已完成的操作。我还要补充一点,Django可能会混合一些迁移命令的执行顺序。

这将是明智的,适用小的变化和运行makemigrations以及migrate如果发生错误的迁移文件进行编辑。

某些行的执行顺序可以更改,以免出错。

I would make @ceasaro words, mine on his comment on this answer.

Newer versions of Django can detect changes and ask about what was done. I also would add that Django might mix the order of execution of some migration commands.

It would be wise to apply small changes and run makemigrations and migrate and if the error occurs the migration file can be edited.

Some lines order of execution can be changed to avoid erros.


回答 10

如果您使用的是像PyCharm这样的优秀IDE,则可以右键单击模型名称并进行重构->重命名。这免除了您遍历引用该模型的所有代码的麻烦。然后运行makemigrations并进行迁移。Django 2+只会确认名称更改。

If you are using a good IDE like PyCharm you can right click on the model name and do a refactor -> rename. This saves you the trouble of going through all your code that references the model. Then run makemigrations and migrate. Django 2+ will simply confirm name change.


回答 11

我将Django从版本10升级到版本11:

sudo pip install -U Django

-U用于“升级”),它解决了问题。

I upgraded Django from version 10 to version 11:

sudo pip install -U Django

(-U for “upgrade”) and it solved the problem.


Django模型表单对象的自动创建日期?

问题:Django模型表单对象的自动创建日期?

自动设置对象创建日期以及记录该对象上次更新时间的字段的最佳方法是什么?

models.py:

created_at = models.DateTimeField(False, True, editable=False)
updated_at = models.DateTimeField(True, True, editable=False)

views.py:

if request.method == 'POST':
    form = MyForm(request.POST)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.user = request.user
        obj.save()
        return HttpResponseRedirect('obj_list')

我得到错误:

objects_object.created_at may not be NULL

我是否必须自己手动设置此值?我以为那是传递给参数的重点DateTimeField(或者它们只是默认值,由于我已经设置了editable=False它们,所以它们不会在表单上显示,因此不会在请求中提交,因此也不会得到放入表格?)。

最好的方法是什么?一种__init__方法是什么?

What’s the best way to set a creation date for an object automatically, and also a field that will record when the object was last updated?

models.py:

created_at = models.DateTimeField(False, True, editable=False)
updated_at = models.DateTimeField(True, True, editable=False)

views.py:

if request.method == 'POST':
    form = MyForm(request.POST)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.user = request.user
        obj.save()
        return HttpResponseRedirect('obj_list')

I get the error:

objects_object.created_at may not be NULL

Do I have to manually set this value myself? I thought that was the point of the parameters passed to DateTimeField (or are they just defaults, and since I’ve set editable=False they don’t get displayed on the form, hence don’t get submitted in the request, and therefore don’t get put into the form?).

What’s the best way of doing this? An __init__ method?


回答 0

您可以分别为和使用auto_nowauto_now_add选项。updated_atcreated_at

class MyModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

You can use the auto_now and auto_now_add options for updated_at and created_at respectively.

class MyModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

回答 1

好吧,上面的答案是正确的,auto_now_addauto_now可以做到,但是最好创建一个抽象类,并在需要created_atupdated_at字段的任何模型中使用它。

class TimeStampMixin(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

现在,您可以在任何要使用它的地方进行简单的继承,并且可以在任何喜欢的模型中使用时间戳。

class Posts(TimeStampMixin):
    name = models.CharField(max_length=50)
    ...
    ...

这样,您可以在Django DRY中利用面向对象的可重用性(不要重复自己)

Well, the above answer is correct, auto_now_add and auto_now would do it, but it would be better to make an abstract class and use it in any model where you require created_at and updated_at fields.

class TimeStampMixin(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

Now anywhere you want to use it you can do a simple inherit and you can use timestamp in any model you make like.

class Posts(TimeStampMixin):
    name = models.CharField(max_length=50)
    ...
    ...

In this way, you can leverage object-oriented reusability, in Django DRY(don’t repeat yourself)