标签归档:Django

从URL获取协议+主机名

问题:从URL获取协议+主机名

在我的Django应用中,我需要从引荐来源网址中获取主机名request.META.get('HTTP_REFERER')及其协议,以便从类似以下网址的网址中获取:

我应该得到:

我查看了其他相关问题,并找到了有关urlparse的信息,但这并没有成功

>>> urlparse(request.META.get('HTTP_REFERER')).hostname
'docs.google.com'

In my Django app, I need to get the host name from the referrer in request.META.get('HTTP_REFERER') along with its protocol so that from URLs like:

I should get:

I looked over other related questions and found about urlparse, but that didn’t do the trick since

>>> urlparse(request.META.get('HTTP_REFERER')).hostname
'docs.google.com'

回答 0

您应该能够做到urlparse(docs:python2python3):

from urllib.parse import urlparse
# from urlparse import urlparse  # Python 2
parsed_uri = urlparse('http://stackoverflow.com/questions/1234567/blah-blah-blah-blah' )
result = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri)
print(result)

# gives
'http://stackoverflow.com/'

You should be able to do it with urlparse (docs: python2, python3):

from urllib.parse import urlparse
# from urlparse import urlparse  # Python 2
parsed_uri = urlparse('http://stackoverflow.com/questions/1234567/blah-blah-blah-blah' )
result = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri)
print(result)

# gives
'http://stackoverflow.com/'

回答 1

https://github.com/john-kurkowski/tldextract

这是urlparse的详细版本。它会为您检测域和子域。

从他们的文档中:

>>> import tldextract
>>> tldextract.extract('http://forums.news.cnn.com/')
ExtractResult(subdomain='forums.news', domain='cnn', suffix='com')
>>> tldextract.extract('http://forums.bbc.co.uk/') # United Kingdom
ExtractResult(subdomain='forums', domain='bbc', suffix='co.uk')
>>> tldextract.extract('http://www.worldbank.org.kg/') # Kyrgyzstan
ExtractResult(subdomain='www', domain='worldbank', suffix='org.kg')

ExtractResult 是一个namedtuple,因此可以轻松访问所需的部件。

>>> ext = tldextract.extract('http://forums.bbc.co.uk')
>>> ext.domain
'bbc'
>>> '.'.join(ext[:2]) # rejoin subdomain and domain
'forums.bbc'

https://github.com/john-kurkowski/tldextract

This is a more verbose version of urlparse. It detects domains and subdomains for you.

From their documentation:

>>> import tldextract
>>> tldextract.extract('http://forums.news.cnn.com/')
ExtractResult(subdomain='forums.news', domain='cnn', suffix='com')
>>> tldextract.extract('http://forums.bbc.co.uk/') # United Kingdom
ExtractResult(subdomain='forums', domain='bbc', suffix='co.uk')
>>> tldextract.extract('http://www.worldbank.org.kg/') # Kyrgyzstan
ExtractResult(subdomain='www', domain='worldbank', suffix='org.kg')

ExtractResult is a namedtuple, so it’s simple to access the parts you want.

>>> ext = tldextract.extract('http://forums.bbc.co.uk')
>>> ext.domain
'bbc'
>>> '.'.join(ext[:2]) # rejoin subdomain and domain
'forums.bbc'

回答 2

Python3使用urlsplit

from urllib.parse import urlsplit
url = "http://stackoverflow.com/questions/9626535/get-domain-name-from-url"
base_url = "{0.scheme}://{0.netloc}/".format(urlsplit(url))
print(base_url)
# http://stackoverflow.com/

Python3 using urlsplit:

from urllib.parse import urlsplit
url = "http://stackoverflow.com/questions/9626535/get-domain-name-from-url"
base_url = "{0.scheme}://{0.netloc}/".format(urlsplit(url))
print(base_url)
# http://stackoverflow.com/

回答 3

纯字符串操作:):

>>> url = "http://stackoverflow.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'stackoverflow.com'
>>> url = "stackoverflow.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'stackoverflow.com'
>>> url = "http://foo.bar?haha/whatever"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'foo.bar'

就是这样,伙计们。

Pure string operations :):

>>> url = "http://stackoverflow.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'stackoverflow.com'
>>> url = "stackoverflow.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'stackoverflow.com'
>>> url = "http://foo.bar?haha/whatever"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'foo.bar'

That’s all, folks.


回答 4

>>> import urlparse
>>> url = 'http://stackoverflow.com/questions/1234567/blah-blah-blah-blah'
>>> urlparse.urljoin(url, '/')
'http://stackoverflow.com/'
>>> import urlparse
>>> url = 'http://stackoverflow.com/questions/1234567/blah-blah-blah-blah'
>>> urlparse.urljoin(url, '/')
'http://stackoverflow.com/'

回答 5

如果您认为自己的网址有效,那么它将一直有效

domain = "http://google.com".split("://")[1].split("/")[0] 

if you think your url is valid then this will work all the time

domain = "http://google.com".split("://")[1].split("/")[0] 

回答 6

纯字符串操作有什么问题吗:

url = 'http://stackoverflow.com/questions/9626535/get-domain-name-from-url'
parts = url.split('//', 1)
print parts[0]+'//'+parts[1].split('/', 1)[0]
>>> http://stackoverflow.com

如果您希望在末尾加上斜杠,请将该脚本扩展如下:

parts = url.split('//', 1)
base = parts[0]+'//'+parts[1].split('/', 1)[0]
print base + (len(url) > len(base) and url[len(base)]=='/'and'/' or '')

可能可以优化一点…

Is there anything wrong with pure string operations:

url = 'http://stackoverflow.com/questions/9626535/get-domain-name-from-url'
parts = url.split('//', 1)
print parts[0]+'//'+parts[1].split('/', 1)[0]
>>> http://stackoverflow.com

If you prefer having a trailing slash appended, extend this script a bit like so:

parts = url.split('//', 1)
base = parts[0]+'//'+parts[1].split('/', 1)[0]
print base + (len(url) > len(base) and url[len(base)]=='/'and'/' or '')

That can probably be optimized a bit …


回答 7

这是一个稍微改进的版本:

urls = [
    "http://stackoverflow.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "Stackoverflow.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "http://stackoverflow.com/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "https://StackOverflow.com:8080?test=/questions/9626535/get-domain-name-from-url",
    "stackoverflow.com?test=questions&v=get-domain-name-from-url"]
for url in urls:
    spltAr = url.split("://");
    i = (0,1)[len(spltAr)>1];
    dm = spltAr[i].split("?")[0].split('/')[0].split(':')[0].lower();
    print dm

输出量

stackoverflow.com
stackoverflow.com
stackoverflow.com
stackoverflow.com
stackoverflow.com

小提琴:https ://pyfiddle.io/fiddle/23e4976e-88d2-4757-993e-532aa41b7bf0/ ? i = true

Here is a slightly improved version:

urls = [
    "http://stackoverflow.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "Stackoverflow.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "http://stackoverflow.com/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "https://StackOverflow.com:8080?test=/questions/9626535/get-domain-name-from-url",
    "stackoverflow.com?test=questions&v=get-domain-name-from-url"]
for url in urls:
    spltAr = url.split("://");
    i = (0,1)[len(spltAr)>1];
    dm = spltAr[i].split("?")[0].split('/')[0].split(':')[0].lower();
    print dm

Output

stackoverflow.com
stackoverflow.com
stackoverflow.com
stackoverflow.com
stackoverflow.com

Fiddle: https://pyfiddle.io/fiddle/23e4976e-88d2-4757-993e-532aa41b7bf0/?i=true


回答 8

这有点钝,但是urlparse在两个方向上都使用:

import urlparse
def uri2schemehostname(uri):
    urlparse.urlunparse(urlparse.urlparse(uri)[:2] + ("",) * 4)

该奇数("",) * 4位是因为urlparse期望精确地 等于len(urlparse.ParseResult._fields)6 的序列

This is a bit obtuse, but uses urlparse in both directions:

import urlparse
def uri2schemehostname(uri):
    urlparse.urlunparse(urlparse.urlparse(uri)[:2] + ("",) * 4)

that odd ("",) * 4 bit is because urlparse expects a sequence of exactly len(urlparse.ParseResult._fields) = 6


回答 9

我知道这是一个老问题,但是今天我也遇到了。用单线解决了这个问题:

import re
result = re.sub(r'(.*://)?([^/?]+).*', '\g<1>\g<2>', url)

I know it’s an old question, but I too encountered it today. Solved this with an one-liner:

import re
result = re.sub(r'(.*://)?([^/?]+).*', '\g<1>\g<2>', url)

回答 10

您只需要标准库函数urllib.parse.urlsplit()。这是Python3的示例:

>>> import urllib.parse
>>> o = urllib.parse.urlsplit('https://user:pass@www.example.com:8080/dir/page.html?q1=test&q2=a2#anchor1')
>>> o.scheme
'https'
>>> o.netloc
'user:pass@www.example.com:8080'
>>> o.hostname
'www.example.com'
>>> o.port
8080
>>> o.path
'/dir/page.html'
>>> o.query
'q1=test&q2=a2'
>>> o.fragment
'anchor1'
>>> o.username
'user'
>>> o.password
'pass'

The standard library function urllib.parse.urlsplit() is all you need. Here is an example for Python3:

>>> import urllib.parse
>>> o = urllib.parse.urlsplit('https://user:pass@www.example.com:8080/dir/page.html?q1=test&q2=a2#anchor1')
>>> o.scheme
'https'
>>> o.netloc
'user:pass@www.example.com:8080'
>>> o.hostname
'www.example.com'
>>> o.port
8080
>>> o.path
'/dir/page.html'
>>> o.query
'q1=test&q2=a2'
>>> o.fragment
'anchor1'
>>> o.username
'user'
>>> o.password
'pass'

回答 11

可以通过re.search()解决

import re
url = 'https://docs.google.com/spreadsheet/ccc?key=blah-blah-blah-blah#gid=1'
result = re.search(r'^http[s]*:\/\/[\w\.]*', url).group()
print(result)

#result
'https://docs.google.com'

It could be solved by re.search()

import re
url = 'https://docs.google.com/spreadsheet/ccc?key=blah-blah-blah-blah#gid=1'
result = re.search(r'^http[s]*:\/\/[\w\.]*', url).group()
print(result)

#result
'https://docs.google.com'

回答 12

获取域名/主机名和来源*

url = '/programming/9626535/get-protocol-host-name-from-url'
hostname = url.split('/')[2] # stackoverflow.com
origin = '/'.join(url.split('/')[:3]) # https://stackoverflow.com

* Origin用于XMLHttpRequest标题

to get domain/hostname and Origin*

url = 'https://stackoverflow.com/questions/9626535/get-protocol-host-name-from-url'
hostname = url.split('/')[2] # stackoverflow.com
origin = '/'.join(url.split('/')[:3]) # https://stackoverflow.com

*Origin is used in XMLHttpRequest headers


回答 13

您可以简单地使用带有相对根“ /”的urljoin作为第二个参数:

try:
    from urlparse import urljoin  # Python2
except ImportError:
    from urllib.parse import urljoin  # Python3


url = '/programming/9626535/get-protocol-host-name-from-url'

root_url = urljoin(url, '/')

You can simply use urljoin with relative root ‘/’ as second argument:

import urllib.parse


url = 'https://stackoverflow.com/questions/9626535/get-protocol-host-name-from-url'
root_url = urllib.parse.urljoin(url, '/')
print(root_url)

回答 14

如果它包含的斜线少于3个,则说明您已经得到了,如果不是,那么我们可以发现它之间的出现:

import re

link = http://forum.unisoftdev.com/something

slash_count = len(re.findall("/", link))
print slash_count # output: 3

if slash_count > 2:
   regex = r'\:\/\/(.*?)\/'
   pattern  = re.compile(regex)
   path = re.findall(pattern, url)

   print path

If it contains less than 3 slashes thus you’ve it got and if not then we can find the occurrence between it:

import re

link = http://forum.unisoftdev.com/something

slash_count = len(re.findall("/", link))
print slash_count # output: 3

if slash_count > 2:
   regex = r'\:\/\/(.*?)\/'
   pattern  = re.compile(regex)
   path = re.findall(pattern, url)

   print path

在Django中,如何使用动态字段查找过滤QuerySet?

问题:在Django中,如何使用动态字段查找过滤QuerySet?

给定一个Class:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

是否有可能(如果有的话)有一个基于动态参数进行过滤的QuerySet?例如:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.

Given a class:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

Is it possible, and if so how, to have a QuerySet that filters based on dynamic arguments? For example:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.

回答 0

Python的参数扩展可用于解决此问题:

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

这是一个非常常见且有用的Python习惯用法。

Python’s argument expansion may be used to solve this problem:

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

This is a very common and useful Python idiom.


回答 1

一个简化的例子:

在Django调查应用程序中,我想要一个显示注册用户的HTML选择列表。但是,因为我们有5000个注册用户,所以我需要一种基于查询条件(例如仅完成某个研讨会的人员)过滤该列表的方法。为了使调查元素可重复使用,我需要创建调查问题的人能够将那些条件附加到该问题上(不想将查询硬编码到应用程序中)。

我想出的解决方案并非100%用户友好(需要技术人员的帮助才能创建查询),但确实可以解决问题。创建问题时,编辑者可以在自定义字段中输入字典,例如:

{'is_staff':True,'last_name__startswith':'A',}

该字符串存储在数据库中。在视图代码中,它以形式返回self.question.custom_query。该值是一个看起来像字典的字符串。我们使用eval()将其转换为真实的字典,然后使用** kwargs将其填充到查询集中:

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

A simplified example:

In a Django survey app, I wanted an HTML select list showing registered users. But because we have 5000 registered users, I needed a way to filter that list based on query criteria (such as just people who completed a certain workshop). In order for the survey element to be re-usable, I needed for the person creating the survey question to be able to attach those criteria to that question (don’t want to hard-code the query into the app).

The solution I came up with isn’t 100% user friendly (requires help from a tech person to create the query) but it does solve the problem. When creating the question, the editor can enter a dictionary into a custom field, e.g.:

{'is_staff':True,'last_name__startswith':'A',}

That string is stored in the database. In the view code, it comes back in as self.question.custom_query . The value of that is a string that looks like a dictionary. We turn it back into a real dictionary with eval() and then stuff it into the queryset with **kwargs:

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

回答 2

Django.db.models.Q正是您想要的Django方式。

Django.db.models.Q is exactly what you want in a Django way.


回答 3

一个非常复杂的搜索表通常表明一个更简单的模型正在尝试挖掘出它的出路。

您究竟希望如何获得列名和操作的值?您从哪里获得'name'an 的值'startswith'

 filter_by = '%s__%s' % ('name', 'startswith')
  1. “搜索”表格?您要-什么?-从名称列表中选择名称?从操作列表中选择操作?尽管开放式,但大多数人都觉得这令人困惑且难以使用。

    有多少列具有此类过滤器?6吗 12吗 18吗

    • 一些?复杂的选择列表没有任何意义。一些字段和一些if语句是有意义的。
    • 大量?您的模型听起来不正确。听起来“字段”实际上是另一个表中的一行的键,而不是列的键。
  2. 特定的过滤器按钮。等等…这就是Django管理员的工作方式。特定的过滤器变成按钮。与上述分析相同。一些过滤器很有意义。大量的过滤器通常意味着一种违反第一范式的行为。

许多相似的字段通常意味着应该有更多的行和更少的字段。

A really complex search forms usually indicates that a simpler model is trying to dig it’s way out.

How, exactly, do you expect to get the values for the column name and operation? Where do you get the values of 'name' an 'startswith'?

 filter_by = '%s__%s' % ('name', 'startswith')
  1. A “search” form? You’re going to — what? — pick the name from a list of names? Pick the operation from a list of operations? While open-ended, most people find this confusing and hard-to-use.

    How many columns have such filters? 6? 12? 18?

    • A few? A complex pick-list doesn’t make sense. A few fields and a few if-statements make sense.
    • A large number? Your model doesn’t sound right. It sounds like the “field” is actually a key to a row in another table, not a column.
  2. Specific filter buttons. Wait… That’s the way the Django admin works. Specific filters are turned into buttons. And the same analysis as above applies. A few filters make sense. A large number of filters usually means a kind of first normal form violation.

A lot of similar fields often means there should have been more rows and fewer fields.


从数据库重新加载Django对象

问题:从数据库重新加载Django对象

是否可以从数据库刷新django对象的状态?我的意思是行为大致等同于:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

更新:在跟踪器中找到了重新打开/固定补丁之战:http ://code.djangoproject.com/ticket/901 。仍然不明白为什么维护者不喜欢这个。

Is it possible to refresh the state of a django object from database? I mean behavior roughly equivalent to:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

UPDATE: Found a reopen/wontfix war in the tracker: http://code.djangoproject.com/ticket/901. Still don’t understand why the maintainers don’t like this.


回答 0

从Django 1.8开始,内置了刷新对象。链接到docs

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

As of Django 1.8 refreshing objects is built in. Link to docs.

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

回答 1

我发现从数据库中重新加载对象相对容易,如下所示:

x = X.objects.get(id=x.id)

I’ve found it relatively easy to reload the object from the database like so:

x = X.objects.get(id=x.id)

回答 2

在引用@grep的评论时,是否应该这样做:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

In reference to @grep’s comment, shouldn’t it be possible to do:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

回答 3

正如@Flimm指出的,这是一个非常棒的解决方案:

foo.refresh_from_db()

这会将所有数据从数据库重新加载到对象中。

As @Flimm pointed out, this is a really awesome solution:

foo.refresh_from_db()

This reloads all data from the database into the object.


SQLAlchemy是否具有与Django的get_or_create等效的功能?

问题:SQLAlchemy是否具有与Django的get_or_create等效的功能?

我想从数据库中获取一个对象(如果已存在)(基于提供的参数),或者如果不存在则创建它。

Django的get_or_create(或source)做到了。SQLAlchemy中是否有等效的快捷方式?

我目前正在像这样明确地写出来:

def get_or_create_instrument(session, serial_number):
    instrument = session.query(Instrument).filter_by(serial_number=serial_number).first()
    if instrument:
        return instrument
    else:
        instrument = Instrument(serial_number)
        session.add(instrument)
        return instrument

I want to get an object from the database if it already exists (based on provided parameters) or create it if it does not.

Django’s get_or_create (or source) does this. Is there an equivalent shortcut in SQLAlchemy?

I’m currently writing it out explicitly like this:

def get_or_create_instrument(session, serial_number):
    instrument = session.query(Instrument).filter_by(serial_number=serial_number).first()
    if instrument:
        return instrument
    else:
        instrument = Instrument(serial_number)
        session.add(instrument)
        return instrument

回答 0

基本上就是这样做的方法,没有快捷方式可供使用的AFAIK。

您可以将其概括为:

def get_or_create(session, model, defaults=None, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance, False
    else:
        params = dict((k, v) for k, v in kwargs.iteritems() if not isinstance(v, ClauseElement))
        params.update(defaults or {})
        instance = model(**params)
        session.add(instance)
        return instance, True

That’s basically the way to do it, there is no shortcut readily available AFAIK.

You could generalize it ofcourse:

def get_or_create(session, model, defaults=None, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance, False
    else:
        params = dict((k, v) for k, v in kwargs.iteritems() if not isinstance(v, ClauseElement))
        params.update(defaults or {})
        instance = model(**params)
        session.add(instance)
        return instance, True

2020 update

Here is a cleaner version with Python 3.9’s the new dict union operator (|=)

def get_or_create(session, Model, defaults=None, **kwargs):
    instance = session.query(Model).filter_by(**kwargs).first()
    if instance:
        return instance
    else:
        kwargs |= defaults or {}
        instance = Model(**kwargs)
        session.add(instance)
        return instance

回答 1

在@WoLpH解决方案之后,这是对我有用的代码(简单版本):

def get_or_create(session, model, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance
    else:
        instance = model(**kwargs)
        session.add(instance)
        session.commit()
        return instance

这样,我就可以get_or_create我的模型的任何对象。

假设我的模型对象是:

class Country(Base):
    __tablename__ = 'countries'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)

要获取或创建我的对象,我写:

myCountry = get_or_create(session, Country, name=countryName)

Following the solution of @WoLpH, this is the code that worked for me (simple version):

def get_or_create(session, model, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance
    else:
        instance = model(**kwargs)
        session.add(instance)
        session.commit()
        return instance

With this, I’m able to get_or_create any object of my model.

Suppose my model object is :

class Country(Base):
    __tablename__ = 'countries'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)

To get or create my object I write :

myCountry = get_or_create(session, Country, name=countryName)

回答 2

我一直在解决这个问题,并最终得到了一个相当强大的解决方案:

def get_one_or_create(session,
                      model,
                      create_method='',
                      create_method_kwargs=None,
                      **kwargs):
    try:
        return session.query(model).filter_by(**kwargs).one(), False
    except NoResultFound:
        kwargs.update(create_method_kwargs or {})
        created = getattr(model, create_method, model)(**kwargs)
        try:
            session.add(created)
            session.flush()
            return created, True
        except IntegrityError:
            session.rollback()
            return session.query(model).filter_by(**kwargs).one(), False

我只是写了一篇有关所有详细信息的相当广泛的博客文章,但是对我为什么要使用它的一些颇有想法。

  1. 它解压缩到一个元组,该元组告诉您对象是否存在。这通常在您的工作流程中很有用。

  2. 该功能使您能够使用@classmethod修饰的创建者功能(以及特定于它们的属性)。

  3. 当您有多个进程连接到数据存储时,该解决方案可防止出现竞争状况。

编辑:我已经改变session.commit()session.flush()在解释这个博客帖子。请注意,这些决定特定于所使用的数据存储(在这种情况下为Postgres)。

编辑2:我已在函数中使用{}作为默认值进行了更新,因为这是典型的Python陷阱。谢谢你的评论,奈杰尔!如果您对此问题感到好奇,请查看此StackOverflow问题此博客文章

I’ve been playing with this problem and have ended up with a fairly robust solution:

def get_one_or_create(session,
                      model,
                      create_method='',
                      create_method_kwargs=None,
                      **kwargs):
    try:
        return session.query(model).filter_by(**kwargs).one(), False
    except NoResultFound:
        kwargs.update(create_method_kwargs or {})
        created = getattr(model, create_method, model)(**kwargs)
        try:
            session.add(created)
            session.flush()
            return created, True
        except IntegrityError:
            session.rollback()
            return session.query(model).filter_by(**kwargs).one(), False

I just wrote a fairly expansive blog post on all the details, but a few quite ideas of why I used this.

  1. It unpacks to a tuple that tells you if the object existed or not. This can often be useful in your workflow.

  2. The function gives the ability to work with @classmethod decorated creator functions (and attributes specific to them).

  3. The solution protects against Race Conditions when you have more than one process connected to the datastore.

EDIT: I’ve changed session.commit() to session.flush() as explained in this blog post. Note that these decisions are specific to the datastore used (Postgres in this case).

EDIT 2: I’ve updated using a {} as a default value in the function as this is typical Python gotcha. Thanks for the comment, Nigel! If your curious about this gotcha, check out this StackOverflow question and this blog post.


回答 3

埃里克出色答案的修改版

def get_one_or_create(session,
                      model,
                      create_method='',
                      create_method_kwargs=None,
                      **kwargs):
    try:
        return session.query(model).filter_by(**kwargs).one(), True
    except NoResultFound:
        kwargs.update(create_method_kwargs or {})
        try:
            with session.begin_nested():
                created = getattr(model, create_method, model)(**kwargs)
                session.add(created)
            return created, False
        except IntegrityError:
            return session.query(model).filter_by(**kwargs).one(), True
  • 使用嵌套事务仅回滚新项的添加,而不回滚所有内容(请参阅此答案以将嵌套事务与SQLite一起使用)
  • 移动create_method。如果创建的对象具有关系,并且通过这些关系为其分配了成员,则它将自动添加到会话中。例如,创建一个book具有user_iduser作为对应关系的,然后在book.user=<user object>里面做create_method将添加book到会话中。这意味着create_method必须在内部with才能从最终回滚中受益。请注意,它会begin_nested自动触发冲洗。

请注意,如果使用MySQL,则必须将事务隔离级别设置为READ COMMITTED而不是REPEATABLE READ此级别。Django的get_or_create(和此处)使用相同的策略,另请参见Django 文档

A modified version of erik’s excellent answer

def get_one_or_create(session,
                      model,
                      create_method='',
                      create_method_kwargs=None,
                      **kwargs):
    try:
        return session.query(model).filter_by(**kwargs).one(), True
    except NoResultFound:
        kwargs.update(create_method_kwargs or {})
        try:
            with session.begin_nested():
                created = getattr(model, create_method, model)(**kwargs)
                session.add(created)
            return created, False
        except IntegrityError:
            return session.query(model).filter_by(**kwargs).one(), True
  • Use a nested transaction to only roll back the addition of the new item instead of rolling back everything (See this answer to use nested transactions with SQLite)
  • Move create_method. If the created object has relations and it is assigned members through those relations, it is automatically added to the session. E.g. create a book, which has user_id and user as corresponding relationship, then doing book.user=<user object> inside of create_method will add book to the session. This means that create_method must be inside with to benefit from an eventual rollback. Note that begin_nested automatically triggers a flush.

Note that if using MySQL, the transaction isolation level must be set to READ COMMITTED rather than REPEATABLE READ for this to work. Django’s get_or_create (and here) uses the same stratagem, see also the Django documentation.


回答 4

这个SQLALchemy食谱能很好地完成工作。

首先要做的是定义一个函数,该函数被赋予要使用的Session,并将字典与Session()关联起来,以跟踪当前的唯一键。

def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
    cache = getattr(session, '_unique_cache', None)
    if cache is None:
        session._unique_cache = cache = {}

    key = (cls, hashfunc(*arg, **kw))
    if key in cache:
        return cache[key]
    else:
        with session.no_autoflush:
            q = session.query(cls)
            q = queryfunc(q, *arg, **kw)
            obj = q.first()
            if not obj:
                obj = constructor(*arg, **kw)
                session.add(obj)
        cache[key] = obj
        return obj

在mixin中有一个使用此功能的示例:

class UniqueMixin(object):
    @classmethod
    def unique_hash(cls, *arg, **kw):
        raise NotImplementedError()

    @classmethod
    def unique_filter(cls, query, *arg, **kw):
        raise NotImplementedError()

    @classmethod
    def as_unique(cls, session, *arg, **kw):
        return _unique(
                    session,
                    cls,
                    cls.unique_hash,
                    cls.unique_filter,
                    cls,
                    arg, kw
            )

最后创建唯一的get_or_create模型:

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

engine = create_engine('sqlite://', echo=True)

Session = sessionmaker(bind=engine)

class Widget(UniqueMixin, Base):
    __tablename__ = 'widget'

    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)

    @classmethod
    def unique_hash(cls, name):
        return name

    @classmethod
    def unique_filter(cls, query, name):
        return query.filter(Widget.name == name)

Base.metadata.create_all(engine)

session = Session()

w1, w2, w3 = Widget.as_unique(session, name='w1'), \
                Widget.as_unique(session, name='w2'), \
                Widget.as_unique(session, name='w3')
w1b = Widget.as_unique(session, name='w1')

assert w1 is w1b
assert w2 is not w3
assert w2 is not w1

session.commit()

配方更深入地介绍了这个想法,并提供了不同的方法,但是我已经成功地使用了这一方法。

This SQLALchemy recipe does the job nice and elegant.

The first thing to do is to define a function that is given a Session to work with, and associates a dictionary with the Session() which keeps track of current unique keys.

def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
    cache = getattr(session, '_unique_cache', None)
    if cache is None:
        session._unique_cache = cache = {}

    key = (cls, hashfunc(*arg, **kw))
    if key in cache:
        return cache[key]
    else:
        with session.no_autoflush:
            q = session.query(cls)
            q = queryfunc(q, *arg, **kw)
            obj = q.first()
            if not obj:
                obj = constructor(*arg, **kw)
                session.add(obj)
        cache[key] = obj
        return obj

An example of utilizing this function would be in a mixin:

class UniqueMixin(object):
    @classmethod
    def unique_hash(cls, *arg, **kw):
        raise NotImplementedError()

    @classmethod
    def unique_filter(cls, query, *arg, **kw):
        raise NotImplementedError()

    @classmethod
    def as_unique(cls, session, *arg, **kw):
        return _unique(
                    session,
                    cls,
                    cls.unique_hash,
                    cls.unique_filter,
                    cls,
                    arg, kw
            )

And finally creating the unique get_or_create model:

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

engine = create_engine('sqlite://', echo=True)

Session = sessionmaker(bind=engine)

class Widget(UniqueMixin, Base):
    __tablename__ = 'widget'

    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)

    @classmethod
    def unique_hash(cls, name):
        return name

    @classmethod
    def unique_filter(cls, query, name):
        return query.filter(Widget.name == name)

Base.metadata.create_all(engine)

session = Session()

w1, w2, w3 = Widget.as_unique(session, name='w1'), \
                Widget.as_unique(session, name='w2'), \
                Widget.as_unique(session, name='w3')
w1b = Widget.as_unique(session, name='w1')

assert w1 is w1b
assert w2 is not w3
assert w2 is not w1

session.commit()

The recipe goes deeper into the idea and provides different approaches but I’ve used this one with great success.


回答 5

语义上最接近的可能是:

def get_or_create(model, **kwargs):
    """SqlAlchemy implementation of Django's get_or_create.
    """
    session = Session()
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance, False
    else:
        instance = model(**kwargs)
        session.add(instance)
        session.commit()
        return instance, True

不知道如何依靠Sessionsqlalchemy中的全局定义,但是Django版本没有连接,所以…

返回的元组包含实例和一个布尔值,指示是否创建了实例(即,如果我们从数据库读取实例,则为False)。

get_or_create经常使用Django 来确保全局数据可用,因此我会尽早提交。

The closest semantically is probably:

def get_or_create(model, **kwargs):
    """SqlAlchemy implementation of Django's get_or_create.
    """
    session = Session()
    instance = session.query(model).filter_by(**kwargs).first()
    if instance:
        return instance, False
    else:
        instance = model(**kwargs)
        session.add(instance)
        session.commit()
        return instance, True

not sure how kosher it is to rely on a globally defined Session in sqlalchemy, but the Django version doesn’t take a connection so…

The tuple returned contains the instance and a boolean indicating if the instance was created (i.e. it’s False if we read the instance from the db).

Django’s get_or_create is often used to make sure that global data is available, so I’m committing at the earliest point possible.


回答 6

我稍微简化了@Kevin。解决方案,以避免将整个功能包装在if/ else语句中。这样,只有一个return,我发现它更干净:

def get_or_create(session, model, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()

    if not instance:
        instance = model(**kwargs)
        session.add(instance)

    return instance

I slightly simplified @Kevin. solution to avoid wrapping the whole function in an if/else statement. This way there’s only one return, which I find cleaner:

def get_or_create(session, model, **kwargs):
    instance = session.query(model).filter_by(**kwargs).first()

    if not instance:
        instance = model(**kwargs)
        session.add(instance)

    return instance

回答 7

根据您采用的隔离级别,以上解决方案均无效。我发现的最佳解决方案是以下形式的RAW SQL:

INSERT INTO table(f1, f2, unique_f3) 
SELECT 'v1', 'v2', 'v3' 
WHERE NOT EXISTS (SELECT 1 FROM table WHERE f3 = 'v3')

无论隔离级别和并行度如何,这在事务上都是安全的。

当心:为了使其高效,为唯一列使用INDEX是明智的。

Depending on the isolation level you adopted, none of the above solutions would work. The best solution I have found is a RAW SQL in the following form:

INSERT INTO table(f1, f2, unique_f3) 
SELECT 'v1', 'v2', 'v3' 
WHERE NOT EXISTS (SELECT 1 FROM table WHERE f3 = 'v3')

This is transactionally safe whatever the isolation level and the degree of parallelism are.

Beware: in order to make it efficient, it would be wise to have an INDEX for the unique column.


在Django中保存Unicode字符串时,MySQL“字符串值不正确”错误

问题:在Django中保存Unicode字符串时,MySQL“字符串值不正确”错误

尝试将first_name,last_name保存到Django的auth_user模型时,出现奇怪的错误消息。

失败的例子

user = User.object.create_user(username, email, password)
user.first_name = u'Rytis'
user.last_name = u'Slatkevičius'
user.save()
>>> Incorrect string value: '\xC4\x8Dius' for column 'last_name' at row 104

user.first_name = u'Валерий'
user.last_name = u'Богданов'
user.save()
>>> Incorrect string value: '\xD0\x92\xD0\xB0\xD0\xBB...' for column 'first_name' at row 104

user.first_name = u'Krzysztof'
user.last_name = u'Szukiełojć'
user.save()
>>> Incorrect string value: '\xC5\x82oj\xC4\x87' for column 'last_name' at row 104

成功的例子

user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED

MySQL设置

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       | 
| character_set_connection | utf8                       | 
| character_set_database   | utf8                       | 
| character_set_filesystem | binary                     | 
| character_set_results    | utf8                       | 
| character_set_server     | utf8                       | 
| character_set_system     | utf8                       | 
| character_sets_dir       | /usr/share/mysql/charsets/ | 
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

表字符集和排序规则

表auth_user具有utf-8字符集,并带有utf8_general_ci排序规则。

UPDATE命令的结果

使用UPDATE命令将上述值更新到auth_user表时,它没有引发任何错误。

mysql> update auth_user set last_name='Slatkevičiusa' where id=1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select last_name from auth_user where id=100;
+---------------+
| last_name     |
+---------------+
| Slatkevi?iusa | 
+---------------+
1 row in set (0.00 sec)

PostgreSQL的

当我在Django中切换数据库后端时,上面列出的失败值可以更新到PostgreSQL表中。真奇怪。

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8     | UTF-8 Unicode               | utf8_general_ci     |      3 | 
...

但是从http://www.postgresql.org/docs/8.1/interactive/multibyte.html,我发现了以下内容:

Name Bytes/Char
UTF8 1-4

这是否意味着unicode char在PostgreSQL中的maxlen为4个字节,而在MySQL中为3个字节,这导致了上述错误?

I got strange error message when tried to save first_name, last_name to Django’s auth_user model.

Failed examples

user = User.object.create_user(username, email, password)
user.first_name = u'Rytis'
user.last_name = u'Slatkevičius'
user.save()
>>> Incorrect string value: '\xC4\x8Dius' for column 'last_name' at row 104

user.first_name = u'Валерий'
user.last_name = u'Богданов'
user.save()
>>> Incorrect string value: '\xD0\x92\xD0\xB0\xD0\xBB...' for column 'first_name' at row 104

user.first_name = u'Krzysztof'
user.last_name = u'Szukiełojć'
user.save()
>>> Incorrect string value: '\xC5\x82oj\xC4\x87' for column 'last_name' at row 104

Succeed examples

user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED

MySQL settings

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       | 
| character_set_connection | utf8                       | 
| character_set_database   | utf8                       | 
| character_set_filesystem | binary                     | 
| character_set_results    | utf8                       | 
| character_set_server     | utf8                       | 
| character_set_system     | utf8                       | 
| character_sets_dir       | /usr/share/mysql/charsets/ | 
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

Table charset and collation

Table auth_user has utf-8 charset with utf8_general_ci collation.

Results of UPDATE command

It didn’t raise any error when updating above values to auth_user table by using UPDATE command.

mysql> update auth_user set last_name='Slatkevičiusa' where id=1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select last_name from auth_user where id=100;
+---------------+
| last_name     |
+---------------+
| Slatkevi?iusa | 
+---------------+
1 row in set (0.00 sec)

PostgreSQL

The failed values listed above can be updated into PostgreSQL table when I switched the database backend in Django. It’s strange.

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8     | UTF-8 Unicode               | utf8_general_ci     |      3 | 
...

But from http://www.postgresql.org/docs/8.1/interactive/multibyte.html, I found the following:

Name Bytes/Char
UTF8 1-4

Is it means unicode char has maxlen of 4 bytes in PostgreSQL but 3 bytes in MySQL which caused above error?


回答 0

这些答案都没有为我解决问题。根本原因是:

您不能在MySQL中使用utf-8字符集存储4字节字符。

MySQL的utf-8字符限制3个字节(是的,这很奇怪,Django开发人员在这里总结得很好

要解决此问题,您需要:

  1. 更改您的MySQL数据库,表和列以使用utf8mb4字符集(仅从MySQL 5.5起可用)
  2. 在Django设置文件中指定字符集,如下所示:

settings.py

DATABASES = {
    'default': {
        'ENGINE':'django.db.backends.mysql',
        ...
        'OPTIONS': {'charset': 'utf8mb4'},
    }
}

注意:重新创建数据库时,您可能会遇到“ 指定密钥太长 ”的问题。

最可能的原因是a CharField,它的max_length为255,上面有某种索引(例如,唯一)。由于utf8mb4比utf-8使用的空间多33%,因此您需要将这些字段缩小33%。

在这种情况下,请将max_length从255更改为191。

或者,您可以编辑MySQL配置以消除此限制, 但是要注意一些django hackery

更新:我只是再次遇到这个问题,最终因为无法将我的字符数减少到191个而切换到PostgreSQLVARCHAR

None of these answers solved the problem for me. The root cause being:

You cannot store 4-byte characters in MySQL with the utf-8 character set.

MySQL has a 3 byte limit on utf-8 characters (yes, it’s wack, nicely summed up by a Django developer here)

To solve this you need to:

  1. Change your MySQL database, table and columns to use the utf8mb4 character set (only available from MySQL 5.5 onwards)
  2. Specify the charset in your Django settings file as below:

settings.py

DATABASES = {
    'default': {
        'ENGINE':'django.db.backends.mysql',
        ...
        'OPTIONS': {'charset': 'utf8mb4'},
    }
}

Note: When recreating your database you may run into the ‘Specified key was too long‘ issue.

The most likely cause is a CharField which has a max_length of 255 and some kind of index on it (e.g. unique). Because utf8mb4 uses 33% more space than utf-8 you’ll need to make these fields 33% smaller.

In this case, change the max_length from 255 to 191.

Alternatively you can edit your MySQL configuration to remove this restriction but not without some django hackery

UPDATE: I just ran into this issue again and ended up switching to PostgreSQL because I was unable to reduce my VARCHAR to 191 characters.


回答 1

我遇到了同样的问题,并通过更改列的字符集解决了它。即使您的数据库具有默认字符集,utf-8我也认为数据库列在MySQL中可能具有不同的字符集。这是我使用的SQL查询:

    ALTER TABLE database.table MODIFY COLUMN col VARCHAR(255)
    CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

I had the same problem and resolved it by changing the character set of the column. Even though your database has a default character set of utf-8 I think it’s possible for database columns to have a different character set in MySQL. Here’s the SQL QUERY I used:

    ALTER TABLE database.table MODIFY COLUMN col VARCHAR(255)
    CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

回答 2

如果您有此问题,请使用以下python脚本自动更改mysql数据库的所有列。

#! /usr/bin/env python
import MySQLdb

host = "localhost"
passwd = "passwd"
user = "youruser"
dbname = "yourdbname"

db = MySQLdb.connect(host=host, user=user, passwd=passwd, db=dbname)
cursor = db.cursor()

cursor.execute("ALTER DATABASE `%s` CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" % dbname)

sql = "SELECT DISTINCT(table_name) FROM information_schema.columns WHERE table_schema = '%s'" % dbname
cursor.execute(sql)

results = cursor.fetchall()
for row in results:
  sql = "ALTER TABLE `%s` convert to character set DEFAULT COLLATE DEFAULT" % (row[0])
  cursor.execute(sql)
db.close()

If you have this problem here’s a python script to change all the columns of your mysql database automatically.

#! /usr/bin/env python
import MySQLdb

host = "localhost"
passwd = "passwd"
user = "youruser"
dbname = "yourdbname"

db = MySQLdb.connect(host=host, user=user, passwd=passwd, db=dbname)
cursor = db.cursor()

cursor.execute("ALTER DATABASE `%s` CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" % dbname)

sql = "SELECT DISTINCT(table_name) FROM information_schema.columns WHERE table_schema = '%s'" % dbname
cursor.execute(sql)

results = cursor.fetchall()
for row in results:
  sql = "ALTER TABLE `%s` convert to character set DEFAULT COLLATE DEFAULT" % (row[0])
  cursor.execute(sql)
db.close()

回答 3

如果这是一个新项目,则只需删除数据库,然后使用适当的字符集创建一个新项目:

CREATE DATABASE <dbname> CHARACTER SET utf8;

If it’s a new project, I’d just drop the database, and create a new one with a proper charset:

CREATE DATABASE <dbname> CHARACTER SET utf8;

回答 4

我只是想出一种避免上述错误的方法。

保存到数据库

user.first_name = u'Rytis'.encode('unicode_escape')
user.last_name = u'Slatkevičius'.encode('unicode_escape')
user.save()
>>> SUCCEED

print user.last_name
>>> Slatkevi\u010dius
print user.last_name.decode('unicode_escape')
>>> Slatkevičius

这是将这样的字符串保存到MySQL表中并在渲染为模板进行显示之前对其进行解码的唯一方法吗?

I just figured out one method to avoid above errors.

Save to database

user.first_name = u'Rytis'.encode('unicode_escape')
user.last_name = u'Slatkevičius'.encode('unicode_escape')
user.save()
>>> SUCCEED

print user.last_name
>>> Slatkevi\u010dius
print user.last_name.decode('unicode_escape')
>>> Slatkevičius

Is this the only method to save strings like that into a MySQL table and decode it before rendering to templates for display?


回答 5

您可以将文本字段的排序规则更改为UTF8_general_ci,此问题将得到解决。

注意,这不能在Django中完成。

You can change the collation of your text field to UTF8_general_ci and the problem will be solved.

Notice, this cannot be done in Django.


回答 6

您不是要保存unicode字符串,而是要以UTF-8编码保存字节字符串。使它们成为实际的unicode字符串文字:

user.last_name = u'Slatkevičius'

或(当您没有字符串文字时)使用utf-8编码对其进行解码:

user.last_name = lastname.decode('utf-8')

You aren’t trying to save unicode strings, you’re trying to save bytestrings in the UTF-8 encoding. Make them actual unicode string literals:

user.last_name = u'Slatkevičius'

or (when you don’t have string literals) decode them using the utf-8 encoding:

user.last_name = lastname.decode('utf-8')

回答 7

只需更改您的表,无需任何操作。只需在数据库上运行此查询。 更改表table_name转换为字符集utf8

它一定会工作。

Simply alter your table, no need to any thing. just run this query on database. ALTER TABLE table_nameCONVERT TO CHARACTER SET utf8

it will definately work.


回答 8

改进@madprops答案-解决方案作为Django管理命令:

import MySQLdb
from django.conf import settings

from django.core.management.base import BaseCommand


class Command(BaseCommand):

    def handle(self, *args, **options):
        host = settings.DATABASES['default']['HOST']
        password = settings.DATABASES['default']['PASSWORD']
        user = settings.DATABASES['default']['USER']
        dbname = settings.DATABASES['default']['NAME']

        db = MySQLdb.connect(host=host, user=user, passwd=password, db=dbname)
        cursor = db.cursor()

        cursor.execute("ALTER DATABASE `%s` CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" % dbname)

        sql = "SELECT DISTINCT(table_name) FROM information_schema.columns WHERE table_schema = '%s'" % dbname
        cursor.execute(sql)

        results = cursor.fetchall()
        for row in results:
            print(f'Changing table "{row[0]}"...')
            sql = "ALTER TABLE `%s` convert to character set DEFAULT COLLATE DEFAULT" % (row[0])
            cursor.execute(sql)
        db.close()

希望这可以帮助我以外的任何人:)

Improvement to @madprops answer – solution as a django management command:

import MySQLdb
from django.conf import settings

from django.core.management.base import BaseCommand


class Command(BaseCommand):

    def handle(self, *args, **options):
        host = settings.DATABASES['default']['HOST']
        password = settings.DATABASES['default']['PASSWORD']
        user = settings.DATABASES['default']['USER']
        dbname = settings.DATABASES['default']['NAME']

        db = MySQLdb.connect(host=host, user=user, passwd=password, db=dbname)
        cursor = db.cursor()

        cursor.execute("ALTER DATABASE `%s` CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" % dbname)

        sql = "SELECT DISTINCT(table_name) FROM information_schema.columns WHERE table_schema = '%s'" % dbname
        cursor.execute(sql)

        results = cursor.fetchall()
        for row in results:
            print(f'Changing table "{row[0]}"...')
            sql = "ALTER TABLE `%s` convert to character set DEFAULT COLLATE DEFAULT" % (row[0])
            cursor.execute(sql)
        db.close()

Hope this helps anybody but me :)


Python + Django页面重定向

问题:Python + Django页面重定向

如何在Django中完成简单的重定向(例如,cflocation在ColdFusion中或header(location:http://)对于PHP)?

How do I accomplish a simple redirect (e.g. cflocation in ColdFusion, or header(location:http://) for PHP) in Django?


回答 0

这很简单:

from django.http import HttpResponseRedirect

def myview(request):
    ...
    return HttpResponseRedirect("/path/")

官方Django文档中的更多信息

更新:Django 1.0

显然,现在使用,在Django中有一种更好的方法generic views

范例-

from django.views.generic.simple import redirect_to

urlpatterns = patterns('',   
    (r'^one/$', redirect_to, {'url': '/another/'}),

    #etc...
)

通用视图文档中还有更多内容。信贷银行的Barrobés

更新#2:Django 1.3+

在Django 1.5中,redirect_to不再存在,并已由RedirectView代替。感谢Yonatan

from django.views.generic import RedirectView

urlpatterns = patterns('',
    (r'^one/$', RedirectView.as_view(url='/another/')),
)

It’s simple:

from django.http import HttpResponseRedirect

def myview(request):
    ...
    return HttpResponseRedirect("/path/")

More info in the official Django docs

Update: Django 1.0

There is apparently a better way of doing this in Django now using generic views.

Example –

from django.views.generic.simple import redirect_to

urlpatterns = patterns('',   
    (r'^one/$', redirect_to, {'url': '/another/'}),

    #etc...
)

There is more in the generic views documentation. Credit – Carles Barrobés.

Update #2: Django 1.3+

In Django 1.5 redirect_to no longer exists and has been replaced by RedirectView. Credit to Yonatan

from django.views.generic import RedirectView

urlpatterns = patterns('',
    (r'^one/$', RedirectView.as_view(url='/another/')),
)

回答 1

根据您的需要(即,如果您不想进行任何其他预处理),仅使用Django的redirect_to通用视图会更简单:

from django.views.generic.simple import redirect_to

urlpatterns = patterns('',
    (r'^one/$', redirect_to, {'url': '/another/'}),

    #etc...
)

有关更多高级示例,请参见文档


对于Django 1.3+,请使用:

from django.views.generic import RedirectView

urlpatterns = patterns('',
    (r'^one/$', RedirectView.as_view(url='/another/')),
)

Depending on what you want (i.e. if you do not want to do any additional pre-processing), it is simpler to just use Django’s redirect_to generic view:

from django.views.generic.simple import redirect_to

urlpatterns = patterns('',
    (r'^one/$', redirect_to, {'url': '/another/'}),

    #etc...
)

See documentation for more advanced examples.


For Django 1.3+ use:

from django.views.generic import RedirectView

urlpatterns = patterns('',
    (r'^one/$', RedirectView.as_view(url='/another/')),
)

回答 2

实际上,有一个比为每个重定向查看都有更简单的方法-您可以直接在中执行此操作urls.py

from django.http import HttpResponsePermanentRedirect

urlpatterns = patterns(
    '',
    # ...normal patterns here...
    (r'^bad-old-link\.php',
     lambda request: HttpResponsePermanentRedirect('/nice-link')),
)

目标既可以是可调用的,也可以是字符串,这是我在这里使用的。

There’s actually a simpler way than having a view for each redirect – you can do it directly in urls.py:

from django.http import HttpResponsePermanentRedirect

urlpatterns = patterns(
    '',
    # ...normal patterns here...
    (r'^bad-old-link\.php',
     lambda request: HttpResponsePermanentRedirect('/nice-link')),
)

A target can be a callable as well as a string, which is what I’m using here.


回答 3

从Django 1.1开始,您还可以使用更简单的重定向快捷方式:

from django.shortcuts import redirect

def myview(request):
    return redirect('/path')

它还需要一个可选的persistent = True关键字参数。

Since Django 1.1, you can also use the simpler redirect shortcut:

from django.shortcuts import redirect

def myview(request):
    return redirect('/path')

It also takes an optional permanent=True keyword argument.


回答 4

如果您想重定向整个子文件夹,那么RedirectView中url参数实际上是插值的,因此您可以在以下代码中执行以下操作urls.py

from django.conf.urls.defaults import url
from django.views.generic import RedirectView

urlpatterns = [
    url(r'^old/(?P<path>.*)$', RedirectView.as_view(url='/new_path/%(path)s')),
]

?P<path>您捕捉将被送入RedirectView。然后,该捕获的变量将替换为url您提供的参数,/new_path/yay/mypath如果您的原始路径为,则会给我们/old/yay/mypath

….as_view(url='…', query_string=True)如果您也想复制查询字符串,也可以这样做。

If you want to redirect a whole subfolder, the url argument in RedirectView is actually interpolated, so you can do something like this in urls.py:

from django.conf.urls.defaults import url
from django.views.generic import RedirectView

urlpatterns = [
    url(r'^old/(?P<path>.*)$', RedirectView.as_view(url='/new_path/%(path)s')),
]

The ?P<path> you capture will be fed into RedirectView. This captured variable will then be replaced in the url argument you gave, giving us /new_path/yay/mypath if your original path was /old/yay/mypath.

You can also do ….as_view(url='…', query_string=True) if you want to copy the query string over as well.


回答 5

在Django 1.3版中,基于类的方法是:

from django.conf.urls.defaults import patterns, url
from django.views.generic import RedirectView

urlpatterns = patterns('',
    url(r'^some-url/$', RedirectView.as_view(url='/redirect-url/'), name='some_redirect'),
)

此示例位于urls.py中

With Django version 1.3, the class based approach is:

from django.conf.urls.defaults import patterns, url
from django.views.generic import RedirectView

urlpatterns = patterns('',
    url(r'^some-url/$', RedirectView.as_view(url='/redirect-url/'), name='some_redirect'),
)

This example lives in in urls.py


回答 6

谨防。我在开发服务器上进行了此操作,并希望稍后进行更改。

我必须清除缓存以进行更改。为了避免将来出现这种令人头疼的问题,我可以将其设置为临时状态,如下所示:

from django.views.generic import RedirectView

url(r'^source$', RedirectView.as_view(permanent=False, 
                                      url='/dest/')),

Beware. I did this on a development server and wanted to change it later.

I had to clear my caches to change it. In order to avoid this head-scratching in the future, I was able to make it temporary like so:

from django.views.generic import RedirectView

url(r'^source$', RedirectView.as_view(permanent=False, 
                                      url='/dest/')),

回答 7

您可以在“管理员”部分中执行此操作。在文档中对其进行了说明。

https://docs.djangoproject.com/en/dev/ref/contrib/redirects/

You can do this in the Admin section. It’s explained in the documentation.

https://docs.djangoproject.com/en/dev/ref/contrib/redirects/


回答 8

page_path =在urls.py中定义

def deletePolls(request):
    pollId = deletePool(request.GET['id'])
    return HttpResponseRedirect("/page_path/")

page_path = define in urls.py

def deletePolls(request):
    pollId = deletePool(request.GET['id'])
    return HttpResponseRedirect("/page_path/")

回答 9

这应该在大多数版本的Django中都可以使用,我在1.6.5中使用了它:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
    ....
    url(r'^(?P<location_id>\d+)/$', lambda x, location_id: HttpResponseRedirect(reverse('dailyreport_location', args=[location_id])), name='location_stats_redirect'),
    ....
)

使用此解决方案,您仍然可以使用url模式的名称,而不是硬编码的url。网址中的location_id参数向下传递给lambda函数。

This should work in most versions of django, I am using it in 1.6.5:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
    ....
    url(r'^(?P<location_id>\d+)/$', lambda x, location_id: HttpResponseRedirect(reverse('dailyreport_location', args=[location_id])), name='location_stats_redirect'),
    ....
)

You can still use the name of the url pattern instead of a hard coded url with this solution. The location_id parameter from the url is passed down to the lambda function.


如何在Django中序列化模型实例?

问题:如何在Django中序列化模型实例?

关于如何序列化模型QuerySet的文档很多,但是如何将模型实例的字段序列化为JSON?

There is a lot of documentation on how to serialize a Model QuerySet but how do you just serialize to JSON the fields of a Model Instance?


回答 0

您可以轻松地使用列表来包装所需的对象,而这正是Django序列化程序正确地序列化它所需要的,例如:

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])

You can easily use a list to wrap the required object and that’s all what django serializers need to correctly serialize it, eg.:

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])

回答 1

如果您要处理的模型实例列表是您最好的选择serializers.serialize(),那么它会完全满足您的需求。

但是,您要尝试序列化单个对象而不是对象的对象时会遇到问题list。这样,为了摆脱各种黑客攻击,只需使用Django即可model_to_dict(如果我没记错的serializers.serialize()话,也要依赖它):

from django.forms.models import model_to_dict

# assuming obj is your model instance
dict_obj = model_to_dict( obj )

现在,您只需要直接json.dumps调用即可将其序列化为json:

import json
serialized = json.dumps(dict_obj)

而已!:)

If you’re dealing with a list of model instances the best you can do is using serializers.serialize(), it gonna fit your need perfectly.

However, you are to face an issue with trying to serialize a single object, not a list of objects. That way, in order to get rid of different hacks, just use Django’s model_to_dict (if I’m not mistaken, serializers.serialize() relies on it, too):

from django.forms.models import model_to_dict

# assuming obj is your model instance
dict_obj = model_to_dict( obj )

You now just need one straight json.dumps call to serialize it to json:

import json
serialized = json.dumps(dict_obj)

That’s it! :)


回答 2

为了避免数组包装,请在返回响应之前将其删除:

import json
from django.core import serializers

def getObject(request, id):
    obj = MyModel.objects.get(pk=id)
    data = serializers.serialize('json', [obj,])
    struct = json.loads(data)
    data = json.dumps(struct[0])
    return HttpResponse(data, mimetype='application/json')

我也发现了关于这个主题的这篇有趣的文章:

http://timsaylor.com/convert-django-model-instances-to-dictionaries

它使用django.forms.models.model_to_dict,它看起来像是完成这项工作的理想工具。

To avoid the array wrapper, remove it before you return the response:

import json
from django.core import serializers

def getObject(request, id):
    obj = MyModel.objects.get(pk=id)
    data = serializers.serialize('json', [obj,])
    struct = json.loads(data)
    data = json.dumps(struct[0])
    return HttpResponse(data, mimetype='application/json')

I found this interesting post on the subject too:

http://timsaylor.com/convert-django-model-instances-to-dictionaries

It uses django.forms.models.model_to_dict, which looks like the perfect tool for the job.


回答 3

对此有一个很好的答案,我很惊讶没有提到它。仅需几行,您就可以处理日期,模型以及其他所有内容。

制作一个可以处理模型的自定义编码器:

from django.forms import model_to_dict
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Model

class ExtendedEncoder(DjangoJSONEncoder):

    def default(self, o):

        if isinstance(o, Model):
            return model_to_dict(o)

        return super().default(o)

现在在使用json.dumps时使用它

json.dumps(data, cls=ExtendedEncoder)

现在,模型,日期和所有内容都可以序列化,而不必放在数组中或序列化和非序列化。您拥有的所有自定义内容都可以添加到default方法中。

您甚至可以通过以下方式使用Django的本地JsonResponse:

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)
``

There is a good answer for this and I’m surprised it hasn’t been mentioned. With a few lines you can handle dates, models, and everything else.

Make a custom encoder that can handle models:

from django.forms import model_to_dict
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Model

class ExtendedEncoder(DjangoJSONEncoder):

    def default(self, o):

        if isinstance(o, Model):
            return model_to_dict(o)

        return super().default(o)

Now use it when you use json.dumps

json.dumps(data, cls=ExtendedEncoder)

Now models, dates and everything can be serialized and it doesn’t have to be in an array or serialized and unserialized. Anything you have that is custom can just be added to the default method.

You can even use Django’s native JsonResponse this way:

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)

回答 4

听起来您要问的是涉及序列化Django模型实例的数据结构以实现互操作性。其他张贴者是正确的:如果您希望将序列化表格与可以通过Django api查询数据库的python应用程序一起使用,则需要使用一个对象序列化一个查询集。另一方面,如果您需要的是在不接触数据库或不使用Django的情况下在其他地方重新添加模型实例的方法,则您需要做一些工作。

这是我的工作:

首先,我demjson用于转换。碰巧是我首先发现的,但可能不是最好的。我的实现方式取决于其功能之一,但其他转换器也应采用类似的方式。

其次,json_equivalent在可能需要序列化的所有模型上实现一个方法。这是的神奇方法demjson,但是无论您选择哪种实现,都可能要考虑一下。这个想法是,您返回一个可以直接转换为的对象json(即数组或字典)。如果您真的想自动执行此操作:

def json_equivalent(self):
    dictionary = {}
    for field in self._meta.get_all_field_names()
        dictionary[field] = self.__getattribute__(field)
    return dictionary

除非您具有完全平坦的数据结构(否ForeignKeys,数据库中只有数字和字符串,等等),否则这对您没有帮助。否则,您应该认真考虑实现此方法的正确方法。

第三,打电话给demjson.JSON.encode(instance)您,您便拥有了想要的东西。

It sounds like what you’re asking about involves serializing the data structure of a Django model instance for interoperability. The other posters are correct: if you wanted the serialized form to be used with a python application that can query the database via Django’s api, then you would wan to serialize a queryset with one object. If, on the other hand, what you need is a way to re-inflate the model instance somewhere else without touching the database or without using Django, then you have a little bit of work to do.

Here’s what I do:

First, I use demjson for the conversion. It happened to be what I found first, but it might not be the best. My implementation depends on one of its features, but there should be similar ways with other converters.

Second, implement a json_equivalent method on all models that you might need serialized. This is a magic method for demjson, but it’s probably something you’re going to want to think about no matter what implementation you choose. The idea is that you return an object that is directly convertible to json (i.e. an array or dictionary). If you really want to do this automatically:

def json_equivalent(self):
    dictionary = {}
    for field in self._meta.get_all_field_names()
        dictionary[field] = self.__getattribute__(field)
    return dictionary

This will not be helpful to you unless you have a completely flat data structure (no ForeignKeys, only numbers and strings in the database, etc.). Otherwise, you should seriously think about the right way to implement this method.

Third, call demjson.JSON.encode(instance) and you have what you want.


回答 5

如果您要问如何从模型中序列化一个对象,并且知道仅要在查询集中获取一个对象(例如,使用objects.get),则可以使用以下方法:

import django.core.serializers
import django.http
import models

def jsonExample(request,poll_id):
    s = django.core.serializers.serialize('json',[models.Poll.objects.get(id=poll_id)])
    # s is a string with [] around it, so strip them off
    o=s.strip("[]")
    return django.http.HttpResponse(o, mimetype="application/json")

这将使您具有以下形式:

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}

If you’re asking how to serialize a single object from a model and you know you’re only going to get one object in the queryset (for instance, using objects.get), then use something like:

import django.core.serializers
import django.http
import models

def jsonExample(request,poll_id):
    s = django.core.serializers.serialize('json',[models.Poll.objects.get(id=poll_id)])
    # s is a string with [] around it, so strip them off
    o=s.strip("[]")
    return django.http.HttpResponse(o, mimetype="application/json")

which would get you something of the form:

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}

回答 6

我通过向模型添加序列化方法解决了这个问题:

def toJSON(self):
    import simplejson
    return simplejson.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))

这是那些讨厌单线的冗长等效项:

def toJSON(self):
    fields = []
    for field in self._meta.fields:
        fields.append(field.name)

    d = {}
    for attr in fields:
        d[attr] = getattr(self, attr)

    import simplejson
    return simplejson.dumps(d)

_meta.fields 是模型字段的有序列表,可以从实例和模型本身进行访问。

I solved this problem by adding a serialization method to my model:

def toJSON(self):
    import simplejson
    return simplejson.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))

Here’s the verbose equivalent for those averse to one-liners:

def toJSON(self):
    fields = []
    for field in self._meta.fields:
        fields.append(field.name)

    d = {}
    for attr in fields:
        d[attr] = getattr(self, attr)

    import simplejson
    return simplejson.dumps(d)

_meta.fields is an ordered list of model fields which can be accessed from instances and from the model itself.


回答 7

这是我的解决方案,可让您轻松自定义JSON并组织相关记录

首先在模型上实现一种方法。我称是,json但是您可以随便叫它,例如:

class Car(Model):
    ...
    def json(self):
        return {
            'manufacturer': self.manufacturer.name,
            'model': self.model,
            'colors': [color.json for color in self.colors.all()],
        }

然后在视图中我这样做:

data = [car.json for car in Car.objects.all()]
return HttpResponse(json.dumps(data), content_type='application/json; charset=UTF-8', status=status)

Here’s my solution for this, which allows you to easily customize the JSON as well as organize related records

Firstly implement a method on the model. I call is json but you can call it whatever you like, e.g.:

class Car(Model):
    ...
    def json(self):
        return {
            'manufacturer': self.manufacturer.name,
            'model': self.model,
            'colors': [color.json for color in self.colors.all()],
        }

Then in the view I do:

data = [car.json for car in Car.objects.all()]
return HttpResponse(json.dumps(data), content_type='application/json; charset=UTF-8', status=status)

回答 8

使用清单,将解决问题

第1步:

 result=YOUR_MODELE_NAME.objects.values('PROP1','PROP2').all();

第2步:

 result=list(result)  #after getting data from model convert result to list

第三步:

 return HttpResponse(json.dumps(result), content_type = "application/json")

Use list, it will solve problem

Step1:

 result=YOUR_MODELE_NAME.objects.values('PROP1','PROP2').all();

Step2:

 result=list(result)  #after getting data from model convert result to list

Step3:

 return HttpResponse(json.dumps(result), content_type = "application/json")

回答 9

要序列化和反序列化,请使用以下命令:

from django.core import serializers

serial = serializers.serialize("json", [obj])
...
# .next() pulls the first object out of the generator
# .object retrieves django object the object from the DeserializedObject
obj = next(serializers.deserialize("json", serial)).object

To serialize and deserialze, use the following:

from django.core import serializers

serial = serializers.serialize("json", [obj])
...
# .next() pulls the first object out of the generator
# .object retrieves django object the object from the DeserializedObject
obj = next(serializers.deserialize("json", serial)).object

回答 10

.values() 我需要将模型实例转换为JSON。

.values()文档:https ://docs.djangoproject.com/zh/3.0/ref/models/querysets/#values

名为Project的模型的示例用法。

注意:我正在使用Django Rest Framework

    @csrf_exempt
    @api_view(["GET"])
    def get_project(request):
        id = request.query_params['id']
        data = Project.objects.filter(id=id).values()
        if len(data) == 0:
            return JsonResponse(status=404, data={'message': 'Project with id {} not found.'.format(id)})
        return JsonResponse(data[0])

有效ID的结果:

{
    "id": 47,
    "title": "Project Name",
    "description": "",
    "created_at": "2020-01-21T18:13:49.693Z",
}

.values() is what I needed to convert a model instance to JSON.

.values() documentation: https://docs.djangoproject.com/en/3.0/ref/models/querysets/#values

Example usage with a model called Project.

Note: I’m using Django Rest Framework

    @csrf_exempt
    @api_view(["GET"])
    def get_project(request):
        id = request.query_params['id']
        data = Project.objects.filter(id=id).values()
        if len(data) == 0:
            return JsonResponse(status=404, data={'message': 'Project with id {} not found.'.format(id)})
        return JsonResponse(data[0])

Result from a valid id:

{
    "id": 47,
    "title": "Project Name",
    "description": "",
    "created_at": "2020-01-21T18:13:49.693Z",
}

回答 11

如果要将单个模型对象作为json响应返回给客户端,则可以执行以下简单解决方案:

from django.forms.models import model_to_dict
from django.http import JsonResponse

movie = Movie.objects.get(pk=1)
return JsonResponse(model_to_dict(movie))

If you want to return the single model object as a json response to a client, you can do this simple solution:

from django.forms.models import model_to_dict
from django.http import JsonResponse

movie = Movie.objects.get(pk=1)
return JsonResponse(model_to_dict(movie))

回答 12

使用Django序列化器python格式,

from django.core import serializers

qs = SomeModel.objects.all()
serialized_obj = serializers.serialize('python', qs)

jsonpython格式有什么区别?

json格式将返回的结果str,而python将在返回的结果要么listOrderedDict

Use Django Serializer with python format,

from django.core import serializers

qs = SomeModel.objects.all()
serialized_obj = serializers.serialize('python', qs)

What’s difference between json and python format?

The json format will return the result as str whereas python will return the result in either list or OrderedDict


回答 13

似乎您不能序列化一个实例,而必须序列化一个对象的QuerySet。

from django.core import serializers
from models import *

def getUser(request):
    return HttpResponse(json(Users.objects.filter(id=88)))

我用完了svndjango发行版,因此在较早的版本中可能不存在。

It doesn’t seem you can serialize an instance, you’d have to serialize a QuerySet of one object.

from django.core import serializers
from models import *

def getUser(request):
    return HttpResponse(json(Users.objects.filter(id=88)))

I run out of the svn release of django, so this may not be in earlier versions.


回答 14

ville = UneVille.objects.get(nom='lihlihlihlih')
....
blablablab
.......

return HttpResponse(simplejson.dumps(ville.__dict__))

我返回我的实例的命令

因此它返回的内容类似于{‘field1’:value,“ field2”:value,….}

ville = UneVille.objects.get(nom='lihlihlihlih')
....
blablablab
.......

return HttpResponse(simplejson.dumps(ville.__dict__))

I return the dict of my instance

so it return something like {‘field1’:value,”field2″:value,….}


回答 15

这样呢:

def ins2dic(obj):
    SubDic = obj.__dict__
    del SubDic['id']
    del SubDic['_state']
return SubDic

或排除您不想要的任何东西。

how about this way:

def ins2dic(obj):
    SubDic = obj.__dict__
    del SubDic['id']
    del SubDic['_state']
return SubDic

or exclude anything you don’t want.


回答 16

与我希望从框架(最简单的方法)相比,所有这些答案都有些棘手,如果您使用其余框架,我认为到目前为止,这是最简单的方法:

rep = YourSerializerClass().to_representation(your_instance)
json.dumps(rep)

这将直接使用Serializer,同时尊重您在其上定义的字段以及任何关联等。

All of these answers were a little hacky compared to what I would expect from a framework, the simplest method, I think by far, if you are using the rest framework:

rep = YourSerializerClass().to_representation(your_instance)
json.dumps(rep)

This uses the Serializer directly, respecting the fields you’ve defined on it, as well as any associations, etc.


Django设置“ SECRET_KEY”的目的

问题:Django设置“ SECRET_KEY”的目的

SECRET_KEYdjango 的意义到底是什么?我做了一些Google搜索,并检查了文档(https://docs.djangoproject.com/en/dev/ref/settings/#secret-key),但是我正在寻找对此的更深入的说明,以及为什么需要它。

例如,如果密钥被泄露/其他人知道密钥是什么,会发生什么?谢谢。

What exactly is the point of the SECRET_KEY in django? I did a few google searches and checked out the docs ( https://docs.djangoproject.com/en/dev/ref/settings/#secret-key ), but I was looking for a more in-depth explanation of this, and why it is required.

For example, what could happen if the key was compromised / others knew what it was? Thank you.


回答 0

它用于制作哈希。看:

>grep -Inr SECRET_KEY *
conf/global_settings.py:255:SECRET_KEY = ''
conf/project_template/settings.py:61:SECRET_KEY = ''
contrib/auth/tokens.py:54:        hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
contrib/comments/forms.py:86:        info = (content_type, object_pk, timestamp, settings.SECRET_KEY)
contrib/formtools/utils.py:15:    order, pickles the result with the SECRET_KEY setting, then takes an md5
contrib/formtools/utils.py:32:    data.append(settings.SECRET_KEY)
contrib/messages/storage/cookie.py:112:        SECRET_KEY, modified to make it unique for the present purpose.
contrib/messages/storage/cookie.py:114:        key = 'django.contrib.messages' + settings.SECRET_KEY
contrib/sessions/backends/base.py:89:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/backends/base.py:95:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
contrib/sessions/backends/base.py:134:        # Use settings.SECRET_KEY as added salt.
contrib/sessions/backends/base.py:143:                       settings.SECRET_KEY)).hexdigest()
contrib/sessions/models.py:16:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/models.py:59:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
core/management/commands/startproject.py:32:        # Create a random SECRET_KEY hash, and put it in the main settings.
core/management/commands/startproject.py:37:        settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
middleware/csrf.py:38:                % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
middleware/csrf.py:41:    return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()

It is used for making hashes. Look:

>grep -Inr SECRET_KEY *
conf/global_settings.py:255:SECRET_KEY = ''
conf/project_template/settings.py:61:SECRET_KEY = ''
contrib/auth/tokens.py:54:        hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
contrib/comments/forms.py:86:        info = (content_type, object_pk, timestamp, settings.SECRET_KEY)
contrib/formtools/utils.py:15:    order, pickles the result with the SECRET_KEY setting, then takes an md5
contrib/formtools/utils.py:32:    data.append(settings.SECRET_KEY)
contrib/messages/storage/cookie.py:112:        SECRET_KEY, modified to make it unique for the present purpose.
contrib/messages/storage/cookie.py:114:        key = 'django.contrib.messages' + settings.SECRET_KEY
contrib/sessions/backends/base.py:89:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/backends/base.py:95:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
contrib/sessions/backends/base.py:134:        # Use settings.SECRET_KEY as added salt.
contrib/sessions/backends/base.py:143:                       settings.SECRET_KEY)).hexdigest()
contrib/sessions/models.py:16:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/models.py:59:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
core/management/commands/startproject.py:32:        # Create a random SECRET_KEY hash, and put it in the main settings.
core/management/commands/startproject.py:37:        settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
middleware/csrf.py:38:                % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
middleware/csrf.py:41:    return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()

回答 1

用于加密签名Django文档介绍了“ SECRET_KEY”设置的用法:

此值[ SECRET_KEY设置]是保护​​签名数据的关键-务必确保此安全性,否则攻击者可能会使用它来生成自己的签名值。

对于SECRET_KEY设置,也从Django文档中引用此部分。)

Django中的加密签名API可供任何应用程序用于值的加密安全签名。Django本身在各种高级功能中使用了此功能:

  • 签名序列化数据(例如JSON文档)。

  • 用户会话,密码重置请求,消息等的唯一令牌。

  • 通过添加(然后期望)请求的唯一值来防止跨站点或重放攻击。

  • 为哈希函数生成唯一的盐。

因此,通常的答案是:Django应用程序中有很多东西需要加密签名,而“ SECRET_KEY”设置是用于这些目的的密钥。它需要具有密码学上很强的熵(计算机难以猜测),并且在所有Django实例之间都是唯一的。

The Django documentation for cryptographic signing covers the uses of the ‘SECRET_KEY’ setting:

This value [the SECRET_KEY setting] is the key to securing signed data – it is vital you keep this secure, or attackers could use it to generate their own signed values.

(This section is also referenced from the Django documentation for the ‘SECRET_KEY’ setting.)

The cryptographic signing API in Django is available to any app for cryptographically-secure signatures on values. Django itself makes use of this in various higher-level features:

  • Signing serialised data (e.g. JSON documents).

  • Unique tokens for a user session, password reset request, messages, etc.

  • Prevention of cross-site or replay attacks by adding (and then expecting) unique values for the request.

  • Generating a unique salt for hash functions.

So, the general answer is: There are many things in a Django app which require a cryptographic signature, and the ‘SECRET_KEY’ setting is the key used for those. It needs to have a cryptographically strong amount of entropy (hard for computers to guess) and unique between all Django instances.


回答 2

根据上的Django文档SECRET_KEY

密钥用于:

  • 如果您使用的会话后端不是django.contrib.sessions.backends.cache或使用默认会话,则所有会话get_session_auth_hash()
  • 如果使用CookieStorage或,则显示所有消息FallbackStorage
  • 所有PasswordResetView令牌。
  • 加密签名的任何用法,除非提供了不同的密钥。

如果旋转密钥,则以上所有内容都会失效。秘密密钥不用于用户密码,密钥旋转不会影响它们。

According to the Django Documentation on SECRET_KEY:

The secret key is used for:

  • All sessions if you are using any other session backend than django.contrib.sessions.backends.cache, or are using the default get_session_auth_hash().
  • All messages if you are using CookieStorage or FallbackStorage.
  • All PasswordResetView tokens.
  • Any usage of cryptographic signing, unless a different key is provided.

If you rotate your secret key, all of the above will be invalidated. Secret keys are not used for passwords of users and key rotation will not affect them.


错误:“字典更新序列元素#0的长度为1;在Django 1.4上需要2

问题:错误:“字典更新序列元素#0的长度为1;在Django 1.4上需要2

我在django 1.4上收到一条错误消息:

字典更新序列元素#0的长度为1;2个为必填项

[编辑]

当我尝试使用模板标签时发生了这种情况:`{%for v in values%}:

dictionary update sequence element #0 has length 1; 2 is required

Request Method:     GET
Request URL:    ...
Django Version:     1.4.5
Exception Type:     ValueError
Exception Value:    

dictionary update sequence element #0 has length 1; 2 is required

Exception Location:     /usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __init__, line 21
Python Executable:  /usr/bin/uwsgi-core
Python Version:     2.7.3
Python Path:    

['/var/www/',
 '.',
 '',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-linux2',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages/PIL',
 '/usr/lib/pymodules/python2.7']

Server time:    sam, 13 Jul 2013 16:15:45 +0200
Error during template rendering

In template /var/www/templates/app/index.html, error at line 172
dictionary update sequence element #0 has length 1; 2 is required

172     {% for product in products %}

Traceback Switch to copy-and-paste view

/usr/lib/python2.7/dist-packages/django/core/handlers/base.py in get_response

                            response = callback(request, *callback_args, **callback_kwargs)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/contrib/auth/decorators.py in _wrapped_view

                    return view_func(request, *args, **kwargs)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/views/decorators/http.py in inner

                return func(request, *args, **kwargs)

    ...
 Local vars
./app/views.py in index

            context_instance=RequestContext(request))

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/shortcuts/__init__.py in render_to_response

        return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/loader.py in render_to_string

            return t.render(context_instance)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                return self._render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in _render

            return self.nodelist.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/loader_tags.py in render

            return compiled_parent._render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in _render

            return self.nodelist.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/loader_tags.py in render

                result = block.nodelist.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/template/defaulttags.py in render

            len_values = len(values)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/core/paginator.py in __len__

            return len(self.object_list)

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/db/models/query.py in __len__

                    self._result_cache = list(self.iterator())

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/db/models/query.py in iterator

                        obj = model(*row[index_start:aggregate_start])

    ...
 Local vars
/usr/lib/python2.7/dist-packages/django/db/models/base.py in __init__

                    setattr(self, field.attname, val)

    ...
 Local vars
/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __set__

                value = self.field._attribute_class(value, self.field, obj)

    ...
 Local vars
/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __init__

            super(HStoreDictionary, self).__init__(value, **params)

    ...
 Local vars

当我尝试访问hstore queryset时,也会发生这种情况:

[编辑]

Traceback (most recent call last):
File "manage.py", line 14, in <module>
    execute_manager(settings)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 459, in execute_manager
    utility.execute()

File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)

File "/home/name/workspace/project/app/data/commands/my_command.py", line 60, in handle
    item_id = tmp[0].id,

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 207, in __getitem__
    return list(qs)[0]

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 87, in __len__
    self._result_cache.extend(self._iter)

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 301, in iterator
    obj = model(*row[index_start:aggregate_start])

File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 300, in __init__
    setattr(self, field.attname, val)

File "/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py", line 38, in __set__
    value = self.field._attribute_class(value, self.field, obj)

File "/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py", line 21, in __init__
    super(HStoreDictionary, self).__init__(value, **params)

ValueError: dictionary update sequence element #0 has length 1; 2 is required

代码是:

tmp = Item.objects.where(HE("kv").contains({'key':value}))

if tmp.count() > 0:

    item_id = tmp[0].id,

我只是在尝试获取价值。我不理解“更新顺序”消息。当我使用游标而不是hstore queryset时,该函数有效。错误也来自模板渲染。我刚刚重新启动uwsgi,一切正常,但是稍后又返回了错误。

[编辑]

有人知道吗?

I have an error message on django 1.4:

dictionary update sequence element #0 has length 1; 2 is required

[EDIT]

It happened when I tried using a template tag like: `{% for v in values %}:

dictionary update sequence element #0 has length 1; 2 is required

Request Method:     GET
Request URL:    ...
Django Version:     1.4.5
Exception Type:     ValueError
Exception Value:    

dictionary update sequence element #0 has length 1; 2 is required

Exception Location:     /usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __init__, line 21
Python Executable:  /usr/bin/uwsgi-core
Python Version:     2.7.3
Python Path:    

['/var/www/',
 '.',
 '',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-linux2',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages/PIL',
 '/usr/lib/pymodules/python2.7']

Server time:    sam, 13 Jul 2013 16:15:45 +0200
Error during template rendering

In template /var/www/templates/app/index.html, error at line 172
dictionary update sequence element #0 has length 1; 2 is required

172     {% for product in products %}

Traceback Switch to copy-and-paste view

/usr/lib/python2.7/dist-packages/django/core/handlers/base.py in get_response

                            response = callback(request, *callback_args, **callback_kwargs)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/contrib/auth/decorators.py in _wrapped_view

                    return view_func(request, *args, **kwargs)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/views/decorators/http.py in inner

                return func(request, *args, **kwargs)

    ...
▶ Local vars
./app/views.py in index

            context_instance=RequestContext(request))

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/shortcuts/__init__.py in render_to_response

        return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/loader.py in render_to_string

            return t.render(context_instance)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                return self._render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in _render

            return self.nodelist.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/loader_tags.py in render

            return compiled_parent._render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in _render

            return self.nodelist.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/loader_tags.py in render

                result = block.nodelist.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/base.py in render

                    bit = self.render_node(node, context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/debug.py in render_node

                return node.render(context)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/template/defaulttags.py in render

            len_values = len(values)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/core/paginator.py in __len__

            return len(self.object_list)

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/db/models/query.py in __len__

                    self._result_cache = list(self.iterator())

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/db/models/query.py in iterator

                        obj = model(*row[index_start:aggregate_start])

    ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/db/models/base.py in __init__

                    setattr(self, field.attname, val)

    ...
▶ Local vars
/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __set__

                value = self.field._attribute_class(value, self.field, obj)

    ...
▶ Local vars
/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py in __init__

            super(HStoreDictionary, self).__init__(value, **params)

    ...
▶ Local vars

It happens too when I try to access on a hstore queryset:

[edit]

Traceback (most recent call last):
File "manage.py", line 14, in <module>
    execute_manager(settings)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 459, in execute_manager
    utility.execute()

File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)

File "/home/name/workspace/project/app/data/commands/my_command.py", line 60, in handle
    item_id = tmp[0].id,

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 207, in __getitem__
    return list(qs)[0]

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 87, in __len__
    self._result_cache.extend(self._iter)

File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 301, in iterator
    obj = model(*row[index_start:aggregate_start])

File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 300, in __init__
    setattr(self, field.attname, val)

File "/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py", line 38, in __set__
    value = self.field._attribute_class(value, self.field, obj)

File "/usr/local/lib/python2.7/dist-packages/djorm_hstore/fields.py", line 21, in __init__
    super(HStoreDictionary, self).__init__(value, **params)

ValueError: dictionary update sequence element #0 has length 1; 2 is required

the code is:

tmp = Item.objects.where(HE("kv").contains({'key':value}))

if tmp.count() > 0:

    item_id = tmp[0].id,

I’m just trying to access the value. I don’t understand the “update sequence” message. When I use a cursor instead of hstore queryset, the function works. The error comes on template rendering too. I just restarted uwsgi and everything works well, but the error comes back later.

[edit]

Has someone an idea?


回答 0

刚遇到这个问题。我不知道是不是碰到了您的代码,但是对我而言,根本原因是因为我忘记name=url(或path在Django 2.0+中)函数调用的最后一个参数。

例如,以下函数引发问题中的错误:

url(r'^foo/(?P<bar>[A-Za-z]+)/$', views.FooBar.as_view(), 'foo')
path('foo/{slug:bar}/', views.FooBar, 'foo')

但是这些实际上有效:

url(r'^foo/(?P<bar>[A-Za-z]+)/$', views.FooBar.as_view(), name='foo')
path('foo/{slug:bar}/', views.FooBar, name='foo')

回溯之所以无济于事,是因为Django在内部希望将给定的位置参数解析为关键字 arguments kwargs,并且由于字符串是可迭代的,因此非典型代码路径开始展开。始终name=在您的网址上使用!

Just ran into this problem. I don’t know if it’s the same thing that hit your code, but for me the root cause was because I forgot to put name= on the last argument of the url (or path in Django 2.0+) function call.

For instance, the following functions throw the error from the question:

url(r'^foo/(?P<bar>[A-Za-z]+)/$', views.FooBar.as_view(), 'foo')
path('foo/{slug:bar}/', views.FooBar, 'foo')

But these actually work:

url(r'^foo/(?P<bar>[A-Za-z]+)/$', views.FooBar.as_view(), name='foo')
path('foo/{slug:bar}/', views.FooBar, name='foo')

The reason why the traceback is unhelpful is because internally, Django wants to parse the given positional argument as the keyword argument kwargs, and since a string is an iterable, an atypical code path begins to unfold. Always use name= on your urls!


回答 1

我在弄乱字符串和字典时遇到了这个错误。

dict1 = {'taras': 'vaskiv', 'iruna': 'vaskiv'}
str1 = str(dict1)
dict(str1)
*** ValueError: dictionary update sequence element #0 has length 1; 2 is required

因此,您实际上要做的是从字符串中获取字典:

dic2 = eval(str1)
dic2
{'taras': 'vaskiv', 'iruna': 'vaskiv'}

或者出于安全考虑,我们可以使用literal_eval

from ast import literal_eval

I got this error when I was messing around with string and dictionary.

dict1 = {'taras': 'vaskiv', 'iruna': 'vaskiv'}
str1 = str(dict1)
dict(str1)
*** ValueError: dictionary update sequence element #0 has length 1; 2 is required

So what you actually got to do to get dict from string is:

dic2 = eval(str1)
dic2
{'taras': 'vaskiv', 'iruna': 'vaskiv'}

Or in matter of security we can use literal_eval

from ast import literal_eval

回答 2

尝试执行以下操作时,将引发问题错误:

>>> a_dictionary = {}
>>> a_dictionary.update([[1]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required

除非显示完整的追溯代码,否则很难说出代码中的原因。

Error in your question is raised when you try something like following:

>>> a_dictionary = {}
>>> a_dictionary.update([[1]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required

It’s hard to tell where is the cause in your code unless you show your code, full traceback.


回答 3

当我忘记将关键字参数名称传递给url()函数时,我遇到了上述问题。

错误代码

 url(r"^testing/$", views.testing, "testing")

代码无错误

url(r"^testing/$", views.testing, name="testing")

所以最后我以这种方式消除了上面的错误。您的情况可能有所不同。因此,请在urls.py中检查您的网址格式。

I faced the above mentioned problem when I forgot to pass a keyword argument name to url() function.

Code with error

 url(r"^testing/$", views.testing, "testing")

Code without error

url(r"^testing/$", views.testing, name="testing")

So finally I removed the above error in this way. It might be something different in your case. So check your url patterns in urls.py.


回答 4

解”

将关键字参数名称(其值作为视图名称)传递给例如homehome-view等。url()的功能。

引发错误»

url(r'^home$', 'common.views.view1', 'home'),

正确”

url(r'^home$', 'common.views.view1', name='home'),

Solution»

Pass a keyword argument name with value as your view name e.g home or home-view etc. to url() function.

Throws Error»

url(r'^home$', 'common.views.view1', 'home'),

Correct»

url(r'^home$', 'common.views.view1', name='home'),


回答 5

这是重现的错误。

>>> d = {}
>>> d.update([(1,)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required
>>> 
>>> d
{}
>>> 
>>> d.update([(1, 2)])
>>> d
{1: 2}
>>> 
>>> d.update('hello_some_string')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>  
ValueError: dictionary update sequence element #0 has length 1; 2 is required
>>> 

如果给定序列,并且任何元素长度为1且需要两个,那么我们将得到这种错误。参见上面的代码。第一次给序列赋予元组,其长度为1,那么我们得到了错误并且字典没有更新。第二次我给内部元组添加了两个元素,字典得到了更新。

Here is the reproduced error.

>>> d = {}
>>> d.update([(1,)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required
>>> 
>>> d
{}
>>> 
>>> d.update([(1, 2)])
>>> d
{1: 2}
>>> 
>>> d.update('hello_some_string')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>  
ValueError: dictionary update sequence element #0 has length 1; 2 is required
>>> 

If you give the sequence and any element length is 1 and required two then we will get this kind of error. See the above code. First time I gave the sequence with tuple and it’s length 1, then we got the error and dictionary is not updated. second time I gave inside tuple with with two elements, dictionary got updated.


回答 6

我遇到了同样的问题,发现这是由于参数错误造成的。在中views.py,我使用了:

return render(request, 'demo.html',{'items', items})    

但我发现了问题:{'items', items}。进行更改以{'items': items}解决问题。

I got the same issue and found that it was due to wrong parameters. In views.py, I used:

return render(request, 'demo.html',{'items', items})    

But I found the issue: {'items', items}. Changing to {'items': items} resolved the issue.


回答 7

就我而言,我get_context_data的观点之一是return render(self.request, 'es_connection_error.html', {'error':error});在try / catch块中返回而不是返回context

In my case, my get_context_data in one of my views was returning return render(self.request, 'es_connection_error.html', {'error':error}); in a try/catch block instead of returning context


回答 8

错误应该与参数有关。请验证params是否为字典对象。如果只是参数列表/元组,则仅使用一个*(*params)而不是两个*(**params)。这会将列表/元组爆炸为适当数量的参数。

或者,如果参数来自代码的其他部分作为JSON文件,请这样做json.loads(params),因为JSON对象有时表现为字符串,因此您需要使用来自字符串的负载(负载)将其作为JSON。

super(HStoreDictionary, self).__init__(value, **params)

希望这可以帮助!

The error should be with the params. Please verify that the params is a dictionary object. If it is just a list/tuple of arguments use only one * (*params) instead of two * (**params). This will explode the list/tuple into the proper amount of arguments.

Or, if the params is coming from some other part of code as a JSON file, please do json.loads(params), because the JSON objects sometimes behave as string and so you need to make it as a JSON using load from string (loads).

super(HStoreDictionary, self).__init__(value, **params)

Hope this helps!


回答 9

尝试使用错误类型的参数调用update方法时遇到此问题。预期的结果是:

{'foo': True}

通过的是:

{'foo': "True"}

确保您检查传递的所有参数均为预期类型。

I encountered this issue when trying to invoke the update method with a parameter of a wrong type. The expected dict was:

{'foo': True}

The one that was passed was:

{'foo': "True"}

make sure you check all the parameters you pass are of the expected type.


回答 10

您发送的参数不正确;它应该是dictionary object

  • 错误: func(a=r)

  • 正确: func(a={'x':y})

You are sending one parameter incorrectly; it should be a dictionary object:

  • Wrong: func(a=r)

  • Correct: func(a={'x':y})


回答 11

我也有类似的问题。解决方法很简单。只是不要尝试在值中输入NULL或None值,否则您可能必须使用类似这样的东西
dic.update([(key,value)])

I too had a similar type of problem . The solution is simple . just dont try to enter NULL or None value in values or u might have to use Something like this
dic.update([(key,value)])


如何在Django模板中获取网站的域名?

问题:如何在Django模板中获取网站的域名?

如何从Django模板中获取当前站点的域名?我试着寻找标签和过滤器,但那里什么也没有。

How do I get the domain name of my current site from within a Django template? I’ve tried looking in the tag and filters but nothing there.


回答 0

我认为您想要的是可以访问请求上下文,请参见RequestContext。

I think what you want is to have access to the request context, see RequestContext.


回答 1

如果需要实际的HTTP Host标头,请参阅Daniel Roseman对@Phsiao答案的评论。另一种选择是,如果您使用的是contrib.sites框架,则可以在数据库中为站点设置一个规范域名(将请求域映射到具有正确SITE_ID的设置文件中,这是您必须通过自己的网络服务器设置)。在这种情况下,您要寻找:

from django.contrib.sites.models import Site

current_site = Site.objects.get_current()
current_site.domain

如果要使用current_site对象,则必须自己将其放在模板上下文中。如果您在各处使用它,则可以将其打包在模板上下文处理器中。

If you want the actual HTTP Host header, see Daniel Roseman’s comment on @Phsiao’s answer. The other alternative is if you’re using the contrib.sites framework, you can set a canonical domain name for a Site in the database (mapping the request domain to a settings file with the proper SITE_ID is something you have to do yourself via your webserver setup). In that case you’re looking for:

from django.contrib.sites.models import Site

current_site = Site.objects.get_current()
current_site.domain

you’d have to put the current_site object into a template context yourself if you want to use it. If you’re using it all over the place, you could package that up in a template context processor.


回答 2

我发现了{{ request.get_host }}方法。

I’ve discovered the {{ request.get_host }} method.


回答 3

作为对Carl Meyer的补充,您可以像这样创建一个上下文处理器:

module.context_processors.py

from django.conf import settings

def site(request):
    return {'SITE_URL': settings.SITE_URL}

本地settings.py

SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

返回上下文实例的模板,URL站点为{{SITE_URL}}

如果要在上下文处理器中处理子域或SSL,则可以编写自己的例程。

Complementing Carl Meyer, you can make a context processor like this:

module.context_processors.py

from django.conf import settings

def site(request):
    return {'SITE_URL': settings.SITE_URL}

local settings.py

SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

templates returning context instance the url site is {{ SITE_URL }}

you can write your own rutine if want to handle subdomains or SSL in the context processor.


回答 4

我使用的上下文处理器的变体是:

from django.contrib.sites.shortcuts import get_current_site
from django.utils.functional import SimpleLazyObject


def site(request):
    return {
        'site': SimpleLazyObject(lambda: get_current_site(request)),
    }

SimpleLazyObject包装可以确保DB调用只有当模板实际使用情况site的对象。这将从管理页面中删除查询。它还缓存结果。

并将其包含在设置中:

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
)

在模板中,您可以{{ site.domain }}用来获取当前域名。

编辑:也要支持协议切换,请使用:

def site(request):
    site = SimpleLazyObject(lambda: get_current_site(request))
    protocol = 'https' if request.is_secure() else 'http'

    return {
        'site': site,
        'site_root': SimpleLazyObject(lambda: "{0}://{1}".format(protocol, site.domain)),
    }

The variation of the context processor I use is:

from django.contrib.sites.shortcuts import get_current_site
from django.utils.functional import SimpleLazyObject


def site(request):
    return {
        'site': SimpleLazyObject(lambda: get_current_site(request)),
    }

The SimpleLazyObject wrapper makes sure the DB call only happens when the template actually uses the site object. This removes the query from the admin pages. It also caches the result.

and include it in the settings:

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
)

In the template, you can use {{ site.domain }} to get the current domain name.

edit: to support protocol switching too, use:

def site(request):
    site = SimpleLazyObject(lambda: get_current_site(request))
    protocol = 'https' if request.is_secure() else 'http'

    return {
        'site': site,
        'site_root': SimpleLazyObject(lambda: "{0}://{1}".format(protocol, site.domain)),
    }

回答 5

我知道这个问题很老,但是我偶然发现了这个问题,寻找一种获取当前域的pythonic方法。

def myview(request):
    domain = request.build_absolute_uri('/')[:-1]
    # that will build the complete domain: http://foobar.com

I know this question is old, but I stumbled upon it looking for a pythonic way to get current domain.

def myview(request):
    domain = request.build_absolute_uri('/')[:-1]
    # that will build the complete domain: http://foobar.com

回答 6

快速简单,但不适用于生产:

(在视图中)

    request.scheme               # http or https
    request.META['HTTP_HOST']    # example.com
    request.path                 # /some/content/1/

(在模板中)

{{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }}

确保使用RequestContext,如果使用render,就是这种情况。

不要相信request.META['HTTP_HOST']生产:该信息来自浏览器。而是使用@CarlMeyer的答案

Quick and simple, but not good for production:

(in a view)

    request.scheme               # http or https
    request.META['HTTP_HOST']    # example.com
    request.path                 # /some/content/1/

(in a template)

{{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }}

Be sure to use a RequestContext, which is the case if you’re using render.

Don’t trust request.META['HTTP_HOST'] in production: that info comes from the browser. Instead, use @CarlMeyer’s answer


回答 7

{{ request.get_host }}ALLOWED_HOSTS设置(在Django 1.4.4中添加)一起使用时,应该可以防止HTTP Host标头攻击。

请注意,{{ request.META.HTTP_HOST }}没有相同的保护。见文档

ALLOWED_HOSTS

代表此Django站点可以服务的主机/域名的字符串列表。这是一种安全措施,可以防止HTTP Host标头攻击,即使在许多看似安全的Web服务器配置下也可能发生这种攻击

…如果Host标头(或者X-Forwarded-Host如果USE_X_FORWARDED_HOST使能)不匹配,在此列表中的任何值,该django.http.HttpRequest.get_host()方法将提高SuspiciousOperation

…此验证仅通过进行get_host();如果您的代码直接从request.META您访问Host标头,则绕过此安全保护措施。


至于request在模板中使用,在Django 1.8中,模板渲染函数调用已更改,因此您不再需要RequestContext直接处理。

这是使用快捷功能为视图渲染模板的方法render()

from django.shortcuts import render

def my_view(request):
    ...
    return render(request, 'my_template.html', context)

这是呈现电子邮件模板的方法,在您需要主机值的情况下,IMO是最常见的情况:

from django.template.loader import render_to_string

def my_view(request):
    ...
    email_body = render_to_string(
        'my_template.txt', context, request=request)

这是在电子邮件模板中添加完整URL的示例;request.scheme应该获得httphttps取决于您使用的是什么:

Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}

{{ request.get_host }} should protect against HTTP Host header attacks when used together with the ALLOWED_HOSTS setting (added in Django 1.4.4).

Note that {{ request.META.HTTP_HOST }} does not have the same protection. See the docs:

ALLOWED_HOSTS

A list of strings representing the host/domain names that this Django site can serve. This is a security measure to prevent HTTP Host header attacks, which are possible even under many seemingly-safe web server configurations.

… If the Host header (or X-Forwarded-Host if USE_X_FORWARDED_HOST is enabled) does not match any value in this list, the django.http.HttpRequest.get_host() method will raise SuspiciousOperation.

… This validation only applies via get_host(); if your code accesses the Host header directly from request.META you are bypassing this security protection.


As for using the request in your template, the template-rendering function calls have changed in Django 1.8, so you no longer have to handle RequestContext directly.

Here’s how to render a template for a view, using the shortcut function render():

from django.shortcuts import render

def my_view(request):
    ...
    return render(request, 'my_template.html', context)

Here’s how to render a template for an email, which IMO is the more common case where you’d want the host value:

from django.template.loader import render_to_string

def my_view(request):
    ...
    email_body = render_to_string(
        'my_template.txt', context, request=request)

Here’s an example of adding a full URL in an email template; request.scheme should get http or https depending on what you’re using:

Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}

回答 8

我使用自定义模板标签。添加到例如<your_app>/templatetags/site.py

# -*- coding: utf-8 -*-
from django import template
from django.contrib.sites.models import Site

register = template.Library()

@register.simple_tag
def current_domain():
    return 'http://%s' % Site.objects.get_current().domain

在这样的模板中使用它:

{% load site %}
{% current_domain %}

I use a custom template tag. Add to e.g. <your_app>/templatetags/site.py:

# -*- coding: utf-8 -*-
from django import template
from django.contrib.sites.models import Site

register = template.Library()

@register.simple_tag
def current_domain():
    return 'http://%s' % Site.objects.get_current().domain

Use it in a template like this:

{% load site %}
{% current_domain %}

回答 9

与用户panchicore的回复类似,这是我在一个非常简单的网站上所做的。它提供了一些变量并使它们在模板上可用。

SITE_URL将举行一个类似的值example.com
SITE_PROTOCOL将举行类似的值httphttps
SITE_PROTOCOL_URL将举行类似的值http://example.comhttps://example.com
SITE_PROTOCOL_RELATIVE_URL将持有的值等//example.com

module / context_processors.py

from django.conf import settings

def site(request):

    SITE_PROTOCOL_RELATIVE_URL = '//' + settings.SITE_URL

    SITE_PROTOCOL = 'http'
    if request.is_secure():
        SITE_PROTOCOL = 'https'

    SITE_PROTOCOL_URL = SITE_PROTOCOL + '://' + settings.SITE_URL

    return {
        'SITE_URL': settings.SITE_URL,
        'SITE_PROTOCOL': SITE_PROTOCOL,
        'SITE_PROTOCOL_URL': SITE_PROTOCOL_URL,
        'SITE_PROTOCOL_RELATIVE_URL': SITE_PROTOCOL_RELATIVE_URL
    }

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

SITE_URL = 'example.com'

然后,在你的模板,把它们作为{{ SITE_URL }}{{ SITE_PROTOCOL }}{{ SITE_PROTOCOL_URL }}{{ SITE_PROTOCOL_RELATIVE_URL }}

Similar to user panchicore’s reply, this is what I did on a very simple website. It provides a few variables and makes them available on the template.

SITE_URL would hold a value like example.com
SITE_PROTOCOL would hold a value like http or https
SITE_PROTOCOL_URL would hold a value like http://example.com or https://example.com
SITE_PROTOCOL_RELATIVE_URL would hold a value like //example.com.

module/context_processors.py

from django.conf import settings

def site(request):

    SITE_PROTOCOL_RELATIVE_URL = '//' + settings.SITE_URL

    SITE_PROTOCOL = 'http'
    if request.is_secure():
        SITE_PROTOCOL = 'https'

    SITE_PROTOCOL_URL = SITE_PROTOCOL + '://' + settings.SITE_URL

    return {
        'SITE_URL': settings.SITE_URL,
        'SITE_PROTOCOL': SITE_PROTOCOL,
        'SITE_PROTOCOL_URL': SITE_PROTOCOL_URL,
        'SITE_PROTOCOL_RELATIVE_URL': SITE_PROTOCOL_RELATIVE_URL
    }

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

SITE_URL = 'example.com'

Then, on your templates, use them as {{ SITE_URL }}, {{ SITE_PROTOCOL }}, {{ SITE_PROTOCOL_URL }} and {{ SITE_PROTOCOL_RELATIVE_URL }}


回答 10

在Django模板中,您可以执行以下操作:

<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>

In a Django template you can do:

<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>

回答 11

如果您使用“请求”上下文处理器,并且正在使用Django sites框架,并且安装了Site中间件(即您的设置包括以下内容):

INSTALLED_APPS = [
    ...
    "django.contrib.sites",
    ...
]

MIDDLEWARE = [
    ...
     "django.contrib.sites.middleware.CurrentSiteMiddleware",
    ...
]

TEMPLATES = [
    {
        ...
        "OPTIONS": {
            "context_processors": [
                ...
                "django.template.context_processors.request",
                ...
            ]
        }
    }
]

…然后您将request在模板中使用该对象,并且该对象将包含对当前Site请求的引用request.site。然后,您可以使用以下模板在模板中检索域:

    {{request.site.domain}}

If you use the “request” context processor, and are using the Django sites framework, and have the Site middleware installed (i.e. your settings include these):

INSTALLED_APPS = [
    ...
    "django.contrib.sites",
    ...
]

MIDDLEWARE = [
    ...
     "django.contrib.sites.middleware.CurrentSiteMiddleware",
    ...
]

… then you will have the request object available in templates, and it will contain a reference to the current Site for the request as request.site. You can then retrieve the domain in a template with:

    {{request.site.domain}}

and the site name with:

    {{request.site.name}}

回答 12

那这种方法呢?为我工作。它也用于django-registration中

def get_request_root_url(self):
    scheme = 'https' if self.request.is_secure() else 'http'
    site = get_current_site(self.request)
    return '%s://%s' % (scheme, site)

What about this approach? Works for me. It is also used in django-registration.

def get_request_root_url(self):
    scheme = 'https' if self.request.is_secure() else 'http'
    site = get_current_site(self.request)
    return '%s://%s' % (scheme, site)

回答 13

from django.contrib.sites.models import Site
if Site._meta.installed:
    site = Site.objects.get_current()
else:
    site = RequestSite(request)
from django.contrib.sites.models import Site
if Site._meta.installed:
    site = Site.objects.get_current()
else:
    site = RequestSite(request)

回答 14

您可以{{ protocol }}://{{ domain }}在模板中使用来获取域名。

You can use {{ protocol }}://{{ domain }} in your templates to get your domain name.