2012-04-09 13 views
7

Jestem nowy w django, a jako aplikacja do nauki buduję aplikację do rejestrowania wydatków.Kopiowanie pól ManyToMany z jednej instancji modelu na inną

W moim modelu mam trzech klas, które wyglądają tak (ja uprościć je lekko na zwięzłość):

class AbstractExpense(models.Model): 
    description = models.CharField(max_length=100) 
    amount  = models.IntegerField() 
    category = models.ForeignKey('Category') 
    tags  = models.ManyToManyField('Tag') 
    insert_date = models.DateTimeField(auto_now=True) 

    class Meta(object): 
     abstract = True 

class Expense(AbstractExpense): 
    date  = models.DateField('Date') 

class RecurringExpense(AbstractExpense): 
    FREQUENCY_CHOICES = (('D', 'daily'), 
         ('W', 'weekly'), 
         ('M', 'monthly'), 
         ('Y', 'yearly')) 
    start_date = models.DateField(blank=False) 
    end_date = models.DateField(blank=True, null=True) 
    last_check = models.DateField(blank=True, null=True) 
    frequency = models.CharField(blank=False, max_length=1, choices=FREQUENCY_CHOICES) 

RecurringExpense jest tylko szablon: gdy system uświadamia sobie, że czas, aby wprowadzić stałe koszta (np. czynsz) powinien pobrać informacje z szablonu i skopiować je w nowej instancji klasy Expense. Oto odnośny nieco od sposobu odpowiedzialnej pracy RecurringExpense:

Expense(description=self.description, 
     amount=self.amount, 
     category=self.category, 
     # tags=self.tags, 
     date=expense_date).save() 

Powyższe działa bez zarzutu, ale gdybym odkomentuj linię tags=self.tags Django narzeka i rzucać się następujący błąd:

Exception Type: TypeError 
Exception Value: 'tags' is an invalid keyword argument for this function 
Exception Location: <snip>/django/db/models/base.py in __init__, line 367 

I znam I could create a loop, aby obejść ten problem, ale zastanawiam się, czy istnieje bardziej elegancki sposób, który pozwoliłby mi na natychmiastowe wykonanie tego samego ...

Odpowiedz

8

Najprostszy sposób mogłem wymyślić:

e = Expense(description=self.description, 
      amount=self.amount, 
      category=self.category, 
      date=expense_date) 
e.save() 
e.tags = self.tags.all() 
+1

Możesz także zastąpić 'Expense (...)'/'e.save() 'z' Expense.objects.create (...) ' –

+0

To może nie działać, jeśli masz dużą liczbę znaczników (sterownik SQL zależny). W takim przypadku możesz dodawać znaczniki w dużych porcjach do wszystkich tagów. – odedfos

11

Nie można ustawić pola m2m bezpośrednio w ten sposób podczas tworzenia modelu i nstance. Spróbuj wykonać następujące czynności zamiast:

expense = Expense(description=self.description, 
     amount=self.amount, 
     category=self.category, 
     date=expense_date) 
expense.save() 
expense.tags.add(*self.tags.all()) 

Można sprawdzić https://docs.djangoproject.com/en/1.4/topics/db/examples/many_to_many/ więcej przykładów, w jaki sposób pracować z wielu do wielu relacji.

+0

Witam i dziękuję za odpowiedź. Czy istnieje konkretny powód, dla którego używasz metody '.add()' w połączeniu z rozpakowywaniem listy zamiast prostego przypisania (zobacz moją własną odpowiedź)? – mac

+0

Często nie potrzebuję zastępować istniejącego zestawu relacji m2m, wystarczy dodać do niego, więc bardziej przyzwyczaiłem się do tego. Dla twojego przypadku użycia, przypisanie jest prostsze i powinno działać dobrze, ponieważ 'ManyRelatedObjectsDescriptor' robi' .clear' + '.add (* wartości)' za kulisami podczas wykonywania przypisania. –

+0

Dobra uwaga. Rewizja! :) – mac

Powiązane problemy