2011-02-24 3 views
5

Предположим, у меня есть три Джанго модели:get_or_create модель Джанго с ManyToMany поле

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

Ваш пример не имеет особого смысла, потому что вы можете» t добавьте отношения m2m до того, как будет сохранен x, но он показал, что вы пытаетесь сделать довольно хорошо. У вас есть список Size объектов, созданных через get_or_create(), и хотите создать Obj, если дублирующихся отношений obj-size не существует?

К сожалению, это невозможно очень легко. Цепь 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) 
+0

Я в конечном счете скорректировал свою модель немного, чтобы уменьшить проблему, хотя фундаментальная проблема совпадения многих и многих моделей все еще существует. Я в конечном итоге импортировал данные в виде отдельных (дубликатов) записей. Я думаю, что я получил от ваших ответов и Джастина, что нет простого решения этого. Это заставляет меня полагать, что это действие необычно и, следовательно, вопрос, не могу ли я моделировать модели по-разному, чтобы вообще избежать этой проблемы. – djs

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) 
+0

Я смотрел на это, но я не уверен, что следую. В этом примере я бы создал модель «ObjSize» с внешними ключами «Obj» и «Size»? Разве я не придерживаюсь той же проблемы? – djs

+1

Ну, теперь вы можете сделать ObjSize.objects.get (obj = some_obj, size = sizemodel1) и тому подобное. – jMyles

+0

Это делает меня Obj, который содержит один размер, который я хочу, но мне нужен Obj, который содержит множество всех объектов размера, которые я указываю. – djs

Смежные вопросы