标签归档:Django

Django 1.7-makemigrations无法检测到更改

问题:Django 1.7-makemigrations无法检测到更改

如标题所述,我似乎无法使迁移正常进行。

该应用程序最初的版本低于1.6,因此我知道迁移最初不会进行,并且如果我运行,python manage.py migrate我会得到:

Operations to perform:
  Synchronize unmigrated apps: myapp
  Apply all migrations: admin, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  No migrations to apply.

如果我对中的任何模型进行了更改myapp,它仍会像预期的那样未迁移。

但是如果我跑步,python manage.py makemigrations myapp我会得到:

No changes detected in app 'myapp'

似乎与我运行命令的方式或方式无关紧要,它永远不会将应用程序检测为更改,也不会向该应用程序添加任何迁移文件。

是否有任何方法可以迫使应用程序迁移并实质上说“这是我的工作基础”或其他内容?还是我错过了什么?

如果有帮助的话,我的数据库就是PostgreSQL。

As the title says, I can’t seem to get migrations working.

The app was originally under 1.6, so I understand that migrations won’t be there initially, and indeed if I run python manage.py migrate I get:

Operations to perform:
  Synchronize unmigrated apps: myapp
  Apply all migrations: admin, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  No migrations to apply.

If I make a change to any models in myapp, it still says unmigrated, as expected.

But if I run python manage.py makemigrations myapp I get:

No changes detected in app 'myapp'

Doesn’t seem to matter what or how I run the command, it’s never detecting the app as having changes, nor is it adding any migration files to the app.

Is there any way to force an app onto migrations and essentially say “This is my base to work with” or anything? Or am I missing something?

My database is a PostgreSQL one if that helps at all.


回答 0

如果要从django 1.6中制作的现有应用程序进行转换,则需要执行文档中列出的一个第一步(如我所知):

python manage.py makemigrations your_app_label

该文档没有明显表明您需要在命令中添加应用标签,因为它首先告诉您要做的是python manage.py makemigrations失败。最初的迁移是在1.7版中创建的应用程序完成的,但是如果您来自1.6版,则不会进行。有关更多详细信息,请参见文档中的“向应用程序添加迁移”

If you’re changing over from an existing app you made in django 1.6, then you need to do one pre-step (as I found out) listed in the documentation:

python manage.py makemigrations your_app_label

The documentation does not make it obvious that you need to add the app label to the command, as the first thing it tells you to do is python manage.py makemigrations which will fail. The initial migration is done when you create your app in version 1.7, but if you came from 1.6 it wouldn’t have been carried out. See the ‘Adding migration to apps’ in the documentation for more details.


回答 1

可能由于以下原因而发生:

  1. 您没有在以下位置的INSTALLED_APPS列表中添加应用程序settings.py (您必须在应用程序文件夹的apps.py中添加应用程序名称或虚线路径到AppConfig的子类,具体取决于所使用的Django版本)。请参阅文档:INSTALLED_APPS
  2. migrations这些应用程序内没有文件夹。(解决方案:只需创建该文件夹)。
  3. 您没有这些应用程序__init__.py文件migrations夹中的文件。(解决方案:只需创建一个名称为__init__.py的空文件)
  4. __init__.py的应用文件夹中没有文件。(解决方案:只需创建一个名称为__init__.py的空文件)
  5. models.py的应用程序中没有文件
  6. 您的Python类(假定是模型)models.py不会继承django.db.models.Model
  7. 您在定义模型时存在语义错误 models.py

注意: 一个常见的错误是migrations.gitignore文件中添加文件夹。从远程存储库克隆后,本地存储库中的文件migrations夹和/或__init__.py文件将丢失。这导致问题。

我建议通过在文件中添加以下几行来忽略迁移.gitignore文件

*/migrations/*
!*/migrations/__init__.py

This may happen due to the following reasons:

  1. You did not add the app in INSTALLED_APPS list in settings.py (You have to add either the app name or the dotted path to the subclass of AppConfig in apps.py in the app folder, depending on the version of django you are using). Refer documentation: INSTALLED_APPS
  2. You don’t have migrations folder inside those apps. (Solution: just create that folder).
  3. You don’t have __init__.py file inside migrations folder of those apps. (Solution: Just create an empty file with name __init__.py)
  4. You don’t have an __init__.py file inside the app folder. (Solution: Just create an empty file with name __init__.py)
  5. You don’t have a models.py file in the app
  6. Your Python class (supposed to be a model) in models.py doesn’t inherit django.db.models.Model
  7. You have some semantic mistake in definition of models in models.py

Note: A common mistake is to add migrations folder in .gitignore file. When cloned from remote repo, migrations folder and/or __init__.py files will be missing in local repo. This causes problem.

I suggest to gitignore migration files by adding the following lines to .gitignore file

*/migrations/*
!*/migrations/__init__.py

回答 2

好的,看来我错过了一个明显的步骤,但是在其他人也这样做的情况下发布了此步骤。

当升级到1.7时,我的模型变成了不受管理的(managed = False)-我像True以前一样拥有它们,但似乎已还原。

删除该行(默认情况下为True)然后makemigrations立即运行就构成了一个迁移模块,现在它可以正常工作了。makemigrations将不适用于非托管表(事后看来很明显)

Ok, looks like I missed an obvious step, but posting this in case anyone else does the same.

When upgrading to 1.7, my models became unmanaged (managed = False) – I had them as True before but seems it got reverted.

Removing that line (To default to True) and then running makemigrations immediately made a migration module and now it’s working. makemigrations will not work on unmanaged tables (Which is obvious in hindsight)


回答 3

我的解决方案未在此处介绍,因此我将其发布。我一直在使用syncdb一个项目-只是为了使其启动并运行。然后,当我尝试开始使用Django迁移时,它首先伪造了它们,然后说是“ OK”,但数据库没有任何反应。

我的解决方案是只删除应用程序的所有迁移文件,以及django_migrations表中应用程序迁移的数据库记录。

然后,我进行了以下初步迁移:

./manage.py makemigrations my_app

其次是:

./manage.py migrate my_app

现在,我可以毫无问题地进行迁移了。

My solution was not covered here so I’m posting it. I had been using syncdb for a project–just to get it up and running. Then when I tried to start using Django migrations, it faked them at first then would say it was ‘OK’ but nothing was happening to the database.

My solution was to just delete all the migration files for my app, as well as the database records for the app migrations in the django_migrations table.

Then I just did an initial migration with:

./manage.py makemigrations my_app

followed by:

./manage.py migrate my_app

Now I can make migrations without a problem.


回答 4

同意@furins。如果一切似乎都井然有序,但是仍然出现此问题,请检查是否有任何名称与要在Model类中添加的属性相同的属性方法。

  1. 删除名称与要添加的属性类似的方法。
  2. manage.py makemigrations my_app
  3. manage.py迁移my_app
  4. 重新添加方法。

Agree with @furins. If everything seems to be in order and yet this problem arises, checkout if there is any property method with same title as the attribute which you are trying to add in the Model class.

  1. Remove method with similar name as attribute you are adding.
  2. manage.py makemigrations my_app
  3. manage.py migrate my_app
  4. Add the methods back.

回答 5

这是一个愚蠢的错误,但是在模型类的字段声明行的末尾有一个逗号,使该行无效。

复制粘贴def时会发生这种情况。从迁移本身定义为数组。

虽然这可能会帮助某人:-)

This is kind of a stupid mistake to make, but having an extra comma at the end of the field declaration line in the model class, makes the line have no effect.

It happens when you copy paste the def. from the migration, which itself is defined as an array.

Though maybe this would help someone :-)


回答 6

也许我来不及了,但是您是否尝试migrations在应用中创建一个__init__.py文件夹,其中包含文件?

Maybe I am too late but did you try to have a migrations folder in your app with a __init__.py file in it?


回答 7

也许这会帮助某人。我正在使用嵌套应用程序。project.appname,我实际上在INSTALLED_APPS中有project和project.appname。从INSTALLED_APPS中删除项目可以检测到更改。

Maybe this will help someone. I was using a nested app. project.appname and I actually had project and project.appname in INSTALLED_APPS. Removing project from INSTALLED_APPS allowed the changes to be detected.


回答 8

答案是在此stackoverflow帖子上,由cdvv7788 在Django 1.7中进行迁移

如果是第一次迁移该应用程序,则必须使用:

manage.py makemigrations myappname完成后,您可以执行以下操作:

manage.py migration如果您的应用程序已包含在数据库中,请修改其模型并且不更新makemigrations上的更改,则您可能尚未迁移它。将您的模型改回其原始形式,运行第一个命令(使用应用程序名称)并迁移…它将对其进行伪造。完成后,将更改放回模型中,请运行makemigrations并再次进行迁移,它应该可以正常工作。

我遇到了完全相同的麻烦,并且执行上述操作完全正常。

我已将django应用程序移至cloud9,由于某种原因,我从未进行过初始迁移。

The answer is on this stackoverflow post, by cdvv7788 Migrations in Django 1.7

If it is the first time you are migrating that app you have to use:

manage.py makemigrations myappname Once you do that you can do:

manage.py migrate If you had your app in database, modified its model and its not updating the changes on makemigrations you probably havent migrated it yet. Change your model back to its original form, run the first command (with the app name) and migrate…it will fake it. Once you do that put back the changes on your model, run makemigrations and migrate again and it should work.

I was having the exact same trouble and doing the above worked perfectly.

I had moved my django app to cloud9 and for some reason I never caught the initial migration.


回答 9

以下为我工作:

  1. 将应用名称添加到settings.py
  2. 使用’python manage.py makemigrations’
  3. 使用’python manage.py migration’

为我工作:Python 3.4,Django 1.10

Following worked for me:

  1. Add the app name to settings.py
  2. use ‘python manage.py makemigrations’
  3. use ‘python manage.py migrate’

Worked for me: Python 3.4, Django 1.10


回答 10

像我这样不喜欢迁移的人可以使用以下步骤。

  1. 删除您要同步的更改。
  2. 运行python manage.py makemigrations app_label初始迁移。
  3. python manage.py migrate进行更改之前,运行以创建表。
  4. 粘贴您在第一步中删除的更改。
  5. 运行步骤2.和3.。

如果您对这些步骤感到困惑,请阅读迁移文件。更改它们以更正您的架构或删除不需要的文件,但不要忘记更改下一个迁移文件的依赖项;)

我希望这会在将来对某人有所帮助。

People like me who don’t like migrations can use steps below.

  1. Remove changes what you want to sync.
  2. Run python manage.py makemigrations app_label for the initial migration.
  3. Run python manage.py migrate for creating tables before you make changes.
  4. Paste changes which you remove at first step.
  5. Run 2. and 3. steps.

If you confused any of these steps, read the migration files. Change them to correct your schema or remove unwanted files but don’t forget to change next migration file’s dependencies part ;)

I hope this will help someone in future.


回答 11

你要检查settings.pyINSTALLED_APPS列表,并确保所有与模型的应用程序在那里上市。

makemigrations在项目文件夹中运行意味着它将寻找更新与settings.py项目中包含的所有应用程序相关的所有表。包含它后,makemigrations将自动包含该应用程序(这样可以节省大量工作,因此您不必makemigrations app_name为项目/站点中的每个应用程序都运行)。

You want to check the settings.py in the INSTALLED_APPS list and make sure all the apps with models are listed in there.

Running makemigrations in the project folder means it will look to update all the tables related to all the apps included in settings.py for the project. Once you include it, makemigrations will automatically include the app (this saves a lot of work so you don’t have to run makemigrations app_name for every app in your project/site).


回答 12

以防万一您有一个不能由makemigrations标识的特定字段:检查两次是否具有相同名称的属性。

例:

field = django.db.models.CharField(max_length=10, default = '', blank=True, null=True)

# ... later

@property
def field(self):
    pass

该属性将“覆盖”字段定义,因此更改不会被 makemigrations

Just in case you have a specific field that does not get identified by makemigrations: check twice if you have a property with the same name.

example:

field = django.db.models.CharField(max_length=10, default = '', blank=True, null=True)

# ... later

@property
def field(self):
    pass

the property will “overwrite” the field definition so changes will not get identified by makemigrations


回答 13

确保您的模型不是abstract。我实际上犯了那个错误,花了一段时间,所以我以为会发布它。

Make sure your model is not abstract. I actually made that mistake and it took a while, so I thought I’d post it.


回答 14

添加此答案是因为只有此方法对我有帮助。

我删除了migrations文件夹run makemigrationsmigrate
它仍然说:没有迁移申请。

我转到migrate文件夹并打开了最后一个创建的文件,
注释了我想要的迁移(已检测到并在此输入)
migrate再次运行。

这基本上是手动编辑迁移文件。
仅当您了解文件内容时,才执行此操作。

Adding this answer because only this method helped me.

I deleted the migrations folder run makemigrations and migrate.
It still said: No migrations to apply.

I went to migrate folder and opened the last created file,
comment the migration I wanted(It was detected and entered there)
and run migrate again.

This basically editing the migrations file manually.
Do this only if you understand the file content.


回答 15

schemamigration my_app --initial重命名旧的迁移文件夹后是否使用过?试试吧。可能会工作。如果不是,请尝试重新创建数据库并进行syncdb + migrate。它对我有用…

Did u use schemamigration my_app --initial after renaming old migration folder? Try it. Might work. If not – try to recreate the database and make syncdb+migrate. It worked for me…


回答 16

遇到相同的问题确保您在models.py中定义了任何类,您必须必须继承models.Model类。

class Product(models.Model):
    title = models.TextField()
    description = models.TextField()
    price = models.TextField()

Had the same problem Make sure whatever classes you have defined in models.py, you must have to inherit models.Model class.

class Product(models.Model):
    title = models.TextField()
    description = models.TextField()
    price = models.TextField()

回答 17

我不得不两次运行makemigrations和各种奇怪的行为时遇到了同样的问题。事实证明,问题的根源在于我正在使用一个函数来设置模型中的默认日期,因此每次我进行makemigrations时,迁移都会检测到更改。这个问题的答案使我走上了正确的轨道:避免进行重新创建日期字段的迁移

I had the same problem with having to run makemigrations twice and all sorts of strange behaviour. It turned out the root of the problem was that I was using a function to set default dates in my models so migrations was detecting a change every time I ran makemigrations. The answer to this question put me on the right track: Avoid makemigrations to re-create date field


回答 18

我最近将Django从1.6升级到1.8,并且几乎没有应用和迁移。我使用了south并schemamigrations在Django 1.6中创建了迁移,而在Django 1.8中删除了该迁移。

当我在升级后添加新型号时,该makemigrations命令未检测到任何更改。然后,我尝试了@drojf建议的解决方案(第一个答案),它工作正常,但未能应用假的初始迁移(python manage.py --fake-initial)。我这样做是因为我的表(旧表)已经创建。

最终,这对我有用,从models.py中删除了新模型(或模型更改),然后必须删除(或重命名以进行安全备份)所有应用程序的迁移文件夹,并manage.py为所有应用程序运行python makemigrations,然后执行了python manage.py migrate --fake-initial。这就像一个魅力。为所有应用创建初始迁移并进行伪初始迁移后,便添加了新模型,并遵循makemigrations该应用的常规流程进行迁移。现在已检测到更改,一切正常。

我只是想在这里分享它,如果有人遇到相同的问题(schemamigrations他们的应用程序有问题),可能会对他们有所帮助:)

I recently upgraded Django from 1.6 to 1.8 and had few apps and migrations for them. I used south and schemamigrations for creating migrations in Django 1.6, which is dropped in Django 1.8.

When I added new models after upgrade, the makemigrations command wasn’t detecting any changes. And then I tried the solution suggested by @drojf (1st answer), it worked fine, but failed to apply fake initial migration (python manage.py --fake-initial). I was doing this as my tables (old tables) were already created.

Finally this worked for me, removed new models (or model changes) from models.py and then had to delete (or rename for safety backup) migrations folder of all apps and run python manage.py makemigrations for all apps, then did python manage.py migrate --fake-initial. This worked like a charm. Once initial migration is created for all apps and fake initial migrated, then added new models and followed regular process of makemigrations and migrate on that app. The changes were detected now and everything went fine.

I just thought of sharing it here, if someone faces same problem (having schemamigrations of south for their apps), it might help them :)


回答 19

也许可以帮助某人,但我遇到了同样的问题。

我已经用序列化程序类和视图创建了两个表。因此,当我想更新时,出现了此错误。

我按照以下步骤操作:

  1. 我做了 .\manage.py makemigrations app
  2. 我执行了 .\manage.py migrate
  3. 我删除了我的两个表 models.py
  4. 我从序列化程序和视图类中删除了对表的所有引用。
  5. 我执行了step 12
  6. 我只是在 models.py
  7. 我再次执行步骤5
  8. 我恢复了所有更改。

如果您正在使用Pycharm,则本地历史记录将非常有帮助。

Maybe that can help someone, I had the same problem.

I’ve already created two tables with the serializer class and the views. So when I wanted to updated, I had this error.

I followed this steps:

  1. I made .\manage.py makemigrations app
  2. I executed .\manage.py migrate
  3. I erased both tables of my models.py
  4. I erased all reference to my tables from serializer and view class.
  5. I executed step 1 and 2.
  6. I retrieved my changes just in the models.py
  7. I executed again step 5.
  8. I restored all my changes.

If you’re working with Pycharm, local history is very helpfull.


回答 20

也许这会帮助某人。

我已经删除了,models.py并希望makemigrations创建DeleteModel语句。

记住要删除*.pyc文件!

Maybe this will help someone.

I’ve deleted my models.py and expected makemigrations to create DeleteModel statements.

Remember to delete *.pyc files!


回答 21

./manage makemigrations
./manage migrate

迁移会跟踪对数据库的更改,因此,如果您从非托管更改为托管,则需要确保您的数据库表与您要处理的模型有关的最新信息。

如果您仍处于开发模式,我个人决定删除我的IDE以及与我的模型相关的django_migrations表中的迁移文件,然后重新运行上述命令。

记住:如果您的迁移在IDE中以_001结尾,在数据库中以_003结尾。Django仅会查看您是否有以_004结尾的迁移来更新任何内容。

2(代码和数据库迁移)是链接在一起的,并且可以协同工作。

快乐的编码。

./manage makemigrations
./manage migrate

Migrations track changes to DB so if youre changing from unmanaged to managed, you’ll need to make sure that youre database table is up to date relating to the Model you’re dealing with.

If you are still in dev mode, I personally decided to delete the migration files in my IDE as well as in the django_migrations table relating to my Model and rerun the above command.

REMEMBER: if you have a migration that ends with _001 in your IDE & _003 in your database. Django will only see if you have a migration ending with _004 for anything to update.

The 2 (code & db migrations) are linked and work in tandem.

Happy coding.


回答 22

  1. 删除您要同步的更改。
  2. 运行python manage.py makemigrations app_label进行初始迁移。
  3. 进行更改之前,请运行python manage.py migration来创建表。
  4. 粘贴您在第一步中删除的更改。
  5. 运行步骤2和3。
  1. Remove changes what you want to sync.
  2. Run python manage.py makemigrations app_label for the initial migration.
  3. Run python manage.py migrate for creating tables before you make changes.
  4. Paste changes which you remove at first step.
  5. Run 2. and 3. steps

回答 23

添加了此答案,因为上面没有其他可用的方法适合我。

在我的情况下,发生了更奇怪的事情(Django 1.7版本),在我的models.py文件的末尾有一个“额外”行(这是一个空行),当我执行python manage.py makemigrations命令时,结果是:“未检测到更改”。

要解决此问题,我删除了我的models.py文件末尾的“空白行”,并再次运行了该命令,所有问题均已修复,并且检测到对models.py所做的所有更改!

Added this answer because none of other available above worked for me.

In my case something even more weird was happening (Django 1.7 Version), In my models.py I had an “extra” line at the end of my file (it was a blank line) and when I executed the python manage.py makemigrations command the result was: “no changes detected”.

To fix this I deleted this “blank line” that was at the end of my models.py file and I did run the command again, everything was fixed and all the changes made to models.py were detected!


回答 24

您可能需要使用以下命令来伪造初始迁移

python manage.py migrate --fake-initial

You may need to fake the initial migrations using the command below

python manage.py migrate --fake-initial

回答 25

首先,此解决方案适用于在heroku服务器上部署期间遇到相同问题的用户,而我也面临相同的问题。

要进行部署,有一个强制性步骤是在settings.py文件中添加django_heroku.settings(locals())。

更改:当我将上述行更改为django_heroku.settings(locals(),database = False)时,它可以正常工作。

First this solution is applicable to those who are facing the same issue during deployment on heroku server, I was facing same issue.

To deploy, there is a mandatory step which is to add django_heroku.settings(locals()) in settings.py file.

Changes: When I changed the above line to django_heroku.settings(locals(), databases=False), it worked flawlessly.


回答 26

就我而言,我需要将模型添加到定义了模型的models文件夹的_ init _.py文件中:

from myapp.models.mymodel import MyModel

In my case I needed to add my model to the _init_.py file of the models folder where my model was defined:

from myapp.models.mymodel import MyModel

回答 27

添加我的2c,因为这些解决方案都不适合我,但这确实…

我刚刚运行manage.py squashmigrations并删除了旧的迁移(django.migrations数据库表中的文件和行)。

在最后一个迁移文件中,这样留下了一行:

replaces = [(b'my_app', '0006_auto_20170713_1735'), (b'my_app', '0007_auto_20170713_2003'), (b'my_app', '0008_auto_20170713_2004')]

这显然使Django感到困惑,并导致了奇怪的行为:运行manage.py makemigrations my_app将重新创建初始迁移,就好像它们不存在一样。删除replaces...线路可解决问题!

Adding my 2c, since none of these solutions worked for me, but this did…

I had just run manage.py squashmigrations and removed the old migrations (both the files and lines in the the django.migrations database table).

This left a line like this in the last migration file:

replaces = [(b'my_app', '0006_auto_20170713_1735'), (b'my_app', '0007_auto_20170713_2003'), (b'my_app', '0008_auto_20170713_2004')]

This apparently confused Django and caused weird behavior: running manage.py makemigrations my_app would recreate the initial migration as if none existed. Removing the replaces... line fixed the problem!


回答 28

python manage.py makemigrations帐户“帐户”的迁移:accounts \ migrations \ 0001_initial.py-创建模型客户-创建模型标签-创建模型产品-创建模型订单

注意:这里的“帐户”是我的应用名称

python manage.py makemigrations accounts Migrations for ‘accounts’: accounts\migrations\0001_initial.py – Create model Customer – Create model Tag – Create model Product – Create model Order

Note: here “accounts” is my app name


在Django中使用Pylint

问题:在Django中使用Pylint

我非常想将pylint集成到我的python项目的构建过程中,但是我遇到了一个问题:我发现一种非常有用的错误类型:– E1101: *%s %r has no %r member*在使用通用django字段时不断报告错误, 例如:

E1101:125:get_user_tags: Class 'Tag' has no 'objects' member

这是由以下代码引起的:

def get_user_tags(username):
   """
   Gets all the tags that username has used.

   Returns a query set.
   """
   return Tag.objects.filter(  ## This line triggers the error.
       tagownership__users__username__exact=username).distinct()

# Here is the Tag class, models.Model is provided by Django:
class Tag(models.Model):
   """
   Model for user-defined strings that help categorize Events on
   on a per-user basis.
   """
   name = models.CharField(max_length=500, null=False, unique=True)

   def __unicode__(self):
       return self.name

如何调整Pylint以适当考虑诸如对象之类的字段?(我也研究了Django的源代码,但无法找到的实现objects,因此我怀疑它不是“只是”一个类字段。另一方面,我对python还是很陌生,所以我可能已经忽略了一些东西。)

编辑:我发现告诉pylint不要警告这些警告的唯一方法是阻止所有类型为(E1101)的错误,这是不可接受的解决方案,因为(在我看来)这是一个非常有用的错误。如果还有另一种方法,而又不增加pylint的来源,请给我指出细节:)

这里对于我已经受够了问题的总结pycheckerpyflakes-他们已经被证明是远远不稳定的一般用途。(在pychecker的情况下,崩溃源于pychecker代码-并非源于正在加载/调用的源。)

I would very much like to integrate pylint into the build process for my python projects, but I have run into one show-stopper: One of the error types that I find extremely useful–:E1101: *%s %r has no %r member*–constantly reports errors when using common django fields, for example:

E1101:125:get_user_tags: Class 'Tag' has no 'objects' member

which is caused by this code:

def get_user_tags(username):
   """
   Gets all the tags that username has used.

   Returns a query set.
   """
   return Tag.objects.filter(  ## This line triggers the error.
       tagownership__users__username__exact=username).distinct()

# Here is the Tag class, models.Model is provided by Django:
class Tag(models.Model):
   """
   Model for user-defined strings that help categorize Events on
   on a per-user basis.
   """
   name = models.CharField(max_length=500, null=False, unique=True)

   def __unicode__(self):
       return self.name

How can I tune Pylint to properly take fields such as objects into account? (I’ve also looked into the Django source, and I have been unable to find the implementation of objects, so I suspect it is not “just” a class field. On the other hand, I’m fairly new to python, so I may very well have overlooked something.)

Edit: The only way I’ve found to tell pylint to not warn about these warnings is by blocking all errors of the type (E1101) which is not an acceptable solution, since that is (in my opinion) an extremely useful error. If there is another way, without augmenting the pylint source, please point me to specifics :)

See here for a summary of the problems I’ve had with pychecker and pyflakes — they’ve proven to be far to unstable for general use. (In pychecker’s case, the crashes originated in the pychecker code — not source it was loading/invoking.)


回答 0

不要通过添加ignores或禁用或削弱Pylint功能generated-members
使用积极开发的理解 Django的Pylint插件。
这个适用于Django的Pylint插件效果很好:

pip install pylint-django

并且在运行pylint时,将以下标志添加到命令中:

--load-plugins pylint_django

详细的博客文章在这里

Do not disable or weaken Pylint functionality by adding ignores or generated-members.
Use an actively developed Pylint plugin that understands Django.
This Pylint plugin for Django works quite well:

pip install pylint-django

and when running pylint add the following flag to the command:

--load-plugins pylint_django

Detailed blog post here.


回答 1

我使用以下内容: pylint --generated-members=objects

I use the following: pylint --generated-members=objects


回答 2

我的〜/ .pylintrc包含

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id

最后两个是专门针对Django的。

请注意,PyLint 0.21.1中存在一个错误,需要对其进行修补才能使其正常工作。

编辑:弄乱了一点之后,我决定对PyLint进行一点修改,以允许我将以上内容扩展为:

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id,[a-zA-Z]+_set

我只是添加:

    import re
    for pattern in self.config.generated_members:
        if re.match(pattern, node.attrname):
            return

在错误报告中提到的修复之后(即,在第129行)。

快乐的时光!

My ~/.pylintrc contains

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id

the last two are specifically for Django.

Note that there is a bug in PyLint 0.21.1 which needs patching to make this work.

Edit: After messing around with this a little more, I decided to hack PyLint just a tiny bit to allow me to expand the above into:

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id,[a-zA-Z]+_set

I simply added:

    import re
    for pattern in self.config.generated_members:
        if re.match(pattern, node.attrname):
            return

after the fix mentioned in the bug report (i.e., at line 129).

Happy days!


回答 3

如果您使用Visual Studio Code,请执行以下操作:

pip install pylint-django

并添加到VSC配置:

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

If you use Visual Studio Code do this:

pip install pylint-django

And add to VSC config:

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

回答 4

django-lint是一个不错的工具,它使用django特定的设置包装pylint:http ://chris-lamb.co.uk/projects/django-lint/

github项目:https : //github.com/lamby/django-lint

django-lint is a nice tool which wraps pylint with django specific settings : http://chris-lamb.co.uk/projects/django-lint/

github project: https://github.com/lamby/django-lint


回答 5

由于pylint的工作方式(它在不让Python实际执行的情况下检查源代码本身)对pylint来说很难弄清楚元类和复杂的基类实际上如何影响类及其实例。在这方面,“ pychecker”工具要好一些,因为它确实允许Python执行代码。它导入模块并检查生成的对象。但是,该方法还有其他问题,因为它确实允许Python执行代码:-)

您可以扩展pylint来教它有关Django所使用的魔术的知识,或者使它更好地理解元类或复杂的基类,或者在检测到一个或多个它不太了解的功能之后忽略这些情况。我认为这不会特别容易。您还可以通过源代码中的特殊注释,命令行选项或.pylintrc文件,告诉pylint不要警告这些事情。

Because of how pylint works (it examines the source itself, without letting Python actually execute it) it’s very hard for pylint to figure out how metaclasses and complex baseclasses actually affect a class and its instances. The ‘pychecker’ tool is a bit better in this regard, because it does actually let Python execute the code; it imports the modules and examines the resulting objects. However, that approach has other problems, because it does actually let Python execute the code :-)

You could extend pylint to teach it about the magic Django uses, or to make it understand metaclasses or complex baseclasses better, or to just ignore such cases after detecting one or more features it doesn’t quite understand. I don’t think it would be particularly easy. You can also just tell pylint to not warn about these things, through special comments in the source, command-line options or a .pylintrc file.


回答 6

我从使用pylint / pychecker辞职,转而将pyflakes与Django代码一起使用-它只是尝试导入模块并报告发现的任何问题,例如未使用的导入或未初始化的本地名称。

I resigned from using pylint/pychecker in favor of using pyflakes with Django code – it just tries to import module and reports any problem it finds, like unused imports or uninitialized local names.


回答 7

这不是解决方案,但是您可以在objects = models.Manager()不更改任何行为的情况下将其添加到Django模型中。

我本人只使用pyflakes,主要是因为我的部分pylint和惰性有些愚蠢的默认设置(不想查看如何更改默认设置)。

This is not a solution, but you can add objects = models.Manager() to your Django models without changing any behavior.

I myself only use pyflakes, primarily due to some dumb defaults in pylint and laziness on my part (not wanting to look up how to change the defaults).


回答 8

尝试与运行pylint

pylint --ignored-classes=Tags

如果可行,添加所有其他Django类-可能使用脚本,例如python:P

该文档--ignore-classes是:

--ignored-classes=<members names>
不应检查其成员属性的类名列表(对于动态设置了属性的类很有用)。[当前:%default]

我认为这并不是一个特别优雅的解决方案,但应该可以。

Try running pylint with

pylint --ignored-classes=Tags

If that works, add all the other Django classes – possibly using a script, in say, python :P

The documentation for --ignore-classes is:

--ignored-classes=<members names>
List of classes names for which member attributes should not be checked (useful for classes with attributes dynamicaly set). [current: %default]

I should add this is not a particular elegant solution in my view, but it should work.


回答 9

另一个问题中提出的解决方案是,只需将get_attr添加到Tag类中即可。丑陋,但是行得通。

The solution proposed in this other question it to simply add get_attr to your Tag class. Ugly, but works.


回答 10

到目前为止,我没有找到真正的解决方案,但是可以解决:

  • 在我们公司,我们要求pylint得分>8。这允许pylint无法理解编码实践,同时确保代码不太“异常”。到目前为止,我们还没有看到E1101阻止我们达到8分或更高分数的情况。
  • 我们的“ make check”目标过滤掉“ for has no’objects member”消息,以消除由于pylint不了解Django引起的大部分干扰。

So far I have found no real solution to that but work around:

  • In our company we require a pylint score > 8. This allows coding practices pylint doesn’t understand while ensuring that the code isn’t too “unusual”. So far we havn’t seen any instance where E1101 kept us from reaching a score of 8 or higher.
  • Our ‘make check’ targets filter out “for has no ‘objects’ member” messages to remove most of the distraction caused by pylint not understanding Django.

回答 11

对于neovim & vim8使用w0rp's ale插件。如果您已经安装了正确的一切,包括w0rp's alepylintpylint-django。在您的代码中vimrc添加以下内容,并享受使用django开发Web应用程序的乐趣。谢谢。

let g:ale_python_pylint_options = '--load-plugins pylint_django'

For neovim & vim8 use w0rp's ale plugin. If you have installed everything correctly including w0rp's ale, pylint & pylint-django. In your vimrc add the following line & have fun developing web apps using django. Thanks.

let g:ale_python_pylint_options = '--load-plugins pylint_django'

您可以给Django应用指定一个冗长的名称以供整个管理员使用吗?

问题:您可以给Django应用指定一个冗长的名称以供整个管理员使用吗?

您可以使用为字段和模型提供Django管理员中显示的详细名称的相同方式,可以为应用程序自定义名称吗?

In the same way that you can give fields and models verbose names that appear in the Django admin, can you give an app a custom name?


回答 0

Django 1.8以上

根据1.8文档(和当前文档),

新应用程序应避免使用default_app_config。相反,它们应要求在中AppConfig显式配置指向适当子类的虚线路径INSTALLED_APPS

例:

INSTALLED_APPS = [
    # ...snip...
    'yourapp.apps.YourAppConfig',
]

然后AppConfig,如下所示更改您的。

的Django 1.7

正如rhunwicks对OP的评论所言,自Django 1.7起,这已成为可能

取自文档

# in yourapp/apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    name = 'yourapp'
    verbose_name = 'Fancy Title'

然后将default_app_config变量设置为YourAppConfig

# in yourapp/__init__.py
default_app_config = 'yourapp.apps.YourAppConfig'

Django 1.7之前的版本

您可以通过在模型定义中定义app_label来给应用程序自定义名称。但是,随着django构建管理页面时,它将按模型的app_label哈希模型,因此,如果希望它们出现在一个应用程序中,则必须在应用程序的所有模型中定义此名称。

class MyModel(models.Model):
        pass
    class Meta:
        app_label = 'My APP name'

Django 1.8+

Per the 1.8 docs (and current docs),

New applications should avoid default_app_config. Instead they should require the dotted path to the appropriate AppConfig subclass to be configured explicitly in INSTALLED_APPS.

Example:

INSTALLED_APPS = [
    # ...snip...
    'yourapp.apps.YourAppConfig',
]

Then alter your AppConfig as listed below.

Django 1.7

As stated by rhunwicks’ comment to OP, this is now possible out of the box since Django 1.7

Taken from the docs:

# in yourapp/apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    name = 'yourapp'
    verbose_name = 'Fancy Title'

then set the default_app_config variable to YourAppConfig

# in yourapp/__init__.py
default_app_config = 'yourapp.apps.YourAppConfig'

Prior to Django 1.7

You can give your application a custom name by defining app_label in your model definition. But as django builds the admin page it will hash models by their app_label, so if you want them to appear in one application, you have to define this name in all models of your application.

class MyModel(models.Model):
        pass
    class Meta:
        app_label = 'My APP name'

回答 1

正如rhunwicks对OP的评论所言,自Django 1.7起,这已成为可能

取自文档

# in yourapp/apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    name = 'yourapp'
    verbose_name = 'Fancy Title'

然后将default_app_config变量设置为YourAppConfig

# in yourapp/__init__.py
default_app_config = 'yourapp.apps.YourAppConfig'

As stated by rhunwicks’ comment to OP, this is now possible out of the box since Django 1.7

Taken from the docs:

# in yourapp/apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    name = 'yourapp'
    verbose_name = 'Fancy Title'

then set the default_app_config variable to YourAppConfig

# in yourapp/__init__.py
default_app_config = 'yourapp.apps.YourAppConfig'

回答 2

如果应用程序中有多个模型,则只需使用元信息创建一个模型,然后为所有模型创建该类的子类。

class MyAppModel(models.Model):
    class Meta:
        app_label = 'My App Label'
        abstract = True

class Category(MyAppModel):
     name = models.CharField(max_length=50)

If you have more than one model in the app just create a model with the Meta information and create subclasses of that class for all your models.

class MyAppModel(models.Model):
    class Meta:
        app_label = 'My App Label'
        abstract = True

class Category(MyAppModel):
     name = models.CharField(max_length=50)

回答 3

给他们一个verbose_name属性。

不要抱有希望。您还需要将索引视图从django.contrib.admin.sites复制到您自己的ProjectAdminSite视图中,并将其包含在您自己的自定义管理实例中:

class ProjectAdminSite(AdminSite):
    def index(self, request, extra_context=None):
        copied stuff here...

admin.site = ProjectAdminSite()

然后调整复制的视图,以便它使用您的verbose_name属性作为应用程序的标签。

我通过在复制的视图中添加如下内容来完成此操作:

        try:
            app_name = model_admin.verbose_name
        except AttributeError:
            app_name = app_label

在调整索引视图时,为什么也不要添加“ order”属性。

Give them a verbose_name property.

Don’t get your hopes up. You will also need to copy the index view from django.contrib.admin.sites into your own ProjectAdminSite view and include it in your own custom admin instance:

class ProjectAdminSite(AdminSite):
    def index(self, request, extra_context=None):
        copied stuff here...

admin.site = ProjectAdminSite()

then tweak the copied view so that it uses your verbose_name property as the label for the app.

I did it by adding something a bit like this to the copied view:

        try:
            app_name = model_admin.verbose_name
        except AttributeError:
            app_name = app_label

While you are tweaking the index view why not add an ‘order’ property too.


回答 4

好吧,我启动了一个名为todo的应用程序,现在决定将其命名为Tasks。问题是我的表中已经有数据,因此我的解决方法如下。放入models.py:

    class Meta:
       app_label = 'Tasks'
       db_table = 'mytodo_todo'

希望能帮助到你。

Well I started an app called todo and have now decided I want it to be named Tasks. The problem is that I already have data within my table so my work around was as follows. Placed into the models.py:

    class Meta:
       app_label = 'Tasks'
       db_table = 'mytodo_todo'

Hope it helps.


回答 5

对于Django 1.4(尚未发布,但主干非常稳定),可以使用以下方法。它依赖于AdminSite现在返回TemplateResponse的事实,您可以在呈现它之前对其进行更改。

在这里,我们做了一些Monkey修补来插入我们的行为,如果您使用自定义AdminSite子类,则可以避免这种情况。

from functools import wraps
def rename_app_list(func):
    m = {'Sites': 'Web sites',
         'Your_app_label': 'Nicer app label',
    }

    @wraps(func)
    def _wrapper(*args, **kwargs):
        response = func(*args, **kwargs)
        app_list = response.context_data.get('app_list')

        if app_list is not None:
            for a in app_list:
                name = a['name']
                a['name'] = m.get(name, name)
        title = response.context_data.get('title')
        if title is not None:
            app_label = title.split(' ')[0]
            if app_label in m:
                response.context_data['title'] = "%s administration" % m[app_label]
        return response
    return _wrapper

admin.site.__class__.index = rename_app_list(admin.site.__class__.index)
admin.site.__class__.app_index = rename_app_list(admin.site.__class__.app_index)

这样可以修复索引和app_index视图。它并不能解决所有其他管理员视图中的面包屑。

For Django 1.4 (not yet released, but trunk is pretty stable), you can use the following method. It relies on the fact that AdminSite now returns a TemplateResponse, which you can alter before it is rendered.

Here, we do a small bit of monkey patching to insert our behaviour, which can be avoided if you use a custom AdminSite subclass.

from functools import wraps
def rename_app_list(func):
    m = {'Sites': 'Web sites',
         'Your_app_label': 'Nicer app label',
    }

    @wraps(func)
    def _wrapper(*args, **kwargs):
        response = func(*args, **kwargs)
        app_list = response.context_data.get('app_list')

        if app_list is not None:
            for a in app_list:
                name = a['name']
                a['name'] = m.get(name, name)
        title = response.context_data.get('title')
        if title is not None:
            app_label = title.split(' ')[0]
            if app_label in m:
                response.context_data['title'] = "%s administration" % m[app_label]
        return response
    return _wrapper

admin.site.__class__.index = rename_app_list(admin.site.__class__.index)
admin.site.__class__.app_index = rename_app_list(admin.site.__class__.app_index)

This fixes the index and the app_index views. It doesn’t fix the bread crumbs in all other admin views.


回答 6

首先,您需要apps.py在appfolder上创建一个像这样的文件:

# appName/apps.py

# -*- coding: utf-8 -*-             
from django.apps import AppConfig

class AppNameConfig(AppConfig):
    name = 'appName'
    verbose_name = "app Custom Name"

要默认加载此AppConfig子类:

# appName/__init__.py
default_app_config = 'appName.apps.AppNameConfig'

是最好的方法。在Django 1.7上测试

对于西班牙语有问题的人

此代码在python2脚本上启用utf-8兼容性

# -*- coding: utf-8 -*-

First you need to create a apps.py file like this on your appfolder:

# appName/apps.py

# -*- coding: utf-8 -*-             
from django.apps import AppConfig

class AppNameConfig(AppConfig):
    name = 'appName'
    verbose_name = "app Custom Name"

To load this AppConfig subclass by default:

# appName/__init__.py
default_app_config = 'appName.apps.AppNameConfig'

Is the best way to do. tested on Django 1.7

For the person who had problems with the Spanish

This code enable the utf-8 compatibility on python2 scripts

# -*- coding: utf-8 -*-

回答 7

否,但是您可以复制管理模板并在其中定义应用程序名称。

No, but you can copy admin template and define app name there.


回答 8

可以完成不需要任何迁移的hack。摘自Ionel的博客,信誉归功于他:http : //blog.ionelmc.ro/2011/06/24/custom-app-names-in-the-django-admin/

还有一个票证应该在Django 1.7 https://code.djangoproject.com/ticket/3591中修复

“”

假设您有一个这样的模型:

class Stuff(models.Model):
    class Meta:
        verbose_name = u'The stuff'
        verbose_name_plural = u'The bunch of stuff'

您有verbose_name,但是您也想自定义app_label以便在admin中进行不同的显示。不幸的是,有一些任意字符串(带空格)是行不通的,而且无论如何也不能显示。

原来,管理员使用app_label。title()进行显示,因此我们可以做些改动:str子类,带有重写的title方法:

class string_with_title(str):
    def __new__(cls, value, title):
        instance = str.__new__(cls, value)
        instance._title = title
        return instance

    def title(self):
        return self._title

    __copy__ = lambda self: self
    __deepcopy__ = lambda self, memodict: self

现在我们可以有这样的模型:

class Stuff(models.Model):
    class Meta:
        app_label = string_with_title("stuffapp", "The stuff box")
        # 'stuffapp' is the name of the django app
        verbose_name = 'The stuff'
        verbose_name_plural = 'The bunch of stuff'

管理员将显示“填充框”作为应用名称。

“”

There is a hack that can be done that does not require any migrations. Taken from Ionel’s blog and credit goes to him: http://blog.ionelmc.ro/2011/06/24/custom-app-names-in-the-django-admin/

There is also a ticket for this that should be fixed in Django 1.7 https://code.djangoproject.com/ticket/3591

“””

Suppose you have a model like this:

class Stuff(models.Model):
    class Meta:
        verbose_name = u'The stuff'
        verbose_name_plural = u'The bunch of stuff'

You have verbose_name, however you want to customise app_label too for different display in admin. Unfortunatelly having some arbitrary string (with spaces) doesn’t work and it’s not for display anyway.

Turns out that the admin uses app_label. title () for display so we can make a little hack: str subclass with overriden title method:

class string_with_title(str):
    def __new__(cls, value, title):
        instance = str.__new__(cls, value)
        instance._title = title
        return instance

    def title(self):
        return self._title

    __copy__ = lambda self: self
    __deepcopy__ = lambda self, memodict: self

Now we can have the model like this:

class Stuff(models.Model):
    class Meta:
        app_label = string_with_title("stuffapp", "The stuff box")
        # 'stuffapp' is the name of the django app
        verbose_name = 'The stuff'
        verbose_name_plural = 'The bunch of stuff'

and the admin will show “The stuff box” as the app name.

“””


回答 9

如果您已经有使用旧应用程序名称的现有表,并且不想迁移它们,则只需在原始模型的代理上设置app_label。

class MyOldModel(models.Model):
    pass

class MyNewModel(MyOldModel):
    class Meta:
        proxy = True
        app_label = 'New APP name'
        verbose_name = MyOldModel._meta.verbose_name

然后,您只需要在admin.py中进行更改:

#admin.site.register(MyOldModel, MyOldModelAdmin)
admin.site.register(MyNewModel, MyOldModelAdmin)

请注意,URL为/ admin / NewAPPname / mynewmodel /,因此您可能只想确保新模型的类名看起来尽可能接近旧模型。

If you already have existing tables using the old app name, and you don’t want to migrate them, then just set the app_label on a proxy of the original model.

class MyOldModel(models.Model):
    pass

class MyNewModel(MyOldModel):
    class Meta:
        proxy = True
        app_label = 'New APP name'
        verbose_name = MyOldModel._meta.verbose_name

Then you just have to change this in your admin.py:

#admin.site.register(MyOldModel, MyOldModelAdmin)
admin.site.register(MyNewModel, MyOldModelAdmin)

Be aware that the url will be /admin/NewAPPname/mynewmodel/ so you might just want to make sure that the class name for the new model looks as close to the old model as possible.


回答 10

好吧,这对我有用。在app.py中使用以下命令:

class MainConfig(AppConfig):
    name = 'main'
    verbose_name="Fancy Title"

在setting.py中添加App的名称和App文件夹中app.py文件中存在的类名称

INSTALLED_APPS = [
    'main.apps.MainConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

]

Well, this works for me. In the app.py use this:

class MainConfig(AppConfig):
    name = 'main'
    verbose_name="Fancy Title"

In setting.py add the name of App and the class name present in app.py file in App folder

INSTALLED_APPS = [
    'main.apps.MainConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

]


回答 11

自以来,以下即插即用的代码完美地发挥了作用Django 1.7。您所要做的就是将以下代码复制__init__.py到特定应用程序的文件中并更改VERBOSE_APP_NAME参数。

from os import path
from django.apps import AppConfig

VERBOSE_APP_NAME = "YOUR VERBOSE APP NAME HERE"


def get_current_app_name(file):
    return path.dirname(file).replace('\\', '/').split('/')[-1]


class AppVerboseNameConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = VERBOSE_APP_NAME


default_app_config = get_current_app_name(__file__) + '.__init__.AppVerboseNameConfig'

如果将其用于多个应用程序,则应将该get_current_app_name功能分解为帮助文件。

The following plug-and-play piece of code works perfectly since Django 1.7. All you have to do is copy the below code in the __init__.py file of the specific app and change the VERBOSE_APP_NAME parameter.

from os import path
from django.apps import AppConfig

VERBOSE_APP_NAME = "YOUR VERBOSE APP NAME HERE"


def get_current_app_name(file):
    return path.dirname(file).replace('\\', '/').split('/')[-1]


class AppVerboseNameConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = VERBOSE_APP_NAME


default_app_config = get_current_app_name(__file__) + '.__init__.AppVerboseNameConfig'

If you use this for multiple apps, you should factor out the get_current_app_name function to a helper file.


使用Python的os.path,如何进入一个目录?

问题:使用Python的os.path,如何进入一个目录?

我最近将Django从v1.3.1升级到v1.4。

我以前settings.py

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname( __file__ ), 'templates').replace('\\', '/'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

这将指向/Users/hobbes3/Sites/mysite/templates,但是因为Django v1.4将项目文件夹移到了与应用程序文件夹相同的级别,所以我的settings.py文件现在位于/Users/hobbes3/Sites/mysite/mysite/而不是/Users/hobbes3/Sites/mysite/

所以实际上我的问题是双重的:

  1. 如何使用os.path来查看上一级目录__file__。换句话说,我想/Users/hobbes3/Sites/mysite/mysite/settings.py找到/Users/hobbes3/Sites/mysite/templates使用相对路径。
  2. 我应该保持template(其具有跨应用程序模板,如文件夹adminregistration在项目等)/User/hobbes3/Sites/mysite水平或在/User/hobbes3/Sites/mysite/mysite

I recently upgrade Django from v1.3.1 to v1.4.

In my old settings.py I have

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname( __file__ ), 'templates').replace('\\', '/'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

This will point to /Users/hobbes3/Sites/mysite/templates, but because Django v1.4 moved the project folder to the same level as the app folders, my settings.py file is now in /Users/hobbes3/Sites/mysite/mysite/ instead of /Users/hobbes3/Sites/mysite/.

So actually my question is now twofold:

  1. How do I use os.path to look at a directory one level above from __file__. In other words, I want /Users/hobbes3/Sites/mysite/mysite/settings.py to find /Users/hobbes3/Sites/mysite/templates using relative paths.
  2. Should I be keeping the template folder (which has cross-app templates, like admin, registration, etc.) at the project /User/hobbes3/Sites/mysite level or at /User/hobbes3/Sites/mysite/mysite?

回答 0

os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates'))

至于template文件夹应该放哪里,我不知道自从Django 1.4刚问世以来,我还没有看过它。您可能应该在SE上问另一个问题以解决该问题。

您也可以使用normpath来清理路径,而不是abspath。但是,在这种情况下,Django需要绝对路径而不是相对路径。

为了实现跨平台兼容性,请使用os.pardir代替'..'

os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates'))

As far as where the templates folder should go, I don’t know since Django 1.4 just came out and I haven’t looked at it yet. You should probably ask another question on SE to solve that issue.

You can also use normpath to clean up the path, rather than abspath. However, in this situation, Django expects an absolute path rather than a relative path.

For cross platform compatability, use os.pardir instead of '..'.


回答 1

要获取文件的文件夹,请使用:

os.path.dirname(path) 

要建立文件夹,只需os.path.dirname再次使用

os.path.dirname(os.path.dirname(path))

您可能要检查是否__file__为符号链接:

if os.path.islink(__file__): path = os.readlink (__file__)

To get the folder of a file just use:

os.path.dirname(path) 

To get a folder up just use os.path.dirname again

os.path.dirname(os.path.dirname(path))

You might want to check if __file__ is a symlink:

if os.path.islink(__file__): path = os.readlink (__file__)

回答 2

如果您使用的是Python 3.4或更高版本,则向上移动多个目录的便捷方法是pathlib

from pathlib import Path

full_path = "path/to/directory"
str(Path(full_path).parents[0])  # "path/to"
str(Path(full_path).parents[1])  # "path"
str(Path(full_path).parents[2])  # "."

If you are using Python 3.4 or newer, a convenient way to move up multiple directories is pathlib:

from pathlib import Path

full_path = "path/to/directory"
str(Path(full_path).parents[0])  # "path/to"
str(Path(full_path).parents[1])  # "path"
str(Path(full_path).parents[2])  # "."

回答 3

您正是想要这样的:

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )

You want exactly this:

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )

回答 4

就个人而言,我会选择功能方法

def get_parent_dir(directory):
    import os
    return os.path.dirname(directory)

current_dirs_parent = get_parent_dir(os.getcwd())

Personally, I’d go for the function approach

def get_parent_dir(directory):
    import os
    return os.path.dirname(directory)

current_dirs_parent = get_parent_dir(os.getcwd())

回答 5

我认为最简单的方法就是重用dirname(),因此您可以调用

os.path.dirname(os.path.dirname( __file__ ))

如果文件位于/Users/hobbes3/Sites/mysite/templates/method.py

这将返回“ / Users / hobbes3 / Sites / mysite”

I think the easiest thing to do is just to reuse dirname() So you can call

os.path.dirname(os.path.dirname( __file__ ))

if you file is at /Users/hobbes3/Sites/mysite/templates/method.py

This will return “/Users/hobbes3/Sites/mysite”


回答 6

from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

更新:

如果您碰巧settings.py通过符号链接“复制” ,@ forivall的答案会更好:

~user/
    project1/  
        mysite/
            settings.py
        templates/
            wrong.html

    project2/
        mysite/
            settings.py -> ~user/project1/settings.py
        templates/
            right.html

上面的方法将“看到”,wrong.html而@forivall的方法将看到right.html

在没有符号链接的情况下,两个答案是相同的。

from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

Update:

If you happen to “copy” settings.py through symlinking, @forivall’s answer is better:

~user/
    project1/  
        mysite/
            settings.py
        templates/
            wrong.html

    project2/
        mysite/
            settings.py -> ~user/project1/settings.py
        templates/
            right.html

The method above will ‘see’ wrong.html while @forivall’s method will see right.html

In the absense of symlinks the two answers are identical.


回答 7

这对于在其他情况下需要x文件夹的情况可能很有用。只需运行walk_up_folder(path, 6)最多6个文件夹即可。

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   

This might be useful for other cases where you want to go x folders up. Just run walk_up_folder(path, 6) to go up 6 folders.

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   

回答 8

对于像我这样的偏执狂,我更喜欢这个

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)

For a paranoid like me, I’d prefer this one

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)

回答 9

打开n文件夹…运行up(n)

import os

def up(n, nth_dir=os.getcwd()):
    while n != 0:
        nth_dir = os.path.dirname(nth_dir)
        n -= 1
    return nth_dir

To go n folders up… run up(n)

import os

def up(n, nth_dir=os.getcwd()):
    while n != 0:
        nth_dir = os.path.dirname(nth_dir)
        n -= 1
    return nth_dir

回答 10

当然:只需使用即可os.chdir(..)

Of course: simply use os.chdir(..).


回答 11

通过使用,os.path我们可以像这样建立一个目录

one_directory_up_path = os.path.dirname('.')

在找到您想要的目录之后,您还可以与其他文件/目录路径一起加入

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')

With using os.path we can go one directory up like that

one_directory_up_path = os.path.dirname('.')

also after finding the directory you want you can join with other file/directory path

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')

如何获得该对象(如果存在)或“无”(如果不存在)?

问题:如何获得该对象(如果存在)或“无”(如果不存在)?

当我要求模型管理器获取一个对象时,DoesNotExist当没有匹配的对象时,它将引发。

go = Content.objects.get(name="baby")

相反的DoesNotExist,我怎么能有go可以None代替?

When I ask the model manager to get an object, it raises DoesNotExist when there is no matching object.

go = Content.objects.get(name="baby")

Instead of DoesNotExist, how can I have go be None instead?


回答 0

没有“内置”方式可以做到这一点。Django每次都会引发DidNotExist异常。在python中处理此问题的惯用方式是将其包装在try catch中:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None

我所做的就是将模型.Manager子类化,创建safe_get类似于上面的代码,并将该经理用于我的模型。这样,您可以编写:SomeModel.objects.safe_get(foo='bar')

There is no ‘built in’ way to do this. Django will raise the DoesNotExist exception every time. The idiomatic way to handle this in python is to wrap it in a try catch:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None

What I did do, is to subclass models.Manager, create a safe_get like the code above and use that manager for my models. That way you can write: SomeModel.objects.safe_get(foo='bar').


回答 1

从Django 1.6开始,您可以像这样使用first()方法:

Content.objects.filter(name="baby").first()

Since django 1.6 you can use first() method like so:

Content.objects.filter(name="baby").first()

回答 2

来自Django文档

get()DoesNotExist如果找不到给定参数的对象,则会引发异常。此异常也是模型类的属性。在DoesNotExist 从异常继承django.core.exceptions.ObjectDoesNotExist

您可以捕获异常并分配None去。

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = None

From django docs

get() raises a DoesNotExist exception if an object is not found for the given parameters. This exception is also an attribute of the model class. The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist

You can catch the exception and assign None to go.

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = None

回答 3

您可以为此创建通用函数。

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.DoesNotExist:
        return None

像下面这样使用:

go = get_or_none(Content,name="baby")

如果没有条目匹配,则go将为None,否则将返回Content条目。

注意:如果为name =“ baby”返回的条目超过一个,则会引发MultipleObjectsReturned异常

You can create a generic function for this.

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.DoesNotExist:
        return None

Use this like below:

go = get_or_none(Content,name="baby")

go will be None if no entry matches else will return the Content entry.

Note:It will raises exception MultipleObjectsReturned if more than one entry returned for name="baby".

You should handle it on the data model to avoid this kind of error but you may prefer to log it at run time like this:

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.MultipleObjectsReturned as e:
        print('ERR====>', e)

    except classmodel.DoesNotExist:
        return None

回答 4

您可以这样操作:

go  = Content.objects.filter(name="baby").first()

现在go变量可以是您想要的对象,也可以是None

参考:https : //docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first

You can do it this way:

go  = Content.objects.filter(name="baby").first()

Now go variable could be either the object you want or None

Ref: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first


回答 5

为了使事情变得更容易,以下是我编写的代码的片段,这些代码基于来自此处精彩答复的输入:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None

然后在您的模型中:

class MyModel(models.Model):
    objects = MyManager()

而已。现在您有了MyModel.objects.get()和MyModel.objetcs.get_or_none()

To make things easier, here is a snippet of the code I wrote, based on inputs from the wonderful replies here:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None

And then in your model:

class MyModel(models.Model):
    objects = MyManager()

That’s it. Now you have MyModel.objects.get() as well as MyModel.objetcs.get_or_none()


回答 6

您可以使用exists过滤器:

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

如果您只想知道它是否存在,则只是一个选择

you could use exists with a filter:

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

just an alternative for if you only want to know if it exists


回答 7

在视图中的不同点处理异常可能真的很麻烦。.如何在models.py文件中定义自定义模型管理器,如

class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

然后将其包含在内容模型类中

class Content(model.Model):
    ...
    objects = ContentManager()

这样可以很容易地在视图中处理,即

post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't exist

Handling exceptions at different points in your views could really be cumbersome..What about defining a custom Model Manager, in the models.py file, like

class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

and then including it in the content Model class

class Content(model.Model):
    ...
    objects = ContentManager()

In this way it can be easily dealt in the views i.e.

post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't exist

回答 8

这是您可能不想重新实现的那些烦人的功能之一:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")

It’s one of those annoying functions that you might not want to re-implement:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")

回答 9

如果您想要一个不涉及异常处理,条件语句或Django 1.6+要求的简单的单行解决方案,请执行以下操作:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)

If you want a simple one-line solution that doesn’t involve exception handling, conditional statements or a requirement of Django 1.6+, do this instead:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)

回答 10

我认为使用它不是一个坏主意 get_object_or_404()

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

此示例等效于:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

您可以在Django在线文档中阅读有关get_object_or_404()的更多信息。

I think it isn’t bad idea to use get_object_or_404()

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

This example is equivalent to:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

You can read more about get_object_or_404() in django online documentation.


回答 11

从Django 1.7起,您可以执行以下操作:

class MyQuerySet(models.QuerySet):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None


class MyBaseModel(models.Model):

    objects = MyQuerySet.as_manager()


class MyModel(MyBaseModel):
    ...

class AnotherMyModel(MyBaseModel):
    ...

“ MyQuerySet.as_manager()”的优点是以下两项都可以工作:

MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()

From django 1.7 onwards you can do like:

class MyQuerySet(models.QuerySet):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None


class MyBaseModel(models.Model):

    objects = MyQuerySet.as_manager()


class MyModel(MyBaseModel):
    ...

class AnotherMyModel(MyBaseModel):
    ...

The advantage of “MyQuerySet.as_manager()” is that both of the following will work:

MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()

回答 12

这是helper函数的一种变体QuerySet,如果您希望从除模型all对象的查询集以外的查询集中获取唯一的对象(如果存在)(例如,从属于父实例):

def get_unique_or_none(model, queryset=None, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(**kwargs)
    except model.DoesNotExist:
        return None

可以通过两种方式使用它,例如:

  1. obj = get_unique_or_none(Model, **kwargs) 如前所述
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)

Here’s a variation on the helper function that allows you to optionally pass in a QuerySet instance, in case you want to get the unique object (if present) from a queryset other than the model’s all objects queryset (e.g. from a subset of child items belonging to a parent instance):

def get_unique_or_none(model, queryset=None, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(**kwargs)
    except model.DoesNotExist:
        return None

This can be used in two ways, e.g.:

  1. obj = get_unique_or_none(Model, **kwargs) as previosuly discussed
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)

回答 13

毫无exceptions:

if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = None

使用异常:

try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = None

关于何时应该在python中使用异常有一些参数。一方面,“请求宽恕比允许更容易”。尽管我同意这一点,但我认为应该保留一个exceptions,这个exceptions,并且“理想情况”应该继续存在而不会碰到一个exceptions。

Without exception:

if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = None

Using an exception:

try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = None

There is a bit of an argument about when one should use an exception in python. On the one hand, “it is easier to ask for forgiveness than for permission”. While I agree with this, I believe that an exception should remain, well, the exception, and the “ideal case” should run without hitting one.


回答 14

我们可以使用Django内置异常,该异常附加到名为的模型上.DoesNotExist。因此,我们不必导入ObjectDoesNotExist异常。

而是这样做:

from django.core.exceptions import ObjectDoesNotExist

try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = None

我们可以完成这个:

try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = None

We can use Django builtin exception which attached to the models named as .DoesNotExist. So, we don’t have to import ObjectDoesNotExist exception.

Instead doing:

from django.core.exceptions import ObjectDoesNotExist

try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = None

We can do this:

try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = None

回答 15

这是Django的get_object_or_404的模仿,只是该方法返回None。当我们必须使用only()查询仅检索某些字段时,这非常有用。此方法可以接受模型或查询集。

from django.shortcuts import _get_queryset


def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

This is a copycat from Django’s get_object_or_404 except that the method returns None. This is extremely useful when we have to use only() query to retreive certain fields only. This method can accept a model or a queryset.

from django.shortcuts import _get_queryset


def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

回答 16

也许使用更好:

User.objects.filter(username=admin_username).exists()

Maybe is better you use:

User.objects.filter(username=admin_username).exists()

如何用下划线替换空格,反之亦然?

问题:如何用下划线替换空格,反之亦然?

我想用字符串中的下划线替换空格以创建漂亮的URL。因此,例如:

"This should be connected" becomes "This_should_be_connected" 

我在Django中使用Python。可以使用正则表达式解决吗?

I want to replace whitespace with underscore in a string to create nice URLs. So that for example:

"This should be connected" becomes "This_should_be_connected" 

I am using Python with Django. Can this be solved using regular expressions?


回答 0

您不需要正则表达式。Python有一个内置的字符串方法可以满足您的需要:

mystring.replace(" ", "_")

You don’t need regular expressions. Python has a built-in string method that does what you need:

mystring.replace(" ", "_")

回答 1

替换空格是可以的,但我建议您进一步处理其他对URL不利的字符,例如问号,撇号,感叹号等。

还要注意,SEO专家之间的普遍共识是,在URL中破折号优先于下划线。

import re

def urlify(s):

    # Remove all non-word characters (everything except numbers and letters)
    s = re.sub(r"[^\w\s]", '', s)

    # Replace all runs of whitespace with a single dash
    s = re.sub(r"\s+", '-', s)

    return s

# Prints: I-cant-get-no-satisfaction"
print(urlify("I can't get no satisfaction!"))

Replacing spaces is fine, but I might suggest going a little further to handle other URL-hostile characters like question marks, apostrophes, exclamation points, etc.

Also note that the general consensus among SEO experts is that dashes are preferred to underscores in URLs.

import re

def urlify(s):

    # Remove all non-word characters (everything except numbers and letters)
    s = re.sub(r"[^\w\s]", '', s)

    # Replace all runs of whitespace with a single dash
    s = re.sub(r"\s+", '-', s)

    return s

# Prints: I-cant-get-no-satisfaction"
print(urlify("I can't get no satisfaction!"))

回答 2

Django具有执行此功能的“ slugify”功能以及其他对URL友好的优化。它隐藏在defaultfilters模块中。

>>> from django.template.defaultfilters import slugify
>>> slugify("This should be connected")

this-should-be-connected

这不完全是您要求的输出,但是IMO最好在URL中使用。

Django has a ‘slugify’ function which does this, as well as other URL-friendly optimisations. It’s hidden away in the defaultfilters module.

>>> from django.template.defaultfilters import slugify
>>> slugify("This should be connected")

this-should-be-connected

This isn’t exactly the output you asked for, but IMO it’s better for use in URLs.


回答 3

这考虑了空格以外的空白字符,我认为它比使用re模块要快:

url = "_".join( title.split() )

This takes into account blank characters other than space and I think it’s faster than using re module:

url = "_".join( title.split() )

回答 4

使用re模块:

import re
re.sub('\s+', '_', "This should be connected") # This_should_be_connected
re.sub('\s+', '_', 'And     so\tshould this')  # And_so_should_this

除非您有多个空格或上述其他空格可能性,否则您可能只想string.replace按照其他人的建议使用即可。

Using the re module:

import re
re.sub('\s+', '_', "This should be connected") # This_should_be_connected
re.sub('\s+', '_', 'And     so\tshould this')  # And_so_should_this

Unless you have multiple spaces or other whitespace possibilities as above, you may just wish to use string.replace as others have suggested.


回答 5

使用字符串的replace方法:

"this should be connected".replace(" ", "_")

"this_should_be_disconnected".replace("_", " ")

use string’s replace method:

"this should be connected".replace(" ", "_")

"this_should_be_disconnected".replace("_", " ")


回答 6

令人惊讶的是,这个图书馆还没有提到

名为python-slugify的python包,可以很好地完成slugizing:

pip install python-slugify

像这样工作:

from slugify import slugify

txt = "This is a test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = "This -- is a ## test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = 'C\'est déjà l\'été.'
r = slugify(txt)
self.assertEquals(r, "cest-deja-lete")

txt = 'Nín hǎo. Wǒ shì zhōng guó rén'
r = slugify(txt)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")

txt = 'Компьютер'
r = slugify(txt)
self.assertEquals(r, "kompiuter")

txt = 'jaja---lol-méméméoo--a'
r = slugify(txt)
self.assertEquals(r, "jaja-lol-mememeoo-a") 

Surprisingly this library not mentioned yet

python package named python-slugify, which does a pretty good job of slugifying:

pip install python-slugify

Works like this:

from slugify import slugify

txt = "This is a test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = "This -- is a ## test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = 'C\'est déjà l\'été.'
r = slugify(txt)
self.assertEquals(r, "cest-deja-lete")

txt = 'Nín hǎo. Wǒ shì zhōng guó rén'
r = slugify(txt)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")

txt = 'Компьютер'
r = slugify(txt)
self.assertEquals(r, "kompiuter")

txt = 'jaja---lol-méméméoo--a'
r = slugify(txt)
self.assertEquals(r, "jaja-lol-mememeoo-a") 

回答 7

我将以下代码用于我的友好网址:

from unicodedata import normalize
from re import sub

def slugify(title):
    name = normalize('NFKD', title).encode('ascii', 'ignore').replace(' ', '-').lower()
    #remove `other` characters
    name = sub('[^a-zA-Z0-9_-]', '', name)
    #nomalize dashes
    name = sub('-+', '-', name)

    return name

Unicode字符也可以正常工作。

I’m using the following piece of code for my friendly urls:

from unicodedata import normalize
from re import sub

def slugify(title):
    name = normalize('NFKD', title).encode('ascii', 'ignore').replace(' ', '-').lower()
    #remove `other` characters
    name = sub('[^a-zA-Z0-9_-]', '', name)
    #nomalize dashes
    name = sub('-+', '-', name)

    return name

It works fine with unicode characters as well.


回答 8

Python在名为replace的字符串上有一个内置方法,其使用方式如下:

string.replace(old, new)

因此,您将使用:

string.replace(" ", "_")

前一段时间我遇到了这个问题,我编写了代码来替换字符串中的字符。我必须开始记得检查python文档,因为它们已经内置了所有功能。

Python has a built in method on strings called replace which is used as so:

string.replace(old, new)

So you would use:

string.replace(" ", "_")

I had this problem a while ago and I wrote code to replace characters in a string. I have to start remembering to check the python documentation because they’ve got built in functions for everything.


回答 9

OP使用的是python,但使用的是javascript(由于语法相似,因此请务必谨慎。

// only replaces the first instance of ' ' with '_'
"one two three".replace(' ', '_'); 
=> "one_two three"

// replaces all instances of ' ' with '_'
"one two three".replace(/\s/g, '_');
=> "one_two_three"

OP is using python, but in javascript (something to be careful of since the syntaxes are similar.

// only replaces the first instance of ' ' with '_'
"one two three".replace(' ', '_'); 
=> "one_two three"

// replaces all instances of ' ' with '_'
"one two three".replace(/\s/g, '_');
=> "one_two_three"

回答 10

mystring.replace (" ", "_")

如果将此值分配给任何变量,它将起作用

s = mystring.replace (" ", "_")

默认情况下,mystring不会有这个

mystring.replace (" ", "_")

if you assign this value to any variable, it will work

s = mystring.replace (" ", "_")

by default mystring wont have this


回答 11

您可以尝试以下方法:

mystring.replace(r' ','-')

You can try this instead:

mystring.replace(r' ','-')

回答 12

perl -e 'map { $on=$_; s/ /_/; rename($on, $_) or warn $!; } <*>;'

匹配并替换空间>​​当前目录中所有文件的下划线

perl -e 'map { $on=$_; s/ /_/; rename($on, $_) or warn $!; } <*>;'

Match et replace space > underscore of all files in current directory


Django模板变量和Javascript

问题:Django模板变量和Javascript

当我使用Django模板渲染器渲染页面时,可以传入包含各种值的字典变量,以使用来在页面中对其进行操作{{ myVar }}

有没有办法在Javascript中访问相同的变量(也许使用DOM,我不知道Django如何使变量可访问)?我希望能够基于传入的变量中包含的值使用AJAX查找来查找详细信息。

When I render a page using the Django template renderer, I can pass in a dictionary variable containing various values to manipulate them in the page using {{ myVar }}.

Is there a way to access the same variable in Javascript (perhaps using the DOM, I don’t know how Django makes the variables accessible)? I want to be able to lookup details using an AJAX lookup based on the values contained in the variables passed in.


回答 0

{{variable}}直接替换为HTML。查看资料;它不是“变量”或类似的变量。它只是渲染的文本。

话虽如此,您可以将这种替换形式添加到JavaScript中。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

这为您提供了“动态” javascript。

The {{variable}} is substituted directly into the HTML. Do a view source; it isn’t a “variable” or anything like it. It’s just rendered text.

Having said that, you can put this kind of substitution into your JavaScript.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

This gives you “dynamic” javascript.


回答 1

注意检查票证#17419,以获取有关将类似的标签添加到Django核心中的讨论以及通过将此模板标签与用户生成的数据一起使用而引入的可能的XSS漏洞。amacneil的评论讨论了故障单中提出的大多数问题。


我认为最灵活,方便的方法是为要在JS代码中使用的变量定义模板过滤器。这样可以确保您的数据已正确转义,并且可以将其用于复杂的数据结构,例如dictlist。这就是为什么我写这个答案的原因,尽管有一个被广泛接受的答案。

这是模板过滤器的示例:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

此模板过滤器将变量转换为JSON字符串。您可以这样使用它:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>

CAUTION Check ticket #17419 for discussion on adding similar tag into Django core and possible XSS vulnerabilities introduced by using this template tag with user generated data. Comment from amacneil discusses most of the concerns raised in the ticket.


I think the most flexible and handy way of doing this is to define a template filter for variables you want to use in JS code. This allows you to ensure, that your data is properly escaped and you can use it with complex data structures, such as dict and list. That’s why I write this answer despite there is an accepted answer with a lot of upvotes.

Here is an example of template filter:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

This template filters converts variable to JSON string. You can use it like so:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>

回答 2

对我有用的解决方案是使用模板中的隐藏输入字段

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

然后以这种方式在javascript中获取值,

var myVar = document.getElementById("myVar").value;

A solution that worked for me is using the hidden input field in the template

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

Then getting the value in javascript this way,

var myVar = document.getElementById("myVar").value;

回答 3

从Django 2.1开始,专门针对此用例引入了一个新的内置模板标记:json_script

https://docs.djangoproject.com/zh-CN/3.0/ref/templates/builtins/#json-script

新标签将安全地序列化模板值并防止XSS。

Django文档摘录:

安全地将Python对象作为JSON输出,包装在标记中,可以与JavaScript一起使用。

As of Django 2.1, a new built in template tag has been introduced specifically for this use case: json_script.

https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#json-script

The new tag will safely serialize template values and protects against XSS.

Django docs excerpt:

Safely outputs a Python object as JSON, wrapped in a tag, ready for use with JavaScript.


回答 4

这是我很容易做的事情:我为模板修改了base.html文件,并将其放在底部:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

然后,当我想在javascript文件中使用变量时,我创建了一个DJdata字典,并通过json将其添加到上下文中: context['DJdata'] = json.dumps(DJdata)

希望能帮助到你!

Here is what I’m doing very easily: I modified my base.html file for my template and put that at the bottom:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

then when I want to use a variable in the javascript files, I create a DJdata dictionary and I add it to the context by a json : context['DJdata'] = json.dumps(DJdata)

Hope it helps!


回答 5

对于字典,最好先编码为JSON。您可以使用simplejson.dumps(),或者如果要从App Engine中的数据模型进行转换,则可以使用GQLEncoder库中的encode()。

For a dictionary, you’re best of encoding to JSON first. You can use simplejson.dumps() or if you want to convert from a data model in App Engine, you could use encode() from the GQLEncoder library.


回答 6

我面临着类似的问题,S.Lott建议的答案为我工作。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

但是,我想在这里指出主要的实现限制。如果您打算将javascript代码放在其他文件中,然后将该文件包含在模板中。这行不通。

仅当主模板和javascript代码位于同一文件中时,此方法才有效。也许django小组可以解决这个限制。

I was facing simillar issue and answer suggested by S.Lott worked for me.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

However I would like to point out major implementation limitation here. If you are planning to put your javascript code in different file and include that file in your template. This won’t work.

This works only when you main template and javascript code is in same file. Probably django team can address this limitation.


回答 7

我也一直在为此苦苦挣扎。从表面上看,上述解决方案应该可行。但是,django架构要求每个html文件都有其自己的呈现变量(即{{contact}}呈现为contact.html,而呈现{{posts}}给eg index.html等)。另一方面,<script>标记出现{%endblock%}base.htmlfrom的后面contact.htmlindex.html继承。这基本上意味着任何解决方案,包括

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

必然会失败,因为变量和脚本不能共存于同一文件中。

我最终想出并为我工作的一个简单解决方案是,简单地用带有id的标签包装变量,然后在js文件中引用它,如下所示:

// index.html
<div id="myvar">{{ myVar }}</div>

然后:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

并且只包含<script src="static/js/somecode.js"></script>base.html照常进行。当然,这只是关于获取内容。关于安全性,只需遵循其他答案即可。

I’ve been struggling with this too. On the surface it seems that the above solutions should work. However, the django architecture requires that each html file has its own rendered variables (that is, {{contact}} is rendered to contact.html, while {{posts}} goes to e.g. index.html and so on). On the other hand, <script> tags appear after the {%endblock%} in base.html from which contact.html and index.html inherit. This basically means that any solution including

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

is bound to fail, because the variable and the script cannot co-exist in the same file.

The simple solution I eventually came up with, and worked for me, was to simply wrap the variable with a tag with id and later refer to it in the js file, like so:

// index.html
<div id="myvar">{{ myVar }}</div>

and then:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

and just include <script src="static/js/somecode.js"></script> in base.html as usual. Of course this is only about getting the content. Regarding security, just follow the other answers.


回答 8

对于以文本形式存储在Django字段中的JavaScript对象,它需要再次成为动态插入页面脚本中的JavaScript对象,您需要同时使用escapejsJSON.parse()

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django的escapejs句柄正确处理了引号,JSON.parse()并将字符串转换回JS对象。

For a JavaScript object stored in a Django field as text, which needs to again become a JavaScript object dynamically inserted into on-page script, you need to use both escapejs and JSON.parse():

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django’s escapejs handles the quoting properly, and JSON.parse() converts the string back into a JS object.


回答 9

请注意,如果要将变量传递给外部.js脚本,则需要在脚本标签之前加上另一个声明全局变量的脚本标签。

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data 在视图中照常定义 get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context

Note, that if you want to pass a variable to an external .js script then you need to precede your script tag with another script tag that declares a global variable.

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data is defined in the view as usual in the get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context

回答 10

我在Django 2.1中使用这种方式并为我工作,这种方式很安全(参考)

Django方面:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

HTML方面:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

I use this way in Django 2.1 and work for me and this way is secure (reference):

Django side:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

Html side:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

回答 11

您可以在字符串中声明数组变量的地方组装整个脚本,如下所示,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

将生成如下字符串

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

拥有此字符串后,必须将其发送到模板

views.py

return render(request, 'example.html', {"prueba": prueba})

在模板中,您会收到它,并以书面形式将其解释为htm代码,例如您需要的javascript代码之前

模板

{{ prueba|safe  }}

在代码的其余部分下面,请记住,在示例中使用的变量是data2

<script>
 console.log(data2);
</script>

这样,您将保留数据类型,在这种情况下,这是一种安排

you can assemble the entire script where your array variable is declared in a string, as follows,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

that will generate a string as follows

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

after having this string, you must send it to the template

views.py

return render(request, 'example.html', {"prueba": prueba})

in the template you receive it and interpret it in a literary way as htm code, just before the javascript code where you need it, for example

template

{{ prueba|safe  }}

and below that is the rest of your code, keep in mind that the variable to use in the example is data2

<script>
 console.log(data2);
</script>

that way you will keep the type of data, which in this case is an arrangement


回答 12

Javascript中有两件事对我有用:

'{{context_variable|escapejs }}'

其他:在views.py中

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

并在html中:

{{ message|safe }}

There are two things that worked for me inside Javascript:

'{{context_variable|escapejs }}'

and other: In views.py

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

and in the html:

{{ message|safe }}

在列表中查找属性等于某个值(满足任何条件)的对象

问题:在列表中查找属性等于某个值(满足任何条件)的对象

我有对象列表。我想在此列表中找到一个属性(或方法结果-任意)等于的(第一个或任何对象)对象value

找到它的最佳方法是什么?

这是测试用例:

  class Test:
      def __init__(self, value):
          self.value = value

  import random

  value = 5

  test_list = [Test(random.randint(0,100)) for x in range(1000)]

  # that I would do in Pascal, I don't believe isn't anywhere near 'Pythonic'
  for x in test_list:
      if x.value == value:
          print "i found it!"
          break

我认为使用生成器reduce()不会有任何区别,因为它仍然会遍历list。

ps .:方程式to value只是一个例子。当然我们要获得满足任何条件的元素。

I’ve got list of objects. I want to find one (first or whatever) object in this list that has attribute (or method result – whatever) equal to value.

What’s is the best way to find it?

Here’s test case:

  class Test:
      def __init__(self, value):
          self.value = value
          
  import random

  value = 5
  
  test_list = [Test(random.randint(0,100)) for x in range(1000)]
                    
  # that I would do in Pascal, I don't believe it's anywhere near 'Pythonic'
  for x in test_list:
      if x.value == value:
          print "i found it!"
          break
  

I think using generators and reduce() won’t make any difference because it still would be iterating through list.

ps.: Equation to value is just an example. Of course we want to get element which meets any condition.


回答 0

next((x for x in test_list if x.value == value), None)

这将从列表中获得与条件匹配的第一项,None如果没有匹配项,则返回。这是我首选的单表达式形式。

然而,

for x in test_list:
    if x.value == value:
        print "i found it!"
        break

天真的循环中断版本完全是Pythonic的-简洁,清晰和高效。为了使其与单线行为相匹配:

for x in test_list:
    if x.value == value:
        print "i found it!"
        break
else:
    x = None

如果您不在循环之外,这将分配None给。xbreak

next((x for x in test_list if x.value == value), None)

This gets the first item from the list that matches the condition, and returns None if no item matches. It’s my preferred single-expression form.

However,

for x in test_list:
    if x.value == value:
        print("i found it!")
        break

The naive loop-break version, is perfectly Pythonic — it’s concise, clear, and efficient. To make it match the behavior of the one-liner:

for x in test_list:
    if x.value == value:
        print("i found it!")
        break
else:
    x = None

This will assign None to x if you don’t break out of the loop.


回答 1

由于尚未提及仅仅是为了完成。好的ol’过滤器可过滤您要过滤的元素。

函数编程

####### Set Up #######
class X:

    def __init__(self, val):
        self.val = val

elem = 5

my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]

####### Set Up #######

### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on

print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)

### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
#   File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
#     print(next(my_filter_iter).value)
# StopIteration


# You can do that None stuff or whatever at this point, if you don't like exceptions.

我知道通常在python列表中首选理解,或者至少这是我读到的,但是我不认为这个问题是诚实的。当然,Python不是FP语言,但是Map / Reduce / Filter完全可读,并且是函数式编程中最标准的标准用例。

所以你去了。了解您的函数式编程。

过滤条件列表

没有比这更容易的了:

next(filter(lambda x: x.val == value,  my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions

Since it has not been mentioned just for completion. The good ol’ filter to filter your to be filtered elements.

Functional programming ftw.

####### Set Up #######
class X:

    def __init__(self, val):
        self.val = val

elem = 5

my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]

####### Set Up #######

### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on

print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)

### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
#   File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
#     print(next(my_filter_iter).value)
# StopIteration


# You can do that None stuff or whatever at this point, if you don't like exceptions.

I know that generally in python list comprehensions are preferred or at least that is what I read, but I don’t see the issue to be honest. Of course Python is not an FP language, but Map / Reduce / Filter are perfectly readable and are the most standard of standard use cases in functional programming.

So there you go. Know thy functional programming.

filter condition list

It won’t get any easier than this:

next(filter(lambda x: x.val == value,  my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions

回答 2

一个简单的例子:我们有以下数组

li = [{"id":1,"name":"ronaldo"},{"id":2,"name":"messi"}]

现在,我们要在数组中找到ID等于1的对象

  1. next列表理解的使用方法
next(x for x in li if x["id"] == 1 )
  1. 使用列表理解并返回第一项
[x for x in li if x["id"] == 1 ][0]
  1. 自定义功能
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

输出以上所有方法是 {'id': 1, 'name': 'ronaldo'}

A simple example: We have the following array

li = [{"id":1,"name":"ronaldo"},{"id":2,"name":"messi"}]

Now, we want to find the object in the array that has id equal to 1

  1. Use method next with list comprehension
next(x for x in li if x["id"] == 1 )
  1. Use list comprehension and return first item
[x for x in li if x["id"] == 1 ][0]
  1. Custom Function
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

Output all the above methods is {'id': 1, 'name': 'ronaldo'}


回答 3

我遇到了一个类似的问题,针对列表中没有对象符合要求的情况设计了一个小型优化(对于我的用例,这导致了重大的性能改进):

与列表test_list一起,我还有一个额外的集合test_value_set,它由我需要过滤的列表的值组成。因此,这里的agf解决方案的其他部分变得非常快。

I just ran into a similar problem and devised a small optimization for the case where no object in the list meets the requirement.(for my use-case this resulted in major performance improvement):

Along with the list test_list, I keep an additional set test_value_set which consists of values of the list that I need to filter on. So here the else part of agf’s solution becomes very-fast.


回答 4

你可以做这样的事情

dict = [{
   "id": 1,
   "name": "Doom Hammer"
 },
 {
    "id": 2,
    "name": "Rings ov Saturn"
 }
]

for x in dict:
  if x["id"] == 2:
    print(x["name"])

那就是我用来在长对象数组中查找对象的东西。

You could do something like this

dict = [{
   "id": 1,
   "name": "Doom Hammer"
 },
 {
    "id": 2,
    "name": "Rings ov Saturn"
 }
]

for x in dict:
  if x["id"] == 2:
    print(x["name"])

Thats what i use to find the objects in a long array of objects.


回答 5

您还可以通过__eq__方法为Test类和use in运算符实现丰富的比较。不知道这是否是最好的独立方法,但是如果您需要Test基于value其他地方比较实例,这可能会很有用。

class Test:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        """To implement 'in' operator"""
        # Comparing with int (assuming "value" is int)
        if isinstance(other, int):
            return self.value == other
        # Comparing with another Test object
        elif isinstance(other, Test):
            return self.value == other.value

import random

value = 5

test_list = [Test(random.randint(0,100)) for x in range(1000)]

if value in test_list:
    print "i found it"

You could also implement rich comparison via __eq__ method for your Test class and use in operator. Not sure if this is the best stand-alone way, but in case if you need to compare Test instances based on value somewhere else, this could be useful.

class Test:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        """To implement 'in' operator"""
        # Comparing with int (assuming "value" is int)
        if isinstance(other, int):
            return self.value == other
        # Comparing with another Test object
        elif isinstance(other, Test):
            return self.value == other.value

import random

value = 5

test_list = [Test(random.randint(0,100)) for x in range(1000)]

if value in test_list:
    print "i found it"

回答 6

对于下面的代码,xGen是一个匿名生成器表达式,yFilt是一个过滤器对象。请注意,对于xGen,将在列表耗尽时返回附加的None参数,而不是抛出StopIteration。

arr =((10,0), (11,1), (12,2), (13,2), (14,3))

value = 2
xGen = (x for x in arr if x[1] == value)
yFilt = filter(lambda x: x[1] == value, arr)
print(type(xGen))
print(type(yFilt))

for i in range(1,4):
    print('xGen: pass=',i,' result=',next(xGen,None))
    print('yFilt: pass=',i,' result=',next(yFilt))

输出:

<class 'generator'>
<class 'filter'>
xGen: pass= 1  result= (12, 2)
yFilt: pass= 1  result= (12, 2)
xGen: pass= 2  result= (13, 2)
yFilt: pass= 2  result= (13, 2)
xGen: pass= 3  result= None
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    print('yFilt: pass=',i,' result=',next(yFilt))
StopIteration

For below code, xGen is an anonomous generator expression, yFilt is a filter object. Note that for xGen the additional None parameter is returned rather than throwing StopIteration when the list is exhausted.

arr =((10,0), (11,1), (12,2), (13,2), (14,3))

value = 2
xGen = (x for x in arr if x[1] == value)
yFilt = filter(lambda x: x[1] == value, arr)
print(type(xGen))
print(type(yFilt))

for i in range(1,4):
    print('xGen: pass=',i,' result=',next(xGen,None))
    print('yFilt: pass=',i,' result=',next(yFilt))

Output:

<class 'generator'>
<class 'filter'>
xGen: pass= 1  result= (12, 2)
yFilt: pass= 1  result= (12, 2)
xGen: pass= 2  result= (13, 2)
yFilt: pass= 2  result= (13, 2)
xGen: pass= 3  result= None
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    print('yFilt: pass=',i,' result=',next(yFilt))
StopIteration

如何在Django中创建子弹?

问题:如何在Django中创建子弹?

我正在尝试SlugField在Django中创建一个。

我创建了这个简单的模型:

from django.db import models

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

然后,我这样做:

>>> from mysite.books.models import Test
>>> t=Test(q="aa a a a", s="b b b b")
>>> t.s
'b b b b'
>>> t.save()
>>> t.s
'b b b b'

我在期待b-b-b-b

I am trying to create a SlugField in Django.

I created this simple model:

from django.db import models

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

I then do this:

>>> from mysite.books.models import Test
>>> t=Test(q="aa a a a", s="b b b b")
>>> t.s
'b b b b'
>>> t.save()
>>> t.s
'b b b b'

I was expecting b-b-b-b.


回答 0

您将需要使用Slugify函数。

>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>

您可以slugify通过覆盖save方法自动调用:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

    def save(self, *args, **kwargs):
        self.s = slugify(self.q)
        super(Test, self).save(*args, **kwargs)

请注意,以上内容将导致您在修改q字段时更改您的URL ,这可能会导致链接断开。创建新对象时最好只生成一次子弹:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

    def save(self, *args, **kwargs):
        if not self.id:
            # Newly created object, so set slug
            self.s = slugify(self.q)

        super(Test, self).save(*args, **kwargs)

You will need to use the slugify function.

>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>

You can call slugify automatically by overriding the save method:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()
    
    def save(self, *args, **kwargs):
        self.s = slugify(self.q)
        super(Test, self).save(*args, **kwargs)

Be aware that the above will cause your URL to change when the q field is edited, which can cause broken links. It may be preferable to generate the slug only once when you create a new object:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()
    
    def save(self, *args, **kwargs):
        if not self.id:
            # Newly created object, so set slug
            self.s = slugify(self.q)

        super(Test, self).save(*args, **kwargs)

回答 1

有一些utf-8字符的特殊情况

例:

>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"

这可以用Unidecode解决

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'

There is corner case with some utf-8 characters

Example:

>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"

This can be solved with Unidecode

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'

回答 2

对Thepeer答案的一个小修正:要覆盖save()模型类中的函数,最好向其添加参数:

from django.utils.text import slugify

def save(self, *args, **kwargs):
    if not self.id:
        self.s = slugify(self.q)

    super(test, self).save(*args, **kwargs)

否则,test.objects.create(q="blah blah blah")将导致force_insert错误(意外参数)。

A small correction to Thepeer’s answer: To override save() function in model classes, better add arguments to it:

from django.utils.text import slugify

def save(self, *args, **kwargs):
    if not self.id:
        self.s = slugify(self.q)

    super(test, self).save(*args, **kwargs)

Otherwise, test.objects.create(q="blah blah blah") will result in a force_insert error (unexpected argument).


回答 3

如果您使用的管理界面增加模型的新项目,你可以建立一个ModelAdmin在你admin.py和利用prepopulated_fields自动进入蛞蝓的:

class ClientAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Client, ClientAdmin)

在这里,当用户在admin表单中为该name字段输入值时,slug将使用正确的slugified自动填充name

If you’re using the admin interface to add new items of your model, you can set up a ModelAdmin in your admin.py and utilize prepopulated_fields to automate entering of a slug:

class ClientAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Client, ClientAdmin)

Here, when the user enters a value in the admin form for the name field, the slug will be automatically populated with the correct slugified name.


回答 4

在大多数情况下,该条块不应更改,因此您实际上只想在首次保存时进行计算:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(editable=False) # hide from admin

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(Test, self).save()

In most cases the slug should not change, so you really only want to calculate it on first save:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(editable=False) # hide from admin

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(Test, self).save()

回答 5

使用prepopulated_fields在您的管理类:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Article, ArticleAdmin)

Use prepopulated_fields in your admin class:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Article, ArticleAdmin)

回答 6

如果您不想将slugfield设置为“不可编辑”,那么我相信您希望将Null和Blank属性设置为False。否则,尝试保存到Admin时会收到错误消息。

因此,对上述示例的修改如下:

class test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(null=True, blank=True) # Allow blank submission in admin.

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(test, self).save()

If you don’t want to set the slugfield to Not be editable, then I believe you’ll want to set the Null and Blank properties to False. Otherwise you’ll get an error when trying to save in Admin.

So a modification to the above example would be::

class test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(null=True, blank=True) # Allow blank submission in admin.

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(test, self).save()

回答 7

我正在使用Django 1.7

像这样在模型中创建一个SlugField:

slug = models.SlugField()

然后在admin.py定义prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

I’m using Django 1.7

Create a SlugField in your model like this:

slug = models.SlugField()

Then in admin.py define prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

回答 8

您可以查看的文档,SlugField以更具描述性的方式进一步了解它。

You can look at the docs for the SlugField to get to know more about it in more descriptive way.


Django-如何使用South重命名模型字段?

问题:Django-如何使用South重命名模型字段?

我想更改模型中特定字段的名称:

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

应更改为:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

使用South进行此操作最简单的方法是什么?

I would like to change a name of specific fields in a model:

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

should change to:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

What’s the easiest way to do this using South?


回答 0

您可以使用该db.rename_column功能。

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

表的第一个参数db.rename_column是表名,因此记住Django如何创建表名很重要:

Django会自动从您的模型类的名称和包含该表的应用程序中获取数据库表的名称。通过将模型的“应用程序标签”(即您在manage.py startapp中使用的名称)连接到模型的类名称,并在其之间加下划线,来构造模型的数据库表名称。

在你有一个多措辞,骆驼套管型号名称的情况下,如项目项,表名会app_projectitem(即下划线不会之间插入projectitem即使它们是骆驼式大小写)。

You can use the db.rename_column function.

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

The first argument of db.rename_column is the table name, so it’s important to remember how Django creates table names:

Django automatically derives the name of the database table from the name of your model class and the app that contains it. A model’s database table name is constructed by joining the model’s “app label” — the name you used in manage.py startapp — to the model’s class name, with an underscore between them.

In the case where you have a multi-worded, camel-cased model name, such as ProjectItem, the table name will be app_projectitem (i.e., an underscore will not be inserted between project and item even though they are camel-cased).


回答 1

这是我的工作:

  1. 在模型中更改列名(在本示例中为myapp/models.py
  2. ./manage.py schemamigration myapp renaming_column_x --auto

注意renaming_column_x可以是任何您喜欢的东西,它只是给迁移文件起一个描述性名称的一种方式。

这将为您生成一个名为的文件myapp/migrations/000x_renaming_column_x.py,该文件将删除您的旧列并添加一个新列。

修改此文件中的代码,以将迁移行为更改为简单的重命名:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')

Here’s what I do:

  1. Make the column name change in your model (in this example it would be myapp/models.py)
  2. Run ./manage.py schemamigration myapp renaming_column_x --auto

Note renaming_column_x can be anything you like, it’s just a way of giving a descriptive name to the migration file.

This will generate you a file called myapp/migrations/000x_renaming_column_x.py which will delete your old column and add a new column.

Modify the code in this file to change the migration behaviour to a simple rename:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')

回答 2

我不知道db.rename列,听起来很方便,但是在过去,我将新列添加为一个schemamigration,然后创建了一个datamigration将值移到新字段中,然后创建了另一个schemamigration以删除旧列。

I didn’t know about db.rename column, sounds handy, however in the past I have added the new column as one schemamigration, then created a datamigration to move values into the new field, then a second schemamigration to remove the old column


回答 3

Django 1.7引入了Migrations,所以现在您甚至不需要安装额外的软件包即可管理迁移。

要重命名模型,您需要首先创建空迁移:

$ manage.py makemigrations <app_name> --empty

然后,您需要像这样编辑迁移代码:

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

然后,您需要运行:

$ manage.py migrate <app_name>

Django 1.7 introduced Migrations so now you don’t even need to install extra package to manage your migrations.

To rename your model you need to create empty migration first:

$ manage.py makemigrations <app_name> --empty

Then you need to edit your migration’s code like this:

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

And after that you need to run:

$ manage.py migrate <app_name>

回答 4

只需更改模型并makemigrations在1.9中运行

Django自动检测到您已删除并创建了一个字段,并询问:

Did you rename model.old to model.new (a IntegerField)? [y/N]

同意,就可以创建正确的迁移。魔法。

Just change the model and run makemigrations in 1.9

Django automatically detects that you’ve deleted and created a single field, and asks:

Did you rename model.old to model.new (a IntegerField)? [y/N]

Say yes, and the right migration gets created. Magic.


回答 5

  1. south在项目设置文件中添加到已安装的应用程序。
  2. 注释掉添加/修改的字段/表。
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. 取消注释该字段并写入修改后的字段
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

如果使用的是“ pycharm”,则可以使用“ ctrl + shift + r”代替“ manage.py”,并使用“ shift”作为参数。

  1. Add south to your installed apps in project setting file.
  2. Comment out the added/modified field/table.
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. Un-comment the field and write the modified one
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

If you are using ‘pycharm’, then you can use ‘ctrl+shift+r’ instead of ‘manage.py’ , and ‘shift ‘ for parameters.