标签归档:Django

通过choices =…设置Django IntegerField

问题:通过choices =…设置Django IntegerField

当您拥有一个带有选项选项的模型字段时,您倾向于具有一些与人类可读名称相关的魔术值。Django中是否有一种方便的方法来通过人类可读的名称而不是值来设置这些字段?

考虑以下模型:

class Thing(models.Model):
  PRIORITIES = (
    (0, 'Low'),
    (1, 'Normal'),
    (2, 'High'),
  )

  priority = models.IntegerField(default=0, choices=PRIORITIES)

在某个时候,我们有一个Thing实例,我们想设置它的优先级。显然你可以做,

thing.priority = 1

但这迫使您记住优先级的值-名称映射。这不起作用:

thing.priority = 'Normal' # Throws ValueError on .save()

目前,我有这个愚蠢的解决方法:

thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']

但这很笨重。考虑到这种情况有多普遍,我想知道是否有人有更好的解决方案。是否有一些我完全忽略的通过选择名称设置字段的字段方法?

When you have a model field with a choices option you tend to have some magic values associated with human readable names. Is there in Django a convenient way to set these fields by the human readable name instead of the value?

Consider this model:

class Thing(models.Model):
  PRIORITIES = (
    (0, 'Low'),
    (1, 'Normal'),
    (2, 'High'),
  )

  priority = models.IntegerField(default=0, choices=PRIORITIES)

At some point we have a Thing instance and we want to set its priority. Obviously you could do,

thing.priority = 1

But that forces you to memorize the Value-Name mapping of PRIORITIES. This doesn’t work:

thing.priority = 'Normal' # Throws ValueError on .save()

Currently I have this silly workaround:

thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']

but that’s clunky. Given how common this scenario could be I was wondering if anyone had a better solution. Is there some field method for setting fields by choice name which I totally overlooked?


回答 0

如做在这里看到。然后,您可以使用代表适当整数的单词。

像这样:

LOW = 0
NORMAL = 1
HIGH = 2
STATUS_CHOICES = (
    (LOW, 'Low'),
    (NORMAL, 'Normal'),
    (HIGH, 'High'),
)

然后它们仍然是数据库中的整数。

用法是 thing.priority = Thing.NORMAL

Do as seen here. Then you can use a word that represents the proper integer.

Like so:

LOW = 0
NORMAL = 1
HIGH = 2
STATUS_CHOICES = (
    (LOW, 'Low'),
    (NORMAL, 'Normal'),
    (HIGH, 'High'),
)

Then they are still integers in the DB.

Usage would be thing.priority = Thing.NORMAL


回答 1

我可能会一劳永逸地设置反向查询字典,但是如果没有,我只会使用:

thing.priority = next(value for value, name in Thing.PRIORITIES
                      if name=='Normal')

这似乎比立即构建dict再扔掉要简单得多;-)。

I’d probably set up the reverse-lookup dict once and for all, but if I hadn’t I’d just use:

thing.priority = next(value for value, name in Thing.PRIORITIES
                      if name=='Normal')

which seems simpler than building the dict on the fly just to toss it away again;-).


回答 2

这是我几分钟前写的一种字段类型,我认为它满足您的要求。它的构造函数需要一个参数“ choices”,它可以是2元组的元组,格式与IntegerField的choices选项相同,也可以是简单的名称列表(例如ChoiceField((’Low’,’Normal’, ‘高’),默认=’低’)。该类为您处理从字符串到int的映射,您从不会看到int。

  class ChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if not hasattr(choices[0],'__iter__'):
            choices = zip(range(len(choices)), choices)

        self.val2choice = dict(choices)
        self.choice2val = dict((v,k) for k,v in choices)

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.val2choice[value]

    def get_db_prep_value(self, choice):
        return self.choice2val[choice]

Here’s a field type I wrote a few minutes ago that I think does what you want. Its constructor requires an argument ‘choices’, which may be either a tuple of 2-tuples in the same format as the choices option to IntegerField, or instead a simple list of names (ie ChoiceField((‘Low’, ‘Normal’, ‘High’), default=’Low’) ). The class takes care of the mapping from string to int for you, you never see the int.

  class ChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if not hasattr(choices[0],'__iter__'):
            choices = zip(range(len(choices)), choices)

        self.val2choice = dict(choices)
        self.choice2val = dict((v,k) for k,v in choices)

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.val2choice[value]

    def get_db_prep_value(self, choice):
        return self.choice2val[choice]

回答 3

我欣赏不断的定义方式,但我相信枚举类型最适合此任务。它们可以同时表示一个项目的整数和字符串,同时保持代码的可读性。

枚举在版本3.4中引入Python。如果您使用的是任何较低版本(例如v2.x),则仍可以通过安装向后移植的软件包来安装它:pip install enum34

# myapp/fields.py
from enum import Enum    


class ChoiceEnum(Enum):

    @classmethod
    def choices(cls):
        choices = list()

        # Loop thru defined enums
        for item in cls:
            choices.append((item.value, item.name))

        # return as tuple
        return tuple(choices)

    def __str__(self):
        return self.name

    def __int__(self):
        return self.value


class Language(ChoiceEnum):
    Python = 1
    Ruby = 2
    Java = 3
    PHP = 4
    Cpp = 5

# Uh oh
Language.Cpp._name_ = 'C++'

这几乎就是全部。您可以继承ChoiceEnum来创建自己的定义,并在模型定义中使用它们,例如:

from django.db import models
from myapp.fields import Language

class MyModel(models.Model):
    language = models.IntegerField(choices=Language.choices(), default=int(Language.Python))
    # ...

您可能会猜到查询是锦上添花:

MyModel.objects.filter(language=int(Language.Ruby))
# or if you don't prefer `__int__` method..
MyModel.objects.filter(language=Language.Ruby.value)

用字符串表示它们也很容易:

# Get the enum item
lang = Language(some_instance.language)

print(str(lang))
# or if you don't prefer `__str__` method..
print(lang.name)

# Same as get_FOO_display
lang.name == some_instance.get_language_display()

I appreciate the constant defining way but I believe Enum type is far best for this task. They can represent integer and a string for an item in the same time, while keeping your code more readable.

Enums were introduced to Python in version 3.4. If you are using any lower (such as v2.x) you can still have it by installing the backported package: pip install enum34.

# myapp/fields.py
from enum import Enum    


class ChoiceEnum(Enum):

    @classmethod
    def choices(cls):
        choices = list()

        # Loop thru defined enums
        for item in cls:
            choices.append((item.value, item.name))

        # return as tuple
        return tuple(choices)

    def __str__(self):
        return self.name

    def __int__(self):
        return self.value


class Language(ChoiceEnum):
    Python = 1
    Ruby = 2
    Java = 3
    PHP = 4
    Cpp = 5

# Uh oh
Language.Cpp._name_ = 'C++'

This is pretty much all. You can inherit the ChoiceEnum to create your own definitions and use them in a model definition like:

from django.db import models
from myapp.fields import Language

class MyModel(models.Model):
    language = models.IntegerField(choices=Language.choices(), default=int(Language.Python))
    # ...

Querying is icing on the cake as you may guess:

MyModel.objects.filter(language=int(Language.Ruby))
# or if you don't prefer `__int__` method..
MyModel.objects.filter(language=Language.Ruby.value)

Representing them in string is also made easy:

# Get the enum item
lang = Language(some_instance.language)

print(str(lang))
# or if you don't prefer `__str__` method..
print(lang.name)

# Same as get_FOO_display
lang.name == some_instance.get_language_display()

回答 4

class Sequence(object):
    def __init__(self, func, *opts):
        keys = func(len(opts))
        self.attrs = dict(zip([t[0] for t in opts], keys))
        self.choices = zip(keys, [t[1] for t in opts])
        self.labels = dict(self.choices)
    def __getattr__(self, a):
        return self.attrs[a]
    def __getitem__(self, k):
        return self.labels[k]
    def __len__(self):
        return len(self.choices)
    def __iter__(self):
        return iter(self.choices)
    def __deepcopy__(self, memo):
        return self

class Enum(Sequence):
    def __init__(self, *opts):
        return super(Enum, self).__init__(range, *opts)

class Flags(Sequence):
    def __init__(self, *opts):
        return super(Flags, self).__init__(lambda l: [1<<i for i in xrange(l)], *opts)

像这样使用它:

Priorities = Enum(
    ('LOW', 'Low'),
    ('NORMAL', 'Normal'),
    ('HIGH', 'High')
)

priority = models.IntegerField(default=Priorities.LOW, choices=Priorities)
class Sequence(object):
    def __init__(self, func, *opts):
        keys = func(len(opts))
        self.attrs = dict(zip([t[0] for t in opts], keys))
        self.choices = zip(keys, [t[1] for t in opts])
        self.labels = dict(self.choices)
    def __getattr__(self, a):
        return self.attrs[a]
    def __getitem__(self, k):
        return self.labels[k]
    def __len__(self):
        return len(self.choices)
    def __iter__(self):
        return iter(self.choices)
    def __deepcopy__(self, memo):
        return self

class Enum(Sequence):
    def __init__(self, *opts):
        return super(Enum, self).__init__(range, *opts)

class Flags(Sequence):
    def __init__(self, *opts):
        return super(Flags, self).__init__(lambda l: [1<<i for i in xrange(l)], *opts)

Use it like this:

Priorities = Enum(
    ('LOW', 'Low'),
    ('NORMAL', 'Normal'),
    ('HIGH', 'High')
)

priority = models.IntegerField(default=Priorities.LOW, choices=Priorities)

回答 5

从Django 3.0开始,您可以使用:

class ThingPriority(models.IntegerChoices):
    LOW = 0, 'Low'
    NORMAL = 1, 'Normal'
    HIGH = 2, 'High'


class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.LOW, choices=ThingPriority.choices)

# then in your code
thing = get_my_thing()
thing.priority = ThingPriority.HIGH

As of Django 3.0, you can use:

class ThingPriority(models.IntegerChoices):
    LOW = 0, 'Low'
    NORMAL = 1, 'Normal'
    HIGH = 2, 'High'


class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.LOW, choices=ThingPriority.choices)

# then in your code
thing = get_my_thing()
thing.priority = ThingPriority.HIGH

回答 6

只需将数字替换为您想要的可读值即可。因此:

PRIORITIES = (
('LOW', 'Low'),
('NORMAL', 'Normal'),
('HIGH', 'High'),
)

这使其易于阅读,但是,您必须定义自己的顺序。

Simply replace your numbers with the human readable values you would like. As such:

PRIORITIES = (
('LOW', 'Low'),
('NORMAL', 'Normal'),
('HIGH', 'High'),
)

This makes it human readable, however, you’d have to define your own ordering.


回答 7

我的回答很晚,对于如今的Django专家来说似乎很明显,但是对于在这里居住的人来说,我最近发现了django-model-utils带来的一种非常优雅的解决方案:https : //django-model-utils.readthedocs.io/ zh / latest / utilities.html#choices

此程序包使您可以定义具有三元组的Choices,其中:

  • 第一项是数据库值
  • 第二项是代码可读值
  • 第三项是人类可读的值

因此,您可以执行以下操作:

from model_utils import Choices

class Thing(models.Model):
    PRIORITIES = Choices(
        (0, 'low', 'Low'),
        (1, 'normal', 'Normal'),
        (2, 'high', 'High'),
      )

    priority = models.IntegerField(default=PRIORITIES.normal, choices=PRIORITIES)

thing.priority = getattr(Thing.PRIORITIES.Normal)

这条路:

  • 您可以使用人类可读的值来实际选择字段的值(对我而言,这非常有用,因为我正在抓取疯狂的内容并将其以规范化的方式存储)
  • 干净值存储在数据库中
  • 您没有非DRY可以做的事;)

请享用 :)

My answer is very late and might seem obvious to nowadays-Django experts, but to whoever lands here, i recently discovered a very elegant solution brought by django-model-utils: https://django-model-utils.readthedocs.io/en/latest/utilities.html#choices

This package allows you to define Choices with three-tuples where:

  • The first item is the database value
  • The second item is a code-readable value
  • The third item is a human-readable value

So here’s what you can do:

from model_utils import Choices

class Thing(models.Model):
    PRIORITIES = Choices(
        (0, 'low', 'Low'),
        (1, 'normal', 'Normal'),
        (2, 'high', 'High'),
      )

    priority = models.IntegerField(default=PRIORITIES.normal, choices=PRIORITIES)

thing.priority = getattr(Thing.PRIORITIES.Normal)

This way:

  • You can use your human-readable value to actually choose the value of your field (in my case, it’s useful because i’m scraping wild content and storing it in a normalized way)
  • A clean value is stored in your database
  • You have nothing non-DRY to do ;)

Enjoy :)


回答 8

最初,我使用@Allan答案的修改版本:

from enum import IntEnum, EnumMeta

class IntegerChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if hasattr(choices, '__iter__') and isinstance(choices, EnumMeta):
            choices = list(zip(range(1, len(choices) + 1), [member.name for member in list(choices)]))

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.choices(value)

    def get_db_prep_value(self, choice):
        return self.choices[choice]

models.IntegerChoiceField = IntegerChoiceField

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    #type = models.IntegerChoiceField(GEAR, default=list(GEAR)[-1].name)
    largest_member = GEAR(max([member.value for member in list(GEAR)]))
    type = models.IntegerChoiceField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

print(Gear().HEAD, (Gear().HEAD == GEAR.HEAD.value))

django-enumfields我现在使用的包简化了:

from enumfields import EnumIntegerField, IntEnum

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    type = EnumIntegerField(GEAR, default=list(GEAR)[-1])
    #largest_member = GEAR(max([member.value for member in list(GEAR)]))
    #type = EnumIntegerField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

Originally I used a modified version of @Allan’s answer:

from enum import IntEnum, EnumMeta

class IntegerChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if hasattr(choices, '__iter__') and isinstance(choices, EnumMeta):
            choices = list(zip(range(1, len(choices) + 1), [member.name for member in list(choices)]))

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.choices(value)

    def get_db_prep_value(self, choice):
        return self.choices[choice]

models.IntegerChoiceField = IntegerChoiceField

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    #type = models.IntegerChoiceField(GEAR, default=list(GEAR)[-1].name)
    largest_member = GEAR(max([member.value for member in list(GEAR)]))
    type = models.IntegerChoiceField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

print(Gear().HEAD, (Gear().HEAD == GEAR.HEAD.value))

Simplified with the django-enumfields package package which I now use:

from enumfields import EnumIntegerField, IntEnum

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    type = EnumIntegerField(GEAR, default=list(GEAR)[-1])
    #largest_member = GEAR(max([member.value for member in list(GEAR)]))
    #type = EnumIntegerField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

回答 9

模型的choices选项接受一个序列,该序列本身由恰好两个项目(例如[[(A,B),(A,B)…])的可迭代项组成,用作该字段的选择。

另外,Django提供 枚举类型,您可以枚举为子类,以简洁的方式定义选择:

class ThingPriority(models.IntegerChoices):
    LOW = 0, _('Low')
    NORMAL = 1, _('Normal')
    HIGH = 2, _('High')

class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.NORMAL, choices=ThingPriority.choices)

Django支持在该元组的末尾添加一个额外的字符串值,以用作人类可读的名称或标签。标签可以是懒惰的可翻译字符串。

   # in your code 
   thing = get_thing() # instance of Thing
   thing.priority = ThingPriority.LOW

注意:您可以使用,使用ThingPriority.HIGHThingPriority.['HIGH']ThingPriority(0)访问或查询枚举成员。

Model’s choices option accepts a sequence consisting itself of iterables of exactly two items (e.g. [(A, B), (A, B) …]) to use as choices for this field.

In addition, Django provides enumeration types that you can subclass to define choices in a concise way:

class ThingPriority(models.IntegerChoices):
    LOW = 0, _('Low')
    NORMAL = 1, _('Normal')
    HIGH = 2, _('High')

class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.NORMAL, choices=ThingPriority.choices)

Django supports adding an extra string value to the end of this tuple to be used as the human-readable name, or label. The label can be a lazy translatable string.

   # in your code 
   thing = get_thing() # instance of Thing
   thing.priority = ThingPriority.LOW

Note: you can use that using ThingPriority.HIGH, ThingPriority.['HIGH'], or ThingPriority(0) to access or lookup enum members.


无效的http_host标头

问题:无效的http_host标头

我正在尝试使用Django框架开发网站,并使用DigitalOcean.com启动并将必要的文件部署到django-project中。

我必须将静态文件包含到Django项目中,并且在收集静态文件后,我尝试刷新我的ip

我包括了我用来创建网站的教程。 https://www.pythonprogramming.net/django-web-server-publish-tutorial/

我收到以下错误:

/无效的HTTP_HOST标头中的DisallowedHost:“ 198.211.99.20”。您可能需要将u’198.211.99.20’添加到ALLOWED_HOSTS。

有人可以帮我解决这个问题吗?这是我第一个使用Django框架的网站。

I am trying to develop a website using Django framework and launched using DigitalOcean.com and deployed the necessary files into django-project.

I had to include static files into Django-project and After collecting static files, I tried to refresh my ip

I am including the tutorials which I have used to create the website. https://www.pythonprogramming.net/django-web-server-publish-tutorial/

I am getting the following error :

DisallowedHost at / Invalid HTTP_HOST header: ‘198.211.99.20’. You may need to add u’198.211.99.20′ to ALLOWED_HOSTS.

Can somebody help me to fix this ? This is my first website using Django framework.


回答 0

错误日志很简单。如它的建议,您需要 在设置中添加198.211.99.20ALLOWED_HOSTS

在您的项目settings.py文件中,设置ALLOWED_HOSTS如下:

ALLOWED_HOSTS = ['198.211.99.20', 'localhost', '127.0.0.1']

如需进一步阅读,请从这里阅读

The error log is straightforward. As it suggested,You need to add 198.211.99.20 to your ALLOWED_HOSTS setting.

In your project settings.py file,set ALLOWED_HOSTS like this :

ALLOWED_HOSTS = ['198.211.99.20', 'localhost', '127.0.0.1']

For further reading read from here.


回答 1

settings.py

ALLOWED_HOSTS = ['*']

settings.py

ALLOWED_HOSTS = ['*']

django模板:包括和扩展

问题:django模板:包括和扩展

我想在2个不同的基本文件中提供相同的内容。

所以我正在尝试这样做:

page1.html:

{% extends "base1.html" %}
{% include "commondata.html" %}

page2.html:

{% extends "base2.html" %} 
{% include "commondata.html" %}

问题是我似乎无法同时使用扩展和包含。有什么办法吗?如果没有,我该如何完成以上工作?

commondata.html覆盖base1.html和base2.html中指定的块

这样做的目的是提供pdf和html格式的同一页面,但格式略有不同。上面的问题虽然简化了我要尝试做的事情,但是如果我可以得到答案,它将解决我的问题。

I would like to provide the same content inside 2 different base files.

So I’m trying to do this:

page1.html:

{% extends "base1.html" %}
{% include "commondata.html" %}

page2.html:

{% extends "base2.html" %} 
{% include "commondata.html" %}

The problem is that I can’t seem to use both extends and include. Is there some way to do that? And if not, how can I accomplish the above?

commondata.html overrides a block that is specified in both base1.html and base2.html

The purpose of this is to provide the same page in both pdf and html format, where the formatting is slightly different. The above question though simplifies what I’m trying to do so if I can get an answer to that it will solve my problem.


回答 0

使用扩展模板标签时,是指当前模板扩展了另一个模板-它是子模板,取决于父模板。Django将查看您的子模板,并使用其内容填充父模板。

您想要在子模板中使用的所有内容都应位于block之内,Django使用该块来填充父模板。如果要在该子模板中使用include语句,则必须将其放在一个块中,以便Django理解。否则,这只是没有意义,而Django不知道该怎么做。

Django文档中有一些非常好的示例,这些示例使用块替换父模板中的块。

https://docs.djangoproject.com/zh-CN/dev/ref/templates/language/#template-inheritance

When you use the extends template tag, you’re saying that the current template extends another — that it is a child template, dependent on a parent template. Django will look at your child template and use its content to populate the parent.

Everything that you want to use in a child template should be within blocks, which Django uses to populate the parent. If you want use an include statement in that child template, you have to put it within a block, for Django to make sense of it. Otherwise it just doesn’t make sense and Django doesn’t know what to do with it.

The Django documentation has a few really good examples of using blocks to replace blocks in the parent template.

https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance


回答 1

从Django文档中:

include标记应被视为“呈现此子模板并包含HTML”的实现,而不应视为“解析此子模板并像其父对象一样包含其内容”。这意味着在包含的模板之间没有共享状态-每个包含都是一个完全独立的呈现过程。

因此,Django不会从您的commondata.html中获取任何块,并且它也不知道如何处理呈现的html外部块。

From Django docs:

The include tag should be considered as an implementation of “render this subtemplate and include the HTML”, not as “parse this subtemplate and include its contents as if it were part of the parent”. This means that there is no shared state between included templates — each include is a completely independent rendering process.

So Django doesn’t grab any blocks from your commondata.html and it doesn’t know what to do with rendered html outside blocks.


回答 2

这应该为您解决了问题:将include标签放在块部分中。

page1.html:

{% extends "base1.html" %}

{% block foo %}
   {% include "commondata.html" %}
{% endblock %}

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}

This should do the trick for you: put include tag inside of a block section.

page1.html:

{% extends "base1.html" %}

{% block foo %}
   {% include "commondata.html" %}
{% endblock %}

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}

回答 3

如果它对将来的人有帮助,为什么它对我不起作用的更多信息:

之所以不起作用,是因为django中的{%include%}不喜欢像特殊的撇号这样的特殊字符。我尝试包含的模板数据是从Word粘贴的。我必须手动删除所有这些特殊字符,然后成功包含其中。

More info about why it wasn’t working for me in case it helps future people:

The reason why it wasn’t working is that {% include %} in django doesn’t like special characters like fancy apostrophe. The template data I was trying to include was pasted from word. I had to manually remove all of these special characters and then it included successfully.


回答 4

您不能将包含文件中的块拉入子模板以覆盖父模板的块。但是,您可以在变量中指定父项,并在上下文中指定基本模板。

文档中

{%扩展变量%}使用变量的值。如果该变量的值为字符串,则Django将使用该字符串作为父模板的名称。如果该变量的值为模板对象,则Django将使用该对象作为父模板。

代替单独的“ page1.html”和“ page2.html”,放在“ commondata.html” {% extends base_template %}的顶部。然后在您的视图中,定义base_template为“ base1.html”或“ base2.html”。

You can’t pull in blocks from an included file into a child template to override the parent template’s blocks. However, you can specify a parent in a variable and have the base template specified in the context.

From the documentation:

{% extends variable %} uses the value of variable. If the variable evaluates to a string, Django will use that string as the name of the parent template. If the variable evaluates to a Template object, Django will use that object as the parent template.

Instead of separate “page1.html” and “page2.html”, put {% extends base_template %} at the top of “commondata.html”. And then in your view, define base_template to be either “base1.html” or “base2.html”.


回答 5

添加以供将来通过Google找到它的人参考:对于此类情况,您可能需要查看夹层库提供的{%overextend%}标签。

Added for reference to future people who find this via google: You might want to look at the {% overextend %} tag provided by the mezzanine library for cases like this.


回答 6

编辑2015年12月10日:正如评论中指出的那样,自1.8版起不推荐使用ssi。根据文档:

该标签已被弃用,并将在Django 1.10中删除。请改用include标签。


在我看来,这个问题的正确答案(最好)是podshumok提出的答案,因为它解释了为什么在与继承一起使用时include的行为。

但是,令我感到有些惊讶的是,没有人提到Django模板系统提供的ssi标记,该标记是专门为内联式设计的,包括一个外部文本。在此,内联表示不会解释,解析或插入外部文本,而只是在调用模板内部“复制”。

请参考文档以获取更多详细信息(请确保在页面右下方的选择器中检查您所使用的Django版本)。

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi

从文档中:

ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
 which must be specified using an absolute path  in the current page

还请注意此技术的安全隐患以及必需的ALLOWED_INCLUDE_ROOTS定义,必须将其添加到设置文件中。

Edit 10th Dec 2015: As pointed out in the comments, ssi is deprecated since version 1.8. According to the documentation:

This tag has been deprecated and will be removed in Django 1.10. Use the include tag instead.


In my opinion, the right (best) answer to this question is the one from podshumok, as it explains why the behaviour of include when used along with inheritance.

However, I was somewhat surprised that nobody mentioned the ssi tag provided by the Django templating system, which is specifically designed for inline including an external piece of text. Here, inline means the external text will not be interpreted, parsed or interpolated, but simply “copied” inside the calling template.

Please, refer to the documentation for further details (be sure to check your appropriate version of Django in the selector at the lower right part of the page).

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi

From the documentation:

ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
– which must be specified using an absolute path – in the current page

Beware also of the security implications of this technique and also of the required ALLOWED_INCLUDE_ROOTS define, which must be added to your settings files.


Django Rest Framework-无法使用视图名称“ user-detail”解析超链接关系的URL

问题:Django Rest Framework-无法使用视图名称“ user-detail”解析超链接关系的URL

我正在Django Rest Framework中建立一个项目,用户可以登录查看其酒窖。我的ModelViewSets工作正常,突然我收到了一个令人沮丧的错误:

无法使用视图名称“用户详细信息”解析超链接关系的URL。您可能无法在API中包含相关模型,或者lookup_field在此字段上配置了错误的属性。

追溯显示:

    [12/Dec/2013 18:35:29] "GET /bottles/ HTTP/1.1" 500 76677
Internal Server Error: /bottles/
Traceback (most recent call last):
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 399, in dispatch
    response = self.handle_exception(exc)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 396, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/mixins.py", line 96, in list
    return Response(serializer.data)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 535, in data
    self._data = [self.to_native(item) for item in obj]
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 325, in to_native
    value = field.field_to_native(obj, field_name)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 153, in field_to_native
    return self.to_native(value)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 452, in to_native
    raise Exception(msg % view_name)
Exception: Could not resolve URL for hyperlinked relationship using view 
name "user-detail". You may have failed to include the related model in 
your API, or incorrectly configured the `lookup_field` attribute on this 
field.

我有一个自定义的电子邮件用户模型,并且models.py中的瓶子模型是:

class Bottle(models.Model):    
      wine = models.ForeignKey(Wine, null=False)
      user = models.ForeignKey(User, null=False, related_name='bottles')

我的序列化器:

class BottleSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Bottle
        fields = ('url', 'wine', 'user')

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'password', 'is_superuser')

我的看法:

class BottleViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows bottles to be viewed or edited.
    """
    queryset = Bottle.objects.all()
    serializer_class = BottleSerializer

class UserViewSet(ListCreateAPIView):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

最后是URL:

router = routers.DefaultRouter()
router.register(r'bottles', views.BottleViewSet, base_name='bottles')

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    # ...

我没有用户详细信息视图,也看不到此问题可能来自何处。有任何想法吗?

谢谢

I am building a project in Django Rest Framework where users can login to view their wine cellar. My ModelViewSets were working just fine and all of a sudden I get this frustrating error:

Could not resolve URL for hyperlinked relationship using view name “user-detail”. You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

The traceback shows:

    [12/Dec/2013 18:35:29] "GET /bottles/ HTTP/1.1" 500 76677
Internal Server Error: /bottles/
Traceback (most recent call last):
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 399, in dispatch
    response = self.handle_exception(exc)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 396, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/mixins.py", line 96, in list
    return Response(serializer.data)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 535, in data
    self._data = [self.to_native(item) for item in obj]
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 325, in to_native
    value = field.field_to_native(obj, field_name)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 153, in field_to_native
    return self.to_native(value)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 452, in to_native
    raise Exception(msg % view_name)
Exception: Could not resolve URL for hyperlinked relationship using view 
name "user-detail". You may have failed to include the related model in 
your API, or incorrectly configured the `lookup_field` attribute on this 
field.

I have a custom email user model and the bottle model in models.py is:

class Bottle(models.Model):    
      wine = models.ForeignKey(Wine, null=False)
      user = models.ForeignKey(User, null=False, related_name='bottles')

My serializers:

class BottleSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Bottle
        fields = ('url', 'wine', 'user')

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'password', 'is_superuser')

My views:

class BottleViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows bottles to be viewed or edited.
    """
    queryset = Bottle.objects.all()
    serializer_class = BottleSerializer

class UserViewSet(ListCreateAPIView):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

and finally the url:

router = routers.DefaultRouter()
router.register(r'bottles', views.BottleViewSet, base_name='bottles')

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    # ...

I don’t have a user detail view and I don’t see where this issue could come from. Any ideas?

Thanks


回答 0

由于是HyperlinkedModelSerializer序列化程序,因此您的序列化程序正在尝试解析与User上相关的URL Bottle
由于您没有用户详细信息视图,因此无法执行此操作。因此,exceptions。

  1. 不仅仅是UserViewSet在路由器上注册可以解决您的问题吗?
  2. 您可以在自己的用户字段上定义BottleSerializer以显式使用,UserSerializer而不是尝试解析URL。请参阅有关处理嵌套对象序列化器文档

Because it’s a HyperlinkedModelSerializer your serializer is trying to resolve the URL for the related User on your Bottle.
As you don’t have the user detail view it can’t do this. Hence the exception.

  1. Would not just registering the UserViewSet with the router solve your issue?
  2. You could define the user field on your BottleSerializer to explicitly use the UserSerializer rather than trying to resolve the URL. See the serializer docs on dealing with nested objects for that.

回答 1

我也遇到了此错误,并按以下方式解决了该错误:

原因是我忘记给“ **-detail”(view_name,例如:user-detail)命名空间。因此,Django Rest Framework无法找到该视图。

我的项目中有一个应用程序,假设我的项目名称为myproject,而应用程序名称为myapp

有两个urls.py文件,一个是myproject/urls.py,另一个是myapp/urls.py。我在中为应用提供了一个命名空间myproject/urls.py,就像:

url(r'', include(myapp.urls, namespace="myapp")),

我在中注册了其余框架路由器myapp/urls.py,然后出现此错误。

我的解决方案是显式地为URL提供命名空间:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="myapp:user-detail")

    class Meta:
        model = User
        fields = ('url', 'username')

它解决了我的问题。

I came across this error too and solved it as follows:

The reason is I forgot giving “**-detail” (view_name, e.g.: user-detail) a namespace. So, Django Rest Framework could not find that view.

There is one app in my project, suppose that my project name is myproject, and the app name is myapp.

There is two urls.py file, one is myproject/urls.py and the other is myapp/urls.py. I give the app a namespace in myproject/urls.py, just like:

url(r'', include(myapp.urls, namespace="myapp")),

I registered the rest framework routers in myapp/urls.py, and then got this error.

My solution was to provide url with namespace explicitly:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="myapp:user-detail")

    class Meta:
        model = User
        fields = ('url', 'username')

And it solved my problem.


回答 2

也许有人可以看看这个:http : //www.django-rest-framework.org/api-guide/routers/

如果将命名空间与超链接的序列化程序一起使用,则还需要确保序列化程序上的所有view_name参数都能正确反映命名空间。例如:

urlpatterns = [
    url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    url(r'^api/', include(router.urls, namespace='api')),
]

您需要包含一个参数,例如view_name='api:user-detail'超链接到用户详细信息视图的序列化程序字段的参数。

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="api:user-detail")

class Meta:
    model = User
    fields = ('url', 'username')

Maybe someone can have a look at this : http://www.django-rest-framework.org/api-guide/routers/

If using namespacing with hyperlinked serializers you’ll also need to ensure that any view_name parameters on the serializers correctly reflect the namespace. For example:

urlpatterns = [
    url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    url(r'^api/', include(router.urls, namespace='api')),
]

you’d need to include a parameter such as view_name='api:user-detail' for serializer fields hyperlinked to the user detail view.

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="api:user-detail")

class Meta:
    model = User
    fields = ('url', 'username')

回答 3

导致此错误的另一个令人讨厌的错误是在urls.py中不必要地定义了base_name。例如:

router.register(r'{pathname}', views.{ViewName}ViewSet, base_name='pathname')

这将导致上述错误。在那里获取该base_name并返回到正常工作的API。下面的代码将修复该错误。万岁!

router.register(r'{pathname}', views.{ViewName}ViewSet)

但是,您可能不仅随便添加了base_name,还因为您为View定义了自定义def get_queryset(),所以Django要求您添加base_name。在这种情况下,您需要为相关的序列化程序显式定义“ url”作为HyperlinkedIdentityField。注意,我们在抛出错误的视图的SERIALIZER上定义了此HyperlinkedIdentityField。如果我的错误是“无法使用视图名称“ study-detail”解析超链接关系的URL。您可能无法在API中包含相关模型,或者lookup_field在此字段上配置了错误的属性。” 我可以使用以下代码修复此问题。

我的ModelViewSet(自定义get_queryset是为什么我必须首先将base_name添加到router.register()的原因):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

    '''custom get_queryset'''
    def get_queryset(self):
        queryset = Study.objects.all()
        return queryset

我在urls.py中为此ModelViewSet注册的路由器:

router.register(r'studies', views.StudyViewSet, base_name='studies')

钱在哪里!然后我可以这样解决:

class StudySerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="studies-detail")
    class Meta:
        model = Study
        fields = ('url', 'name', 'active', 'created',
              'time_zone', 'user', 'surveys')

是的 您必须自己明确定义此HyperlinkedIdentityField才能起作用。而且,您需要确保view_nameHyperlinkedIdentityField上的定义与base_nameurls.py中的定义相同,并在其后添加“ -detail”。

Another nasty mistake that causes this error is having the base_name unnecessarily defined in your urls.py. For example:

router.register(r'{pathname}', views.{ViewName}ViewSet, base_name='pathname')

This will cause the error noted above. Get that base_name outta there and get back to a working API. The code below would fix the error. Hooray!

router.register(r'{pathname}', views.{ViewName}ViewSet)

However, you probably didn’t just arbitrarily add the base_name, you might have done it because you defined a custom def get_queryset() for the View and so Django mandates that you add the base_name. In this case you’ll need to explicitly define the ‘url’ as a HyperlinkedIdentityField for the serializer in question. Notice we are defining this HyperlinkedIdentityField ON THE SERIALIZER of the view that is throwing the error. If my error were “Could not resolve URL for hyperlinked relationship using view name “study-detail”. You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.” I could fix this with the following code.

My ModelViewSet (the custom get_queryset is why I had to add the base_name to the router.register() in the first place):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

    '''custom get_queryset'''
    def get_queryset(self):
        queryset = Study.objects.all()
        return queryset

My router registration for this ModelViewSet in urls.py:

router.register(r'studies', views.StudyViewSet, base_name='studies')

AND HERE’S WHERE THE MONEY IS! Then I could solve it like so:

class StudySerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="studies-detail")
    class Meta:
        model = Study
        fields = ('url', 'name', 'active', 'created',
              'time_zone', 'user', 'surveys')

Yep. You have to explicitly define this HyperlinkedIdentityField on itself for it to work. And you need to make sure that the view_name defined on the HyperlinkedIdentityField is the same as you defined on the base_name in urls.py with a ‘-detail’ added after it.


回答 4

该代码也应该起作用。

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')

This code should work, too.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')

回答 5

将命名空间添加到我的网址后,我遇到了此错误

 url('api/v2/', include('api.urls', namespace='v2')),

并将app_name添加到我的urls.py

我通过在项目的settings.py中为其余框架api指定NamespaceVersioning来解决此问题

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}

I ran into this error after adding namespace to my url

 url('api/v2/', include('api.urls', namespace='v2')),

and adding app_name to my urls.py

I resolved this by specifying NamespaceVersioning for my rest framework api in settings.py of my project

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}

回答 6

今天,我遇到了同样的错误,下面的更改可以挽救我。

更改

class BottleSerializer(serializers.HyperlinkedModelSerializer):

至:

 class BottleSerializer(serializers.ModelSerializer):

Today, I got the same error and below changes rescue me.

Change

class BottleSerializer(serializers.HyperlinkedModelSerializer):

to:

 class BottleSerializer(serializers.ModelSerializer):

回答 7

错误相同,但原因不同:

我定义了一个自定义用户模型,没有新的字段:

from django.contrib.auth.models import (AbstractUser)
class CustomUser(AbstractUser):
    """
    custom user, reference below example
    https://github.com/jonathanchu/django-custom-user-example/blob/master/customuser/accounts/models.py

    # original User class has all I need
    # Just add __str__, not rewrite other field
    - id
    - username
    - password
    - email
    - is_active
    - date_joined
    - method, email_user
    """

    def __str__(self):
        return self.username

这是我的视图功能:

from rest_framework import permissions
from rest_framework import viewsets
from .models import (CustomUser)
class UserViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.AllowAny,)
    serializer_class = UserSerializer

    def get_queryset(self):
        queryset = CustomUser.objects.filter(id=self.request.user.id)
        if self.request.user.is_superuser:
            queryset = CustomUser.objects.all()
        return queryset

由于我没有queryset直接输入UserViewSet,因此必须base_name在注册此视图集时进行设置。这是urls.py文件引起的我的错误消息:

from myapp.views import (UserViewSet)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='customuser')  # <--base_name needs to be 'customuser' instead of 'user'

您需要base_name与模型名称相同- customuser

Same Error, but different reason:

I define a custom user model, nothing new field:

from django.contrib.auth.models import (AbstractUser)
class CustomUser(AbstractUser):
    """
    custom user, reference below example
    https://github.com/jonathanchu/django-custom-user-example/blob/master/customuser/accounts/models.py

    # original User class has all I need
    # Just add __str__, not rewrite other field
    - id
    - username
    - password
    - email
    - is_active
    - date_joined
    - method, email_user
    """

    def __str__(self):
        return self.username

This is my view function:

from rest_framework import permissions
from rest_framework import viewsets
from .models import (CustomUser)
class UserViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.AllowAny,)
    serializer_class = UserSerializer

    def get_queryset(self):
        queryset = CustomUser.objects.filter(id=self.request.user.id)
        if self.request.user.is_superuser:
            queryset = CustomUser.objects.all()
        return queryset

Since I didn’t give queryset directly in UserViewSet, I have to set base_name when I register this viewset. This is where my error message caused by urls.py file:

from myapp.views import (UserViewSet)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='customuser')  # <--base_name needs to be 'customuser' instead of 'user'

You need a base_name same as your model name – customuser.


回答 8

如果要扩展GenericViewSetListModelMixin类,并且在列表视图中添加url字段时出现相同的错误,那是因为没有定义详细信息视图。确保您正在扩展RetrieveModelMixin mixin:

class UserViewSet (mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):

If you’re extending the GenericViewSet and ListModelMixin classes, and have the same error when adding the url field in the list view, it’s because you’re not defining the detail view. Be sure you’re extending the RetrieveModelMixin mixin:

class UserViewSet (mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):

回答 9

似乎HyperlinkedModelSerializer不同意拥有一条道路namespace。在我的应用程序中,我做了两个更改。

# rootapp/urls.py
urlpatterns = [
    # path('api/', include('izzi.api.urls', namespace='api'))
    path('api/', include('izzi.api.urls')) # removed namespace
]

在导入的urls文件中

# app/urls.py
app_name = 'api' // removed the app_name

希望这可以帮助。

It appears that HyperlinkedModelSerializer do not agree with having a path namespace. In my application I made two changes.

# rootapp/urls.py
urlpatterns = [
    # path('api/', include('izzi.api.urls', namespace='api'))
    path('api/', include('izzi.api.urls')) # removed namespace
]

In the imported urls file

# app/urls.py
app_name = 'api' // removed the app_name

Hope this helps.


回答 10

在遵循DRF快速入门指南http://www.django-rest-framework.org/tutorial/quickstart/并尝试浏览到/ users时遇到了相同的错误 。在没有问题之前,我已经完成了多次此设置。

我的解决方案不在代码中,而是在替换数据库中。

此安装与之前的安装之间的区别是我创建本地数据库时的区别。

这次我跑了

./manage.py migrate
./manage.py createsuperuser

跑步后立即

virtualenv venv
. venv/bin/activate
pip install django
pip install djangorestframework

而不是指南中列出的确切顺序。

我怀疑数据库中未正确创建某些内容。我不在乎我的开发数据库,​​所以我删除了它并运行了./manage.py migrate再次命令,创建了一个超级用户,浏览到/ users,错误消失了。

我配置DRF和db的操作顺序出现了问题。

如果您正在使用sqlite并能够测试更改为新数据库,那么在剖析所有代码之前,值得尝试一下。

I ran into the same error while I was following the DRF quickstart guide http://www.django-rest-framework.org/tutorial/quickstart/ and then attempting to browse to /users. I’ve done this setup many times before without problems.

My solution was not in the code but in replacing the database.

The difference between this install and the others before was when I created the local database.

This time I ran my

./manage.py migrate
./manage.py createsuperuser

immediately after running

virtualenv venv
. venv/bin/activate
pip install django
pip install djangorestframework

Instead of the exact order listed in the guide.

I suspected something wasn’t properly created in the DB. I didn’t care about my dev db so I deleted it and ran the ./manage.py migrate command once more, created a super user, browsed to /users and the error was gone.

Something was problematic with the order of operations in which I configured DRF and the db.

If you are using sqlite and are able to test changing to a fresh DB then it’s worth an attempt before you go dissecting all of your code.


回答 11

Bottle =序列化器.PrimaryKeyRelatedField(read_only = True)

read_only允许您表示字段,而不必将其链接到模型的另一个视图。

Bottle = serializers.PrimaryKeyRelatedField(read_only=True)

read_only allows you to represent the field without having to link it to another view of the model.


回答 12

当数据库中的段标值为空(等于”)时,我在DRF 3.7.7上收到该错误。

I got that error on DRF 3.7.7 when a slug value was empty (equals to ”) in the database.


回答 13

我遇到了同样的问题,并通过将其generics.RetrieveAPIView作为基类添加到我的视图集来解决了该问题。

I ran into this same issue and resolved it by adding generics.RetrieveAPIView as a base class to my viewset.


回答 14

我在这个错误中停留了将近2个小时:

在/ api_users / users / 1 /上配置不正确。无法使用视图名称“ users-detail”解析超链接关系的URL。您可能没有在API中包含相关模型,或者配置了错误的lookup_field在此字段上属性。

当我终于得到解决方案但不明白为什么时,所以我的代码是:

#models.py
class Users(models.Model):
    id          = models.AutoField(primary_key=True)
    name        = models.CharField(max_length=50, blank=False, null=False)
    email       = models.EmailField(null=False, blank=False) 
    class Meta:
        verbose_name = "Usuario"
        verbose_name_plural = "Usuarios"

    def __str__(self):
        return str(self.name)


#serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Users
        fields = (
            'id',
            'url',
            'name',        
            'email',       
            'description', 
            'active',      
            'age',         
            'some_date',   
            'timestamp',
            )
#views.py
class UserViewSet(viewsets.ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UserSerializer

#urls_api.py
router = routers.DefaultRouter()
router.register(r'users',UserViewSet, base_name='users')

urlpatterns = [ 
        url(r'^', include(router.urls)),
]

但是在我的主要网址中是:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls', namespace='api')),

]

所以最后我解决了擦除命名空间的问题:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls')),

]

我终于解决了我的问题,所以任何人都可以让我知道为什么,最好。

I was stuck in this error for almost 2 hours:

ImproperlyConfigured at /api_users/users/1/ Could not resolve URL for hyperlinked relationship using view name “users-detail”. You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

When I finally get the solution but I don’t understand why, so my code is:

#models.py
class Users(models.Model):
    id          = models.AutoField(primary_key=True)
    name        = models.CharField(max_length=50, blank=False, null=False)
    email       = models.EmailField(null=False, blank=False) 
    class Meta:
        verbose_name = "Usuario"
        verbose_name_plural = "Usuarios"

    def __str__(self):
        return str(self.name)


#serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Users
        fields = (
            'id',
            'url',
            'name',        
            'email',       
            'description', 
            'active',      
            'age',         
            'some_date',   
            'timestamp',
            )
#views.py
class UserViewSet(viewsets.ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UserSerializer

#urls_api.py
router = routers.DefaultRouter()
router.register(r'users',UserViewSet, base_name='users')

urlpatterns = [ 
        url(r'^', include(router.urls)),
]

but in my main URLs, it was:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls', namespace='api')),

]

So to finally I resolve the problem erasing namespace:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls')),

]

And I finally resolve my problem, so any one can let me know why, bests.


回答 15

如果您在序列化程序中省略了字段“ id”和“ url”,则不会有任何问题。无论如何,您都可以使用json对象中返回的ID来访问帖子,这使实现前端变得更加容易。

If you omit the fields ‘id’ and ‘url’ from your serializer you won’t have any problem. You can access to the posts by using the id that is returned in the json object anyways, which it makes it even easier to implement your frontend.


回答 16

我有同样的问题,我想你应该检查一下

get_absolute_url

对象模型的方法输入值(** kwargs)标题。并在lookup_field中使用确切的字段名称

I had the same problem , I think you should check your

get_absolute_url

object model’s method input value (**kwargs) title. and use exact field name in lookup_field


您试图将非空字段’new_field’添加到用户配置文件中,而没有默认设置

问题:您试图将非空字段’new_field’添加到用户配置文件中,而没有默认设置

我知道从Django 1.7开始,我不需要使用South或任何其他迁移系统,因此我只是使用简单的命令 python manage.py makemigrations

但是,我得到的只是这个错误:

You are trying to add a non-nullable field 'new_field' to userprofile without a default;
we can't do that (the database needs something to populate existing rows).

这是models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    new_field = models.CharField(max_length=140)

有哪些选择?

I know that from Django 1.7 I don’t need to use South or any other migration system, so I am just using simple command python manage.py makemigrations

However, all I get is this error:

You are trying to add a non-nullable field 'new_field' to userprofile without a default;
we can't do that (the database needs something to populate existing rows).

Here is models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    new_field = models.CharField(max_length=140)

What are options?


回答 0

您需要提供一个默认值:

new_field = models.CharField(max_length=140, default='SOME STRING')

You need to provide a default value:

new_field = models.CharField(max_length=140, default='SOME STRING')

回答 1

如果您处于早期开发周期,并且不关心当前的数据库数据,则可以将其删除然后迁移。但是首先,您需要清除迁移目录并从表中删除其行(django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate

If you are in early development cycle and don’t care about your current database data you can just remove it and then migrate. But first you need to clean migrations dir and remove its rows from table (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate

回答 2

一种选择是声明“ new_field”的默认值:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE')

另一个选择是将“ new_field”声明为可为空的字段:

new_field = models.CharField(max_length=140, null=True)

如果您决定接受“ new_field”作为可为空的字段,则可能要接受“无输入”作为“ new_field”的有效输入。然后,您还必须添加该blank=True语句:

new_field = models.CharField(max_length=140, blank=True, null=True)

即使使用null=True和/或,blank=True也可以根据需要添加默认值:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)

One option is to declare a default value for ‘new_field’:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE')

another option is to declare ‘new_field’ as a nullable field:

new_field = models.CharField(max_length=140, null=True)

If you decide to accept ‘new_field’ as a nullable field you may want to accept ‘no input’ as valid input for ‘new_field’. Then you have to add the blank=True statement as well:

new_field = models.CharField(max_length=140, blank=True, null=True)

Even with null=True and/or blank=True you can add a default value if necessary:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)

回答 3

如果您处于开发周期的初期,可以尝试以下方法-

删除/注释该模型及其所有用法。应用迁移。这将删除该模型,然后再次添加模型,运行迁移,您将获得一个干净的模型,并添加了新字段。

If you are early into the development cycle you can try this –

Remove/comment that model and all its usages. Apply migrations. That would delete that model and then add the model again, run migrations and you have a clean model with the new field added.


回答 4

如果“网站”可以为空,new_field则还应该设置为空。

现在,如果您要在保存上添加逻辑,如果if new_field为空,则可以从“网站”获取值,您需要做的就是覆盖保存函数,Model如下所示:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True, default='DEFAULT VALUE')
    new_field = models.CharField(max_length=140, blank=True, default='DEFAULT VALUE')

    def save(self, *args, **kwargs):
        if not self.new_field:
            # Setting the value of new_field with website's value
            self.new_field = self.website

        # Saving the object with the default save() function
        super(UserProfile, self).save(*args, **kwargs)

If “website” can be empty than new_field should also be set to be empty.

Now if you want to add logic on save where if new_field is empty to grab the value from “website” all you need to do is override the save function for your Model like this:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True, default='DEFAULT VALUE')
    new_field = models.CharField(max_length=140, blank=True, default='DEFAULT VALUE')

    def save(self, *args, **kwargs):
        if not self.new_field:
            # Setting the value of new_field with website's value
            self.new_field = self.website

        # Saving the object with the default save() function
        super(UserProfile, self).save(*args, **kwargs)

回答 5

如果有人设置ForeignKey,则可以只允许设置可为空的字段,而无需设置默认值:

new_field = models.ForeignKey(model, null=True)

如果您已经在数据库中存储了数据,则还可以设置一个默认值:

new_field = models.ForeignKey(model, default=<existing model id here>)

In case anyone is setting a ForeignKey, you can just allow nullable fields without setting a default:

new_field = models.ForeignKey(model, null=True)

If you already have data stored within the database, you can also set a default value:

new_field = models.ForeignKey(model, default=<existing model id here>)

回答 6

您不能添加对已经有数据的表的引用。
更改:

user = models.OneToOneField(User)

至:

user = models.OneToOneField(User, default = "")

做:

python manage.py makemigrations
python manage.py migrate

再次更改:

user = models.OneToOneField(User)

再次迁移:

python manage.py makemigrations
python manage.py migrate

You can’t add reference to table that have already data inside.
Change:

user = models.OneToOneField(User)

to:

user = models.OneToOneField(User, default = "")

do:

python manage.py makemigrations
python manage.py migrate

change again:

user = models.OneToOneField(User)

do migration again:

python manage.py makemigrations
python manage.py migrate

回答 7

在new_file中,添加boolean属性null。

new_field = models.CharField(max_length=140, null=True)

在运行./manage.py syncdb刷新数据库后。最后你运行./manage.py makemigrations./manage.py migrate

In new_file add the boolean property null.

new_field = models.CharField(max_length=140, null=True)

after you run a ./manage.py syncdb for refresh the DB. and finally you run ./manage.py makemigrations and ./manage.py migrate


回答 8

您可以从以下页面使用Django Doc中的方法https://docs.djangoproject.com/en/1.8/ref/models/fields/#default

创建默认值并使用它

def contact_default():
   return {"email": "to1@example.com"}

contact_info = JSONField("ContactInfo", default=contact_default)

You can use method from Django Doc from this page https://docs.djangoproject.com/en/1.8/ref/models/fields/#default

Create default and use it

def contact_default():
   return {"email": "to1@example.com"}

contact_info = JSONField("ContactInfo", default=contact_default)

回答 9

表中是否已经有数据库条目UserProfile?如果是这样,那么当您添加新列时,数据库就不会知道将其设置为的原因NULL。因此,它询问您要将列中的那些字段设置为什么new_fields。我必须删除该表中的所有行以解决问题。

(我知道这是在一段时间前回答的,但是我只是遇到了这个问题,这是我的解决方案。希望它将对任何看到此问题的新人有所帮助)

Do you already have database entries in the table UserProfile? If so, when you add new columns the DB doesn’t know what to set it to because it can’t be NULL. Therefore it asks you what you want to set those fields in the column new_fields to. I had to delete all the rows from this table to solve the problem.

(I know this was answered some time ago, but I just ran into this problem and this was my solution. Hopefully it will help anyone new that sees this)


回答 10

老实说,我认为最好的解决方法是使用所需的所有字段创建另一个模型,并命名稍有不同。运行迁移。删除未使用的模型,然后再次运行迁移。瞧

I honestly fount the best way to get around this was to just create another model with all the fields that you require and named slightly different. Run migrations. Delete unused model and run migrations again. Voila.


回答 11

如果可以截断相关模型的表,可以None在提示中指定一次性的默认值。迁移将是多余的,default=None而您的代码没有默认值。可以很好地应用它,因为表中不再有需要默认的数据。

If you are fine with truncating the table of the model in question, you can specify a one-off default value of None in the prompt. The migration will have superfluous default=None while your code has no default. It can be applied just fine because there’s no data in the table anymore which would require a default.


回答 12

我还处于开发周期的初期,所以这可能并不适合所有人(但我不明白为什么不行)。

我添加blank=True, null=True到出现错误的列中。然后我运行了python manage.py makemigrations命令。

在运行此命令后(以及在运行之前python manage.py migrate),我立即blank=True, null=True从所有列中删除了。然后我又跑python manage.py makemigrations了。我可以选择自己更改列。

然后我跑了python manage.py migrate,一切顺利!

I was early in my development cycle, so this may not work for everyone (but I don’t see why it wouldn’t).

I added blank=True, null=True to the columns where I was getting the error. Then I ran the python manage.py makemigrations command.

Immediately after running this command (and before running python manage.py migrate), I removed the blank=True, null=True from all the columns. Then I ran python manage.py makemigrations again. I was given an option to just change the columns myself, which I selected.

Then I ran python manage.py migrate and everything worked well!


回答 13

Django实际说的是:

Userprofile表中有数据,并且可能new_field有空值,但我不知道,所以您确定要将属性标记为不可空值,因为如果这样做,如果存在带有NULL的值,则可能会出错

如果您确定userprofile表中的所有值都不为NULL-请放心使用,并忽略该警告。

在这种情况下,最佳实践是创建RunPython迁移以处理空值,如选项2中所述

2)暂时忽略,让我自己处理带有NULL的现有行(例如,因为您添加了RunPython或RunSQL操作来处理以前的数据迁移中的NULL值)

在RunPython迁移中,您必须找到所有UserProfile具有空new_field值的实例,然后在其中放置正确的值(或Django要求您在模型中设置的默认值)。您将获得如下内容:

# please keep in mind that new_value can be an empty string. You decide whether it is a correct value.
for profile in UserProfile.objects.filter(new_value__isnull=True).iterator():
    profile.new_value = calculate_value(profile)
    profile.save() # better to use batch save

玩得开心!

What Django actually says is:

Userprofile table has data in it and there might be new_field values which are null, but I do not know, so are you sure you want to mark property as non nullable, because if you do you might get an error if there are values with NULL

If you are sure that none of values in the userprofile table are NULL – fell free and ignore the warning.

The best practice in such cases would be to create a RunPython migration to handle empty values as it states in option 2

2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)

In RunPython migration you have to find all UserProfile instances with empty new_field value and put a correct value there (or a default value as Django asks you to set in the model). You will get something like this:

# please keep in mind that new_value can be an empty string. You decide whether it is a correct value.
for profile in UserProfile.objects.filter(new_value__isnull=True).iterator():
    profile.new_value = calculate_value(profile)
    profile.save() # better to use batch save

Have fun!


回答 14

在models.py中

class UserProfile(models.Model): user = models.OneToOneField(User) website = models.URLField(blank=True) new_field = models.CharField(max_length=140, default="some_value")

您需要添加一些默认值。

In models.py

class UserProfile(models.Model): user = models.OneToOneField(User) website = models.URLField(blank=True) new_field = models.CharField(max_length=140, default="some_value")

You need to add some values as default.


回答 15

如果使用SSH,它有2个选项,请选择数字1,然后输入“无”。只是……暂时。

If the SSH it gives you 2 options, choose number 1, and put “None”. Just that…for the moment.


Django查询中的“ LIKE”等效SQL

问题:Django查询中的“ LIKE”等效SQL

django中的此SQL语句等效于什么?

SELECT * FROM table_name WHERE string LIKE pattern;

如何在Django中实现呢?我试过了

result = table.objects.filter( pattern in string )

但这没有用。我该如何实施?

What is the equivalent of this SQL statement in django?

SELECT * FROM table_name WHERE string LIKE pattern;

How do I implement this in django? I tried

result = table.objects.filter( pattern in string )

But that did not work. How do i implement this?


回答 0

使用__contains__icontains(不区分大小写):

result = table.objects.filter(string__contains='pattern')

SQL等效为

SELECT ... WHERE string LIKE '%pattern%';

Use __contains or __icontains (case-insensitive):

result = table.objects.filter(string__contains='pattern')

The SQL equivalent is

SELECT ... WHERE string LIKE '%pattern%';

回答 1

由falsetru提及的包含和icontains使查询类似 SELECT ... WHERE headline LIKE '%pattern%

与它们一起,您可能需要具有类似行为的这些: startswithistartswithendswithiendswith

制造

SELECT ... WHERE headline LIKE 'pattern%

要么

SELECT ... WHERE headline LIKE '%pattern

contains and icontains mentioned by falsetru make queries like SELECT ... WHERE headline LIKE '%pattern%

Along with them, you might need these ones with similar behavior: startswith, istartswith, endswith, iendswith

making

SELECT ... WHERE headline LIKE 'pattern%

or

SELECT ... WHERE headline LIKE '%pattern


回答 2

result = table.objects.filter(string__icontains='pattern')

不区分大小写的字段中搜索字符串。

result = table.objects.filter(string__icontains='pattern')

Case insensitive search for string in a field.


回答 3

为了像sql LIKE’%pattern%’语句中那样保留单词的顺序,我使用了iregex,例如:

qs = table.objects.filter(string__iregex=pattern.replace(' ', '.*'))

字符串方法是不可变的,因此您的模式变量不会更改,并且使用。*时,您会寻找0个或多个出现的任何字符,但要换行。

通过使用以下代码遍历模式词:

qs = table.objects
for word in pattern.split(' '):
    qs = qs.filter(string__icontains=word)

对于某些可能有用的人,将不会保留模式中单词的顺序,但是在尝试模仿sql like语句的情况下,我将使用第一个选项。

In order to preserve the order of the words as in the sql LIKE ‘%pattern%’ statement I use iregex, for example:

qs = table.objects.filter(string__iregex=pattern.replace(' ', '.*'))

string methods are immutable so your pattern variable will not change and with .* you’ll be looking for 0 or more occurrences of any character but break lines.

By using the following to iterate over the pattern words:

qs = table.objects
for word in pattern.split(' '):
    qs = qs.filter(string__icontains=word)

the order of the words in your pattern will not be preserved, for some people that could work but in the case of trying to mimic the sql like statement I’ll use the first option.


回答 4

这可以通过Django的自定义查询来完成。我已经将查询转换为Django式lookup应用程序。安装后__like,使用%和查找_将启用通配符。

该应用程序中所有必需的代码是:

from django.db.models import Lookup
from django.db.models.fields import Field


@Field.register_lookup
class Like(Lookup):
    lookup_name = 'like'

    def as_sql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return '%s LIKE %s' % (lhs, rhs), params

This can be done with Django’s custom lookups. I have made the lookup into a Django-like-lookup application. After installing it the __like lookup with the % and _ wildcards will be enabled.

All the necessary code in the application is:

from django.db.models import Lookup
from django.db.models.fields import Field


@Field.register_lookup
class Like(Lookup):
    lookup_name = 'like'

    def as_sql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return '%s LIKE %s' % (lhs, rhs), params

如何在Django中设置PostgreSQL数据库

问题:如何在Django中设置PostgreSQL数据库

我是Python和Django的新手。

我正在使用PostgreSQL数据库引擎后端配置Django项目,但是每个数据库操作都出现错误。例如,当我跑步时manage.py syncdb,我得到:

C:\xampp\htdocs\djangodir>python manage.py syncdb
Traceback (most recent call last):
  File "manage.py", line 11, in <module>
    execute_manager(settings)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
438, in execute_manager
    utility.execute()
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
261, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
67, in load_command_class
    module = import_module('%s.management.commands.%s' % (app_name, name))
  File "C:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in im
port_module
    __import__(name)
  File "C:\Python27\lib\site-packages\django\core\management\commands\syncdb.py"
, line 7, in <module>
    from django.core.management.sql import custom_sql_for_model, emit_post_sync_
signal
  File "C:\Python27\lib\site-packages\django\core\management\sql.py", line 6, in
 <module>
    from django.db import models
  File "C:\Python27\lib\site-packages\django\db\__init__.py", line 77, in <modul
e>
    connection = connections[DEFAULT_DB_ALIAS]
  File "C:\Python27\lib\site-packages\django\db\utils.py", line 92, in __getitem
__
    backend = load_backend(db['ENGINE'])
  File "C:\Python27\lib\site-packages\django\db\utils.py", line 33, in load_back
end
    return import_module('.base', backend_name)
  File "C:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in im
port_module
    __import__(name)
  File "C:\Python27\lib\site-packages\django\db\backends\postgresql\base.py", li
ne 23, in <module>
    raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
django.core.exceptions.ImproperlyConfigured: Error loading psycopg module: No mo
dule named psycopg

有人可以告诉我发生了什么吗?

I’m new to Python and Django.

I’m configuring a Django project using a PostgreSQL database engine backend, But I’m getting errors on each database operation. For example when I run manage.py syncdb, I’m getting:

C:\xampp\htdocs\djangodir>python manage.py syncdb
Traceback (most recent call last):
  File "manage.py", line 11, in <module>
    execute_manager(settings)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
438, in execute_manager
    utility.execute()
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
261, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line
67, in load_command_class
    module = import_module('%s.management.commands.%s' % (app_name, name))
  File "C:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in im
port_module
    __import__(name)
  File "C:\Python27\lib\site-packages\django\core\management\commands\syncdb.py"
, line 7, in <module>
    from django.core.management.sql import custom_sql_for_model, emit_post_sync_
signal
  File "C:\Python27\lib\site-packages\django\core\management\sql.py", line 6, in
 <module>
    from django.db import models
  File "C:\Python27\lib\site-packages\django\db\__init__.py", line 77, in <modul
e>
    connection = connections[DEFAULT_DB_ALIAS]
  File "C:\Python27\lib\site-packages\django\db\utils.py", line 92, in __getitem
__
    backend = load_backend(db['ENGINE'])
  File "C:\Python27\lib\site-packages\django\db\utils.py", line 33, in load_back
end
    return import_module('.base', backend_name)
  File "C:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in im
port_module
    __import__(name)
  File "C:\Python27\lib\site-packages\django\db\backends\postgresql\base.py", li
ne 23, in <module>
    raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
django.core.exceptions.ImproperlyConfigured: Error loading psycopg module: No mo
dule named psycopg

Can someone give me a clue on what is going on?


回答 0

您需要安装psycopg2Python库。

安装


下载http://initd.org/psycopg/,然后将其安装在Python PATH下

下载后,轻松解压缩tarball并:

$ python setup.py install

或者,如果愿意,可以通过easy_installpip进行安装。

我更喜欢无缘无故地使用pip而不是easy_install。

  • $ easy_install psycopg2
  • $ pip install psycopg2

组态


设置 .py中

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'db_name',                      
        'USER': 'db_user',
        'PASSWORD': 'db_user_password',
        'HOST': '',
        'PORT': 'db_port_number',
    }
}

-其他安装说明可在下载页面安装页面找到

You need to install psycopg2 Python library.

Installation


Download http://initd.org/psycopg/, then install it under Python PATH

After downloading, easily extract the tarball and:

$ python setup.py install

Or if you wish, install it by either easy_install or pip.

(I prefer to use pip over easy_install for no reason.)

  • $ easy_install psycopg2
  • $ pip install psycopg2

Configuration


in settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'db_name',                      
        'USER': 'db_user',
        'PASSWORD': 'db_user_password',
        'HOST': '',
        'PORT': 'db_port_number',
    }
}

– Other installation instructions can be found at download page and install page.


回答 1

另外,请确保已安装PostgreSQL开发包。在Ubuntu上,您需要执行以下操作:

$ sudo apt-get install libpq-dev

Also make sure you have the PostgreSQL development package installed. On Ubuntu you need to do something like this:

$ sudo apt-get install libpq-dev

回答 2

我使用的分步指南:

 - sudo apt-get install python-dev
 - sudo apt-get install postgresql-server-dev-9.1
 - sudo apt-get install python-psycopg2 - Or sudo pip install psycopg2

您可能需要安装图形工具来管理数据库,为此,您可以执行以下操作:

sudo apt-get install postgresql pgadmin3 

之后,您必须更改Postgre用户密码,然后执行以下操作:

 - sudo su
 - su postgres -c psql postgres
 - ALTER USER postgres WITH PASSWORD 'YourPassWordHere';
 - \q

在您的settings.py文件中,您可以执行以下操作:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '',
        'PORT': '',
    }
}

额外:

如果要使用命令行创建数据库,则可以执行以下操作:

- sudo su
- su postgres -c psql postgres
- CREATE DATABASE dbname;
- CREATE USER djangouser WITH ENCRYPTED PASSWORD 'myPasswordHere';
- GRANT ALL PRIVILEGES ON DATABASE dbname TO djangouser;

在您的settings.py文件中,您可以执行以下操作:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'djangouser',
        'PASSWORD': 'myPasswordHere',
        'HOST': '',
        'PORT': '',
    }
}

Step by step that I use:

 - sudo apt-get install python-dev
 - sudo apt-get install postgresql-server-dev-9.1
 - sudo apt-get install python-psycopg2 - Or sudo pip install psycopg2

You may want to install a graphic tool to manage your databases, for that you can do:

sudo apt-get install postgresql pgadmin3 

After, you must change Postgre user password, then do:

 - sudo su
 - su postgres -c psql postgres
 - ALTER USER postgres WITH PASSWORD 'YourPassWordHere';
 - \q

On your settings.py file you do:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '',
        'PORT': '',
    }
}

Extra:

If you want to create the db using the command line you can just do:

- sudo su
- su postgres -c psql postgres
- CREATE DATABASE dbname;
- CREATE USER djangouser WITH ENCRYPTED PASSWORD 'myPasswordHere';
- GRANT ALL PRIVILEGES ON DATABASE dbname TO djangouser;

On your settings.py file you do:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'djangouser',
        'PASSWORD': 'myPasswordHere',
        'HOST': '',
        'PORT': '',
    }
}

回答 3

这似乎有点冗长,但是对我来说没有任何错误。

首先,从Ubuntu软件中心安装phppgadmin。

然后在终端中运行这些步骤。

sudo apt-get install libpq-dev python-dev
pip install psycopg2
sudo apt-get install postgresql postgresql-contrib phppgadmin

启动apache服务器

sudo service apache2 start

现在在终端中也运行此命令以编辑apache文件。

sudo gedit /etc/apache2/apache2.conf

将以下行添加到打开的文件中:

Include /etc/apache2/conf.d/phppgadmin

现在重新加载apache。使用终端。

sudo /etc/init.d/apache2 reload

现在,您将不得不创建一个新的数据库。以“ postgres”用户身份登录。在终端继续。

sudo su - postgres

如果您在使用密码“ postgres”时遇到麻烦,可以在此处使用答案https://stackoverflow.com/a/12721020/1990793进行更改,然后继续执行步骤。

现在创建一个数据库

createdb <db_name>

现在,创建一个新用户以稍后登录到phppgadmin,并提供一个新密码。

createuser -P <new_user>

现在您的postgressql已设置完毕,您可以转到:

http://localhost/phppgadmin/

并使用您创建的新用户登录,以查看数据库。

This may seem a bit lengthy, but it worked for me without any error.

At first, Install phppgadmin from Ubuntu Software Center.

Then run these steps in terminal.

sudo apt-get install libpq-dev python-dev
pip install psycopg2
sudo apt-get install postgresql postgresql-contrib phppgadmin

Start the apache server

sudo service apache2 start

Now run this too in terminal, to edit the apache file.

sudo gedit /etc/apache2/apache2.conf

Add the following line to the opened file:

Include /etc/apache2/conf.d/phppgadmin

Now reload apache. Use terminal.

sudo /etc/init.d/apache2 reload

Now you will have to create a new database. Login as ‘postgres’ user. Continue in terminal.

sudo su - postgres

In case you have trouble with the password of ‘postgres’, you can change it using the answer here https://stackoverflow.com/a/12721020/1990793 and continue with the steps.

Now create a database

createdb <db_name>

Now create a new user to login to phppgadmin later, providing a new password.

createuser -P <new_user>

Now your postgressql has been setup, and you can go to:

http://localhost/phppgadmin/

and login using the new user you’ve created, in order to view the database.


回答 4

您可以使用以下命令安装“ psycopg”:

# sudo easy_install psycopg2

另外,您可以使用pip:

# pip install psycopg2

easy_install和pip包含在ActivePython中,或从各个 项目站点手动安装。

或者,只需获取预构建的Windows安装程序

You can install “psycopg” with the following command:

# sudo easy_install psycopg2

Alternatively, you can use pip :

# pip install psycopg2

easy_install and pip are included with ActivePython, or manually installed from the respective project sites.

Or, simply get the pre-built Windows installer.


回答 5

眼前的问题似乎是您缺少了psycopg模块。

The immediate problem seems to be that you’re missing the psycopg module.


回答 6

如果您使用的是Fedora 20,Django 1.6.5,postgresql 9.3。*,并且需要psycopg2模块,请执行以下操作:

yum install postgresql-devel
easy_install psycopg2

如果您像我一样,可能会找不到有据可查的libpq-dev rpm。

If you are using Fedora 20, Django 1.6.5, postgresql 9.3.* and you need the psycopg2 module, do this:

yum install postgresql-devel
easy_install psycopg2

If you are like me, you may have trouble finding the well documented libpq-dev rpm… The above worked for me just now.


回答 7

我在Mac上遇到过同样的问题。

解决方案是仅使用PIP来安装所有东西,并触摸一些东西。

首先从以下 网址安装PIP:https //pip.pypa.io/en/latest/

然后,您要确定pg_config的路径是否在PATH中(回显$ PATH),如果没有,则可以编辑bash_profile:

vi /Users/<user>/.bash_profile

并添加以下行:

export PATH=$PATH:/path/to/pg_config/bin

如果您不知道pg_config在哪里,则可以使用“ locate”工具,但是请确保您的locate.db是最新的(我使用的是旧的locate.db,并且使用的路径不存在)。

sudo /usr/libexec/locate.updatedb
locate pg_config

然后安装Django(如果需要)和psycopg2。

sudo pip install Django
sudo pip install psycopg2

然后在settings.py(localhost:defaultport)中

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '',
        'PORT': '',
    }
}

问候!

I was having the same Issue on Mac.

The solution was to use only PIP to install everything, and touch some things.

First install PIP from: https://pip.pypa.io/en/latest/

Then you want to make sure if path to pg_config is in your PATH (echo $PATH), if not you can edit your bash_profile:

vi /Users/<user>/.bash_profile

and add this line:

export PATH=$PATH:/path/to/pg_config/bin

If you don’t know where pg_config is you can use the “locate” tool, but be sure your locate.db is up to date (i was using an old locate.db and using paths that does not exists).

sudo /usr/libexec/locate.updatedb
locate pg_config

Then install Django (if needed) and psycopg2.

sudo pip install Django
sudo pip install psycopg2

And then in settings.py (localhost:defaultport)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '',
        'PORT': '',
    }
}

Greets!


回答 8

$ sudo apt-get install libpq-dev

年,这解决了我的问题。执行此操作后,请执行以下操作:pip install psycopg2

$ sudo apt-get install libpq-dev

Year, this solve my problem. After execute this, do: pip install psycopg2


回答 9

请注意,psycopg2通过pip或setup.py进行安装需要具有Visual Studio 2008(更确切地说是可执行文件vcvarsall.bat)。如果您没有管理员权限来安装它或在Windows上设置适当的PATH变量,则可以从此处下载已编译的库。

Please note that installation of psycopg2 via pip or setup.py requires to have Visual Studio 2008 (more precisely executable file vcvarsall.bat). If you don’t have admin rights to install it or set the appropriate PATH variable on Windows, you can download already compiled library from here.


回答 10

这是PostgreSQL在ubuntu服务器中设置的非常好的逐步过程之一。我已经尝试了它,Ubuntu 16.04并且可以正常工作。

https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-django-application-on-ubuntu-14-04

This is one of the very good and step by step process to set up PostgreSQL in ubuntu server. I have tried it with Ubuntu 16.04 and its working.

https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-django-application-on-ubuntu-14-04


在Django Admin中调整字段大小

问题:在Django Admin中调整字段大小

Django倾向于在管理员上添加或编辑条目时填充水平空间,但是在某些情况下,这是真正的空间浪费,例如,编辑日期字段(8个字符宽)或CharField(也可以是6或8)字符宽,然后编辑框最多为15或20个字符。

如何告诉管理员文本框的宽度或TextField编辑框的高度?

Django tends to fill up horizontal space when adding or editing entries on the admin, but, in some cases, is a real waste of space, when, i.e., editing a date field, 8 characters wide, or a CharField, also 6 or 8 chars wide, and then the edit box goes up to 15 or 20 chars.

How can I tell the admin how wide a textbox should be, or the height of a TextField edit box?


回答 0

您应该使用ModelAdmin.formfield_overrides

这很容易- admin.py定义:

from django.forms import TextInput, Textarea
from django.db import models

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {'widget': TextInput(attrs={'size':'20'})},
        models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':40})},
    }

admin.site.register(YourModel, YourModelAdmin)

You should use ModelAdmin.formfield_overrides.

It is quite easy – in admin.py, define:

from django.forms import TextInput, Textarea
from django.db import models

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {'widget': TextInput(attrs={'size':'20'})},
        models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':40})},
    }

admin.site.register(YourModel, YourModelAdmin)

回答 1

您可以使用其“ attrs”属性在窗口小部件上设置任意HTML属性。

您可以在Django管理员中使用formfield_for_dbfield进行此操作:

class MyModelAdmin(admin.ModelAdmin):
  def formfield_for_dbfield(self, db_field, **kwargs):
    field = super(ContentAdmin, self).formfield_for_dbfield(db_field, **kwargs)
    if db_field.name == 'somefield':
      field.widget.attrs['class'] = 'someclass ' + field.widget.attrs.get('class', '')
    return field

或带有自定义Widget子类和formfield_overrides字典

class DifferentlySizedTextarea(forms.Textarea):
  def __init__(self, *args, **kwargs):
    attrs = kwargs.setdefault('attrs', {})
    attrs.setdefault('cols', 80)
    attrs.setdefault('rows', 5)
    super(DifferentlySizedTextarea, self).__init__(*args, **kwargs)

class MyModelAdmin(admin.ModelAdmin):
  formfield_overrides = { models.TextField: {'widget': DifferentlySizedTextarea}}

You can set arbitrary HTML attributes on a widget using its “attrs” property.

You can do this in the Django admin using formfield_for_dbfield:

class MyModelAdmin(admin.ModelAdmin):
  def formfield_for_dbfield(self, db_field, **kwargs):
    field = super(ContentAdmin, self).formfield_for_dbfield(db_field, **kwargs)
    if db_field.name == 'somefield':
      field.widget.attrs['class'] = 'someclass ' + field.widget.attrs.get('class', '')
    return field

or with a custom Widget subclass and the formfield_overrides dictionary:

class DifferentlySizedTextarea(forms.Textarea):
  def __init__(self, *args, **kwargs):
    attrs = kwargs.setdefault('attrs', {})
    attrs.setdefault('cols', 80)
    attrs.setdefault('rows', 5)
    super(DifferentlySizedTextarea, self).__init__(*args, **kwargs)

class MyModelAdmin(admin.ModelAdmin):
  formfield_overrides = { models.TextField: {'widget': DifferentlySizedTextarea}}

回答 2

更改特定字段的宽度。

通过ModelAdmin.get_form制成

class YourModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(YourModelAdmin, self).get_form(request, obj, **kwargs)
        form.base_fields['myfield'].widget.attrs['style'] = 'width: 45em;'
        return form

To change the width for a specific field.

Made via ModelAdmin.get_form:

class YourModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(YourModelAdmin, self).get_form(request, obj, **kwargs)
        form.base_fields['myfield'].widget.attrs['style'] = 'width: 45em;'
        return form

回答 3

一种快速而肮脏的选择是简单地为所讨论的模型提供自定义模板。

如果您创建一个名为的模板,admin/<app label>/<class name>/change_form.html则管理员将使用该模板代替默认模板。也就是说,如果您在名为Person的应用中有一个名为的模型people,则可以创建一个名为的模板admin/people/person/change_form.html

所有管理模板都有一个extrahead块,您可以覆盖该块以将内容放入中<head>,而难题的最后一部分是每个字段的HTML ID为id_<field-name>

因此,您可以在模板中添加以下内容:

{% extends "admin/change_form.html" %}

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}

A quick and dirty option is to simply provide a custom template for the model in question.

If you create a template named admin/<app label>/<class name>/change_form.html then the admin will use that template instead of the default. That is, if you’ve got a model named Person in an app named people, you’d create a template named admin/people/person/change_form.html.

All the admin templates have an extrahead block you can override to place stuff in the <head>, and the final piece of the puzzle is the fact that every field has an HTML id of id_<field-name>.

So, you could put something like the following in your template:

{% extends "admin/change_form.html" %}

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}

回答 4

如果要更改每个字段实例的属性,可以将“ attrs”属性直接添加到表单条目中。

例如:

class BlogPostForm(forms.ModelForm):
    title = forms.CharField(label='Title:', max_length=128)
    body = forms.CharField(label='Post:', max_length=2000, 
        widget=forms.Textarea(attrs={'rows':'5', 'cols': '5'}))

    class Meta:
        model = BlogPost
        fields = ('title', 'body')

“ attrs”属性基本上沿HTML标记传递,它将调整表单字段。每个条目都是您要覆盖的属性的元组,以及您要覆盖其的值。您可以输入任意多个属性,只要用逗号分隔每个元组即可。

If you want to change the attributes on a per-field instance, you can add the “attrs” property directly in to your form entries.

for example:

class BlogPostForm(forms.ModelForm):
    title = forms.CharField(label='Title:', max_length=128)
    body = forms.CharField(label='Post:', max_length=2000, 
        widget=forms.Textarea(attrs={'rows':'5', 'cols': '5'}))

    class Meta:
        model = BlogPost
        fields = ('title', 'body')

The “attrs” property basically passes along the HTML markup that will adjust the form field. Each entry is a tuple of the attribute you would like to override and the value you would like to override it with. You can enter as many attributes as you like as long as you separate each tuple with a comma.


回答 5

我发现最好的方法是这样的:

class NotificationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs): 
        super(NotificationForm, self).__init__(*args, **kwargs)
        self.fields['content'].widget.attrs['cols'] = 80
        self.fields['content'].widget.attrs['rows'] = 15
        self.fields['title'].widget.attrs['size'] = 50
    class Meta:
        model = Notification

对于ModelForm而言,它比使用不同的小部件覆盖字段要好得多,因为它可以保留namehelp_text属性以及模型字段的默认值,因此您不必将它们复制到表单中。

The best way I found is something like this:

class NotificationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs): 
        super(NotificationForm, self).__init__(*args, **kwargs)
        self.fields['content'].widget.attrs['cols'] = 80
        self.fields['content'].widget.attrs['rows'] = 15
        self.fields['title'].widget.attrs['size'] = 50
    class Meta:
        model = Notification

Its much better for ModelForm than overriding fields with different widgets, as it preserves name and help_text attributes and also default values of model fields, so you don’t have to copy them to your form.


回答 6

我在TextField中遇到了类似的问题。我正在使用Django 1.0.2,并且想要在关联的textarea中更改“行”的默认值。该版本不存在formfield_overrides。重写formfield_for_dbfield可以,但是我必须对每个ModelAdmin子类都这样做,否则会导致递归错误。最终,我发现将以下代码添加到models.py可以正常工作:

from django.forms import Textarea

class MyTextField(models.TextField):
#A more reasonably sized textarea                                                                                                            
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": Textarea(attrs={'rows':2, 'cols':80})}
         )
         return super(MyTextField, self).formfield(**kwargs)

然后在定义模型时使用MyTextField而不是TextField。我从这个答案中将其改编为类似的问题。

I had a similar problem with TextField. I’m using Django 1.0.2 and wanted to change the default value for ‘rows’ in the associated textarea. formfield_overrides doesn’t exist in this version. Overriding formfield_for_dbfield worked but I had to do it for each of my ModelAdmin subclasses or it would result in a recursion error. Eventually, I found that adding the code below to models.py works:

from django.forms import Textarea

class MyTextField(models.TextField):
#A more reasonably sized textarea                                                                                                            
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": Textarea(attrs={'rows':2, 'cols':80})}
         )
         return super(MyTextField, self).formfield(**kwargs)

Then use MyTextField instead of TextField when defining your models. I adapted it from this answer to a similar question.


回答 7

Django FAQ对此进行了很好的描述:

问:如何更改模型中字段上小部件的属性?

答:覆盖ModelAdmin / StackedInline / TabularInline类中的formfield_for_dbfield

class MyOtherModelInline(admin.StackedInline):
    model = MyOtherModel
    extra = 1

    def formfield_for_dbfield(self, db_field, **kwargs):
        # This method will turn all TextFields into giant TextFields
        if isinstance(db_field, models.TextField):
            return forms.CharField(widget=forms.Textarea(attrs={'cols': 130, 'rows':30, 'class': 'docx'}))
        return super(MyOtherModelInline, self).formfield_for_dbfield(db_field, **kwargs)

It’s well described in Django FAQ:

Q: How do I change the attributes for a widget on a field in my model?

A: Override the formfield_for_dbfield in the ModelAdmin/StackedInline/TabularInline class

class MyOtherModelInline(admin.StackedInline):
    model = MyOtherModel
    extra = 1

    def formfield_for_dbfield(self, db_field, **kwargs):
        # This method will turn all TextFields into giant TextFields
        if isinstance(db_field, models.TextField):
            return forms.CharField(widget=forms.Textarea(attrs={'cols': 130, 'rows':30, 'class': 'docx'}))
        return super(MyOtherModelInline, self).formfield_for_dbfield(db_field, **kwargs)

回答 8

您总是可以在自定义样式表中设置字段大小,并告诉Django将其用于ModelAdmin类:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}

You can always set your fields sizes in a custom stylesheet and tell Django to use that for your ModelAdmin class:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}

回答 9

对于1.6,使用表格我必须在charfield内指定textarea的属性:

test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])

for 1.6, using forms I had to specify the attributes of the textarea inside the charfield:

test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])

回答 10

与msdin的答案相同,但使用TextInput而不是TextArea:

from django.forms import TextInput

class ShortTextField(models.TextField):
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": TextInput(attrs={'size': 10})}
         )
         return super(ShortTextField, self).formfield(**kwargs)

Same answer as msdin but with TextInput instead of TextArea:

from django.forms import TextInput

class ShortTextField(models.TextField):
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": TextInput(attrs={'size': 10})}
         )
         return super(ShortTextField, self).formfield(**kwargs)

回答 11

这是一个简单但灵活的解决方案。使用自定义表单覆盖某些小部件。

# models.py
class Elephant(models.Model):
    name = models.CharField(max_length=25)
    age = models.IntegerField()

# forms.py
class ElephantForm(forms.ModelForm):

    class Meta:
        widgets = {
            'age': forms.TextInput(attrs={'size': 3}),
        }

# admin.py
@admin.register(Elephant)
class ElephantAdmin(admin.ModelAdmin):
    form = ElephantForm

中提供的小部件 ElephantForm将替换默认的。关键是字段的字符串表示形式。表单中未指定的字段将使用默认窗口小部件。

请注意,尽管age是,但IntegerField我们可以使用该TextInput小部件,因为与不同NumberInput,它TextInput接受size属性。

本文介绍此解决方案。

Here is a simple, yet flexible solution. Use a custom form to override some widgets.

# models.py
class Elephant(models.Model):
    name = models.CharField(max_length=25)
    age = models.IntegerField()

# forms.py
class ElephantForm(forms.ModelForm):

    class Meta:
        widgets = {
            'age': forms.TextInput(attrs={'size': 3}),
        }

# admin.py
@admin.register(Elephant)
class ElephantAdmin(admin.ModelAdmin):
    form = ElephantForm

The widgets given in ElephantForm will replace the default ones. The key is the string representation of the field. Fields not specified in the form will use the default widget.

Note that although age is an IntegerField we can use the TextInput widget, because unlike the NumberInput, TextInput accepts the size attribute.

This solution is described in this article.


回答 12

如果您正在使用涉及选项/选项/下拉菜单的ForeignKey字段,则可以formfield_for_foreignkey在Admin实例中覆盖:

class YourNewAdmin(admin.ModelAdmin):
    ...

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'your_fk_field':
            """ For your FK field of choice, override the dropdown style """
            kwargs["widget"] = django.forms.widgets.Select(attrs={
                'style': 'width: 250px;'
            })

        return super().formfield_for_foreignkey(db_field, request, **kwargs)

这种模式的更多信息,在这里这里

If you are working with a ForeignKey field that involves choices/options/a dropdown menu, you can override formfield_for_foreignkey in the Admin instance:

class YourNewAdmin(admin.ModelAdmin):
    ...

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'your_fk_field':
            """ For your FK field of choice, override the dropdown style """
            kwargs["widget"] = django.forms.widgets.Select(attrs={
                'style': 'width: 250px;'
            })

        return super().formfield_for_foreignkey(db_field, request, **kwargs)

More information on this pattern here and here.


回答 13

还有另一个例子:

class SecenekInline(admin.TabularInline):
   model = Secenek
   # classes = ['collapse']
   def formfield_for_dbfield(self, db_field, **kwargs):
       field = super(SecenekInline, self).formfield_for_dbfield(db_field, **kwargs)
       if db_field.name == 'harf':
           field.widget = TextInput(attrs={'size':2})
       return field
   formfield_overrides = {
       models.TextField: {'widget': Textarea(attrs={'rows':2})},
   }
   extra = 2

如果只想编辑特定的字段大小,则可以使用它。

And one more example too :

class SecenekInline(admin.TabularInline):
   model = Secenek
   # classes = ['collapse']
   def formfield_for_dbfield(self, db_field, **kwargs):
       field = super(SecenekInline, self).formfield_for_dbfield(db_field, **kwargs)
       if db_field.name == 'harf':
           field.widget = TextInput(attrs={'size':2})
       return field
   formfield_overrides = {
       models.TextField: {'widget': Textarea(attrs={'rows':2})},
   }
   extra = 2

If you want to edit only a specific fields size, you can use this.


如何直接转到Django的urls.py中的模板?

问题:如何直接转到Django的urls.py中的模板?

我希望它转到模板robots.txt,而不是views.py。

Instead of going to views.py, I want it to go to to a template, robots.txt.


回答 0

Django 2.0以上

使用基于类的通用视图,但要使用django 2.0+模式进行注册。

from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path('foo/', TemplateView.as_view(template_name='foo.html'))
]

https://docs.djangoproject.com/zh-CN/2.0/ref/class-based-views/base/#templateview

Django 1.5以上

使用基于类的通用视图。

from django.views.generic import TemplateView

urlpatterns = patterns('',
    (r'^foo/$', TemplateView.as_view(template_name='foo.html')),
)

Django <= 1.4

文档:https : //docs.djangoproject.com/zh-CN/1.4/ref/generic-views/#django-views-generic-simple-direct-to-template

urlpatterns = patterns('django.views.generic.simple',
    (r'^foo/$',             'direct_to_template', {'template': 'foo_index.html'}),
    (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
)

Django 2.0+

Use the class based generic views but register with the django 2.0+ pattern.

from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path('foo/', TemplateView.as_view(template_name='foo.html'))
]

https://docs.djangoproject.com/en/2.0/ref/class-based-views/base/#templateview

Django 1.5+

Use the class based generic views.

from django.views.generic import TemplateView

urlpatterns = patterns('',
    (r'^foo/$', TemplateView.as_view(template_name='foo.html')),
)

Django <= 1.4

Docs: https://docs.djangoproject.com/en/1.4/ref/generic-views/#django-views-generic-simple-direct-to-template

urlpatterns = patterns('django.views.generic.simple',
    (r'^foo/$',             'direct_to_template', {'template': 'foo_index.html'}),
    (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
)

回答 1

有关此网站的最新哑剧类型的最新更新,包括:

http://www.techstricks.com/adding-robots-txt-to-your-django-project/

from django.conf.urls import url
from django.views.generic import TemplateView

urlpatterns = [
    #... your project urls
    url(r'^robots.txt$', TemplateView.as_view(template_name="robots.txt", content_type="text/plain"), name="robots_file")
]

A further update for more recent versions and including mime type from this site:

http://www.techstricks.com/adding-robots-txt-to-your-django-project/

from django.conf.urls import url
from django.views.generic import TemplateView

urlpatterns = [
    #... your project urls
    url(r'^robots.txt$', TemplateView.as_view(template_name="robots.txt", content_type="text/plain"), name="robots_file")
]

如何在Django中获取所有请求标头?

问题:如何在Django中获取所有请求标头?

我需要获取所有Django请求标头。根据我的阅读,Django只是将所有内容request.META与大量其他数据一起转储到变量中。获取客户端发送到我的Django应用程序的所有标头的最佳方法是什么?

我将使用这些来构建httplib请求。

I need to get all the Django request headers. From what i’ve read, Django simply dumps everything into the request.META variable along with a lot aof other data. What would be the best way to get all the headers that the client sent to my Django application?

I’m going use these to build a httplib request.


回答 0

根据文档,这 request.META是“包含所有可用HTTP标头的标准Python词典”。如果要获取所有标头,则可以简单地遍历字典。

代码的哪一部分执行此操作取决于您的确切要求。有权访问的任何地方都request应该这样做。

更新资料

我需要在Middleware类中访问它,但是当我对其进行迭代时,除了HTTP标头之外,我还获得了很多其他值。

从文档中:

除了CONTENT_LENGTH和之外CONTENT_TYPE,如上所述,通过将所有字符HTTP都转换META为大写字母,用下划线替换所有连字符并将名称添加HTTP_前缀,将请求中的所有标头都转换为键。

(添加了强调)

HTTP单独获取标题,只需按前缀为的键进行过滤HTTP_

更新2

您能否告诉我如何通过从request.META变量中滤除所有以HTTP_开头并除去开头的HTTP_部分的键来构建标头字典。

当然。这是一种方法。

import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value) 
       in request.META.items() if header.startswith('HTTP_'))

According to the documentation request.META is a “standard Python dictionary containing all available HTTP headers”. If you want to get all the headers you can simply iterate through the dictionary.

Which part of your code to do this depends on your exact requirement. Anyplace that has access to request should do.

Update

I need to access it in a Middleware class but when i iterate over it, I get a lot of values apart from HTTP headers.

From the documentation:

With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name.

(Emphasis added)

To get the HTTP headers alone, just filter by keys prefixed with HTTP_.

Update 2

could you show me how I could build a dictionary of headers by filtering out all the keys from the request.META variable which begin with a HTTP_ and strip out the leading HTTP_ part.

Sure. Here is one way to do it.

import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value) 
       in request.META.items() if header.startswith('HTTP_'))

回答 1

从Django 2.2开始,您可以使用request.headers访问HTTP标头。从HttpRequest.headers文档中

不区分大小写,类似于dict的对象,该对象提供对请求中所有HTTP前缀的标头(加上Content-Length和Content-Type)的访问。

每个标题的名称在显示时都带有标题框(例如User-Agent)。您可以不区分大小写地访问标头:

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

要获取所有标题,可以使用request.headers.keys()request.headers.items()

Starting from Django 2.2, you can use request.headers to access the HTTP headers. From the documentation on HttpRequest.headers:

A case insensitive, dict-like object that provides access to all HTTP-prefixed headers (plus Content-Length and Content-Type) from the request.

The name of each header is stylized with title-casing (e.g. User-Agent) when it’s displayed. You can access headers case-insensitively:

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

To get all headers, you can use request.headers.keys() or request.headers.items().


回答 2

这是另一种实现方法,与上面的Manoj Govindan的答案非常相似:

import re
regex_http_          = re.compile(r'^HTTP_.+$')
regex_content_type   = re.compile(r'^CONTENT_TYPE$')
regex_content_length = re.compile(r'^CONTENT_LENGTH$')

request_headers = {}
for header in request.META:
    if regex_http_.match(header) or regex_content_type.match(header) or regex_content_length.match(header):
        request_headers[header] = request.META[header]

这还将抓取CONTENT_TYPECONTENT_LENGTH请求标头以及HTTP_那些标头。request_headers['some_key]== request.META['some_key']

如果需要包括/省略某些标题,请进行相应的修改。Django在这里列出了一堆,但不是全部:https : //docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Django请求标头的算法:

  1. -用下划线替换连字符_
  2. 转换为大写。
  3. 前置HTTP_到原请求的所有头,除了CONTENT_TYPECONTENT_LENGTH

每个标头的值都应保持不变。

This is another way to do it, very similar to Manoj Govindan‘s answer above:

import re
regex_http_          = re.compile(r'^HTTP_.+$')
regex_content_type   = re.compile(r'^CONTENT_TYPE$')
regex_content_length = re.compile(r'^CONTENT_LENGTH$')

request_headers = {}
for header in request.META:
    if regex_http_.match(header) or regex_content_type.match(header) or regex_content_length.match(header):
        request_headers[header] = request.META[header]

That will also grab the CONTENT_TYPE and CONTENT_LENGTH request headers, along with the HTTP_ ones. request_headers['some_key] == request.META['some_key'].

Modify accordingly if you need to include/omit certain headers. Django lists a bunch, but not all, of them here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Django’s algorithm for request headers:

  1. Replace hyphen - with underscore _
  2. Convert to UPPERCASE.
  3. Prepend HTTP_ to all headers in original request, except for CONTENT_TYPE and CONTENT_LENGTH.

The values of each header should be unmodified.


回答 3

request.META.get(’HTTP_AUTHORIZATION’) /python3.6/site-packages/rest_framework/authentication.py

你可以从这个文件中得到…

request.META.get(‘HTTP_AUTHORIZATION’) /python3.6/site-packages/rest_framework/authentication.py

you can get that from this file though…


回答 4

我认为没有简单的方法可以仅获取HTTP标头。您必须遍历request.META字典以获得所需的所有内容。

django-debug-toolbar采用相同的方法显示标题信息。看一下负责检索头信息的文件

I don’t think there is any easy way to get only HTTP headers. You have to iterate through request.META dict to get what all you need.

django-debug-toolbar takes the same approach to show header information. Have a look at this file responsible for retrieving header information.


回答 5

如果要从请求标头获取客户端密钥,则可以尝试以下操作:

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from apps.authentication.models import CerebroAuth

class CerebroAuthentication(BaseAuthentication):
def authenticate(self, request):
    client_id = request.META.get('HTTP_AUTHORIZATION')
    if not client_id:
        raise exceptions.AuthenticationFailed('Client key not provided')
    client_id = client_id.split()
    if len(client_id) == 1 or len(client_id) > 2:
        msg = ('Invalid secrer key header. No credentials provided.')
        raise exceptions.AuthenticationFailed(msg)
    try:
        client = CerebroAuth.objects.get(client_id=client_id[1])
    except CerebroAuth.DoesNotExist:
        raise exceptions.AuthenticationFailed('No such client')
    return (client, None)

If you want to get client key from request header, u can try following:

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from apps.authentication.models import CerebroAuth

class CerebroAuthentication(BaseAuthentication):
def authenticate(self, request):
    client_id = request.META.get('HTTP_AUTHORIZATION')
    if not client_id:
        raise exceptions.AuthenticationFailed('Client key not provided')
    client_id = client_id.split()
    if len(client_id) == 1 or len(client_id) > 2:
        msg = ('Invalid secrer key header. No credentials provided.')
        raise exceptions.AuthenticationFailed(msg)
    try:
        client = CerebroAuth.objects.get(client_id=client_id[1])
    except CerebroAuth.DoesNotExist:
        raise exceptions.AuthenticationFailed('No such client')
    return (client, None)

回答 6

对于它的价值,看来您的意图是使用传入的HTTP请求来形成另一个HTTP请求。有点像网关。有一个出色的模块django-revproxy可以完成此任务。

资料来源很好地参考了如何完成您想做的事情。

For what it’s worth, it appears your intent is to use the incoming HTTP request to form another HTTP request. Sort of like a gateway. There is an excellent module django-revproxy that accomplishes exactly this.

The source is a pretty good reference on how to accomplish what you are trying to do.


回答 7

<b>request.META</b><br>
{% for k_meta, v_meta in request.META.items %}
  <code>{{ k_meta }}</code> : {{ v_meta }} <br>
{% endfor %}
<b>request.META</b><br>
{% for k_meta, v_meta in request.META.items %}
  <code>{{ k_meta }}</code> : {{ v_meta }} <br>
{% endfor %}

回答 8

只需从Django 2.2开始使用HttpRequest.headers。以下示例直接取自Django官方文档的请求和响应对象”部分。

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

Simply you can use HttpRequest.headers from Django 2.2 onward. Following example is directly taken from the official Django Documentation under Request and response objects section.

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)