Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django tastypie需要一个递归CSV序列化程序_Python_Django_Csv_Serialization_Tastypie - Fatal编程技术网

Python Django tastypie需要一个递归CSV序列化程序

Python Django tastypie需要一个递归CSV序列化程序,python,django,csv,serialization,tastypie,Python,Django,Csv,Serialization,Tastypie,我已经使用tastypie为我的Django应用程序创建了一个简单的GET-only api。我需要提供平面表格CSV数据,但我的数据库结构是规范化的。我已经实现了一个定制的序列化程序类,其to_csv()方法如下 def to_csv(self, data, options=None): options = options or {} data = self.to_simple(data, options) raw_data = StringIO.StringIO()

我已经使用tastypie为我的Django应用程序创建了一个简单的GET-only api。我需要提供平面表格CSV数据,但我的数据库结构是规范化的。我已经实现了一个定制的
序列化程序
类,其
to_csv()
方法如下

def to_csv(self, data, options=None):
    options = options or {}
    data = self.to_simple(data, options)

    raw_data = StringIO.StringIO()
    writer = csv.writer(raw_data, quotechar="'", quoting=csv.QUOTE_NONNUMERIC)

    if "meta" in data.keys():#if multiple objects are returned
        objects = data.get("objects")
        writer.writerow(objects[0].keys())

        for object in objects:
            test = object.values()
            writer.writerow(test)
    else:
        writer.writerow(data.values())

    CSVContent=raw_data.getvalue()
    return CSVContent
这非常有效,除了默认情况下将任何资源呈现为JSON(当我在ModelResource ForeignKey规范中包含
full=True
时),因此我最终得到了包含嵌套JSON数据的CSV数据,这些数据如下所示

foodID,foodName,related_details
1,"apricot","{'type':'fruit', 'cost':'medium'}"
2,"beef","{'type':'animal', 'cost':'high'}"
3,"celery","{'type':'vegetable', 'cost':'low'}"
我期望的输出是

foodID,foodName,type,cost
1,"apricot","fruit","medium"
2,"beef","animal","high"
3,"celery","vegetable","low"

我有一个想法,我需要递归地应用我的序列化程序,然后在写入CSV之前合并结果,但到目前为止还没有成功

您可以使用以下功能
列出您拥有的每一行:

def to_csv(self, data, options=None):
    options = options or {}
    data = self.to_simple(data, options)

    raw_data = StringIO.StringIO()
    first = True

    if "meta" in data.keys():#if multiple objects are returned
        objects = data.get("objects")

        for value in objects:
            test = {}
            self.flatten(value, test)
            if first:
                writer = csv.DictWriter(raw_data, test.keys(), quotechar="'", quoting=csv.QUOTE_NONNUMERIC)
                writer.writeheader()
                writer.writerow(test)
                first=False
            else:
                writer.writerow(test)
    else:
        test = {}
        self.flatten(data, test)
        if first:
            writer = csv.DictWriter(raw_data, test.keys(), quotechar="'", quoting=csv.QUOTE_NONNUMERIC)
            writer.writeheader()
            writer.writerow(test)
            first=False
        else:
            writer.writerow(test)
    CSVContent=raw_data.getvalue()
    return CSVContent

def flatten(self, data, odict = {}):
    if isinstance(data, list):
        for value in data:
            self.flatten(value, odict)
    elif isinstance(data, dict):
        for (key, value) in data.items():
            if not isinstance(value, (dict, list)):
                odict[key] = value
            else:
                self.flatten(value, odict)
def to_list(line):
    idx = -1
    for i, l in enumerate(line):
        if type(l) is str and '{' in l and '}' in l:
            idx = i
            break
    if idx != -1:
        result = line[:idx] + eval(line[idx]).values() + line[idx+1:]
    else:
        result = line
    return result

if __name__ == "__main__":
    lst = [[1,"apricot","{'type':'fruit', 'cost':'medium'}"],
           ["beef","{'type':'animal', 'cost':'high'}", 3],
           ["meat", "sugar"],
           ["{'type':'car', 'cost':'nothing'}", "something"]]
    for line in lst:
        print to_list(line)
因此,对于以下列表:

1, "apricot", "{'type':'fruit', 'cost':'medium'}"
"beef", "{'type':'animal', 'cost':'high'}", 3
"meat", "sugar"
"{'type':'car', 'cost':'nothing'}", "something"
您将获得:

1, 'apricot', 'medium', 'fruit'
'beef', 'high', 'animal', 3
'meat', 'sugar'
'nothing', 'car', 'something'

正如您所见,它既不取决于元素的数量,也不取决于JSON字符串的位置。

您是否在寻找一些代码来转换第三个元素,例如:lambda函数中的
line[:2]+eval(line[2]).values()
?这听起来很有希望,但我对lambda函数一无所知。它需要是一般性的,在某种意义上,我不想假设它总是行中需要转换的第三个元素,因为不同的模型有不同的外键。所以首先需要检测它是JSON,然后应用转换。我认为使用
DictWriter
会更好。“我设想的是无序数据。@安德鲁·巴尔关于您的需求,我认为lambda函数不匹配。我在下面的回答中向您推荐了一个更通用的函数,它不依赖于JSON字符串的位置,也不依赖于元素的数量!非常感谢。当我明天尝试时,我一定会让你知道它是如何工作的/接受答案。在我调整它之后,它工作了。我提交了一个答案的编辑,在展平后的第一次迭代中获得标题值(字典键)。