假设我有三个django模型:
class Section(models.Model):
name = models.CharField()
class Size(models.Model):
section = models.ForeignKey(Section)
size = models.IntegerField()
class Obj(models.Model):
name = models.CharField()
sizes = models.ManyToManyField(Size)
我想导入大量的Obj数据,其中许多大小的字段都是相同的。但是,由于Obj有一个ManyToMany字段,我不能像往常一样测试存在。我希望能够做到这样的事情:
try:
x = Obj(name='foo')
x.sizes.add(sizemodel1) # these can be looked up with get_or_create
...
x.sizes.add(sizemodelN) # these can be looked up with get_or_create
# Now test whether x already exists, so I don't add a duplicate
try:
Obj.objects.get(x)
except Obj.DoesNotExist:
x.save()
但是,我不知道以这种方式获取对象的方法,你必须传递关键字参数,这对于ManyToManyFields不起作用。
我能做到这一点有什么好办法吗?我唯一的想法就是建立一组Q对象来传递给:
myq = myq & Q(sizes__id=sizemodelN.id)
但我不确定这是否会奏效......
答案 0 :(得分:1)
使用直通模型,然后使用.get()。
http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships
一旦有了直通模型,就可以使用.get()或.filter()或.exists()来确定是否存在您可能想要创建的对象。请注意,.get()实际上适用于数据库强制执行唯一的列 - 您可能会出现更好的.exists()性能。
如果这是一个过于激进或不方便的解决方案,您也可以抓住ManyRelatedManager并迭代以确定该对象是否存在:
object_sizes = obj.sizes.all()
exists = object_sizes.filter(id__in = some_bunch_of_size_object_ids_you_are_curious_about).exists()
if not exists:
(your creation code here)
答案 1 :(得分:0)
您的示例没有多大意义,因为您无法在保存x
之前添加m2m关系,但它说明了您要做的很好。您有通过Size
创建的get_or_create()
个对象的列表,如果不存在重复的obj-size关系,您想要创建Obj
吗?
不幸的是,这很难做到。链接Q(id=F) & Q(id=O) & Q(id=O)
对m2m不起作用。
您当然可以使用Obj.objects.filter(size__in=Sizes)
,但这意味着您可以在一个庞大的尺寸列表中找到Obj
与1 size
的匹配。
Check out this post for an __in
exact question,马尔科姆回答,所以我相信它。
我为了好玩而写了一些python,可以解决这个问题 这是一次性导入权吗?
def has_exact_m2m_match(match_list):
"""
Get exact Obj m2m match
"""
if isinstance(match_list, QuerySet):
match_list = [x.id for x in match_list]
results = {}
match = set(match_list)
for obj, size in \
Obj.sizes.through.objects.filter(size__in=match).values_list('obj', 'size'):
# note: we are accessing the auto generated through model for the sizes m2m
try:
results[obj].append(size)
except KeyError:
results[obj] = [size]
return bool(filter(lambda x: set(x) == match, results.values()))
# filter any specific objects that have the exact same size IDs
# if there is a match, it means an Obj exists with exactly
# the sizes you provided to the function, no more.
sizes = [size1, size2, size3, sizeN...]
if has_exact_m2m_match(sizes):
x = Obj.objects.create(name=foo) # saves so you can use x.sizes.add
x.sizes.add(sizes)