Django Natural Key for Fixtures Give Deserializati

2020-03-26 06:41发布

问题:

I've seen a few similar questions to this on SO, but none seem to answer my particular problem. I'm new to Django and was guiding myself by the instructions at this page to allow myself to use natural keys to load fixtures. Nevertheless, I'm getting Deserialization errors because Django wants an integer for a foreign key and can't seem to map my natural key to an integer primary key as is noted in the instructions. Specifically, my relevant models code is:

class GraphTypeManager(models.Manager):
    def get_by_natural_key(self, type):
        return self.get(type=type)
class GraphType(models.Model):
    type = models.CharField(max_length=100, unique=True)

class GraphManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name=name)
class Graph(models.Model):
    name = models.CharField(max_length=200, unique=True)
    type = models.ForeignKey(GraphType)

class LineManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name=name)
class Line(models.Model):
    name = models.CharField(max_length=200, unique=True)

class GraphToLineManager(models.Manager):
    def get_by_natural_key(self, line, graph):
        return self.get(line=line,graph=graph)
class GraphToLine(models.Model):
    line = models.ForeignKey(Line)
    graph = models.ForeignKey(Graph)
    class Meta:
        unique_together = (('line', "graph"),)

And my YAML fixture is:

- model: graphs_container.GraphType
  pk: null
  fields:
    type: TimeSeries
- model: graphs_container.Graph
  pk: null
  fields:
    name: LikesOverTime
    type: [TimeSeries]
- model: graphs_container.Graph
  pk: null
  fields:
    name: UsersOverTime
    type: [TimeSeries]
- model: graphs_container.Line
  pk: null
  fields:
    name: NumUsers
- model: graphs_container.Line
  pk: null
  fields:
    name: NumLikes

But when trying to run python manage.py loaddata sample_data.yaml, I get the following error:

DeserializationError: [u"'['TimeSeries']' value must be an integer."]

What am I doing wrong?

回答1:

You need to

  • define natural_key method in your models
  • have a manager with get_by_natural_key method
  • actually attach the managers (objects=GraphManager())

After playing with your code, I made it work:

class GraphTypeManager(models.Manager):
    def get_by_natural_key(self, type):
        return self.get(type=type)

class GraphType(models.Model):
    type = models.CharField(max_length=100, unique=True)
    objects = GraphTypeManager()

    def natural_key(self):
        return (self.type,)  # must return a tuple

class GraphManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name=name)

class Graph(models.Model):
    name = models.CharField(max_length=200, unique=True)
    type = models.ForeignKey(GraphType)
    objects = GraphManager()

Dumping the data:

$ bin/django dumpdata index --indent=4 --natural > project/apps/fixtures_dev/initial_data.json
[
    {
        "pk": 1,
        "model": "index.graphtype",
        "fields": {
            "type": "asotuh"
        }
    },
    {
        "pk": 1,
        "model": "index.graph",
        "fields": {
            "type": [
                "asotuh"
            ],
            "name": "saoneuht"
        }
    }
]

bin/django loaddata project/apps/fixtures_dev/initial_data.json 
Installed 2 object(s) from 1 fixture(s)