簡體   English   中英

使用ManyToMany字段get_or_create django模型

[英]get_or_create django model with ManyToMany field

假設我有三個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)

但我不確定這甚至會起作用......

使用直通模型,然后使用.get()。

http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

一旦有了直通模型,就可以使用.get()或.filter()或.exists()來確定是否存在您可能想要創建的對象。 請注意,.get()實際上適用於DB強制執行唯一的列 - 您可能會出於更好的性能使用.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)

你的例子沒有多大意義,因為在保存x之前你不能添加m2m關系,但它說明了你想要做的很好。 你有一個通過get_or_create()創建的Size對象列表,如果不存在重復的obj-size關系,你想創建一個Obj嗎?

不幸的是,這是不可能的。 鏈接Q(id=F) & Q(id=O) & Q(id=O)對m2m不起作用。

你當然可以使用Obj.objects.filter(size__in=Sizes)但這意味着你可以在一個龐大的大小列表中獲得一個具有1個sizeObj的匹配。

看看這個職位的__in准確的問題 ,由Malcolm回答,所以我相信它頗有幾分。

我寫了一些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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM