Considerer this model
class Dealership(models.Model):
dealership = models.CharField(max_length=50)
class Ordered(models.Model):
customer = models.ForeignKey("Customer")
dealership = models.ManyToManyField("Dealership")
status = models.CharField(max_length=2, choices=status_list, default='p')
I try
$ ./manage.py shell
>>> from new_way.core.models import Ordered, Dealership
>>> q = Ordered.objects.all()[:5]
>>> [i.dealership for i in q.dealership.all]
And generate error
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'QuerySet' object has no attribute 'dealership'
How to return
Ordered.dealership.dealership
all dealership by Ordered.
You're very close:
Change:
[i.dealership for i in q.dealership.all]
to:
[dealership for dealership in q.dealership.all()]
Here's sample output from one of my model's M2M relationships on a project which demonstrates what you should see from the list comprehension. shared_with is an M2M field to a model called Profile:
>>> from polls.models import Poll
>>> polls = Poll.objects.all()
>>> for p in polls:
... print([sw for sw in p.shared_with.all()])
...
[<Profile: kerri>]
[<Profile: kerri>]
[]
[<Profile: jake>, <Profile: kerri>]
[<Profile: jake>, <Profile: kerri>]
[<Profile: jake>, <Profile: kerri>]
[<Profile: btaylor>]
[<Profile: jake>, <Profile: kerri>]
It should be:
q.dealership.all() #gives a list of objects
You can directly do this instead of using list comprehension(in the above ans).
Example: (Taken from docs)
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
def __str__(self): # __unicode__ on Python 2
return self.title
class Meta:
ordering = ('title',)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
def __str__(self): # __unicode__ on Python 2
return self.headline
class Meta:
ordering = ('headline',)
Create a couple of Publications:
p1 = Publication(title='The Python Journal')
p1.save()
p2 = Publication(title='Science News')
p2.save()
p3 = Publication(title='Science Weekly')
p3.save()
Now, create an Article and the associate the Article with a Publication:
a1 = Article(headline='NASA uses Python')
a1.save()
a1.publications.add(p1, p2)
a1.publications.add(p3)
a1.publications.all()
[<Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
Related
I have the following django model
class Course(models.Model):
name = models.CharField(max_length=50)
pre_req_courses = models.ManyToManyField('self')
def __str__(self):
return self.name
when I create courses in following way:
course1 = Course.objects.create(name='Course1')
course1.save()
course2 = Course.objects.create(name='Course2')
course2.save()
course2.pre_req_courses.set(course1)
when I run the following command I get:
course2.pre_req_courses.all()
>>> <QuerySet [<Course: Course1>]>
course1.pre_req_courses.all()
>>> <QuerySet [<Course: Course2>]>
Wht I want is:
course2.pre_req_courses.all()
>>> <QuerySet [<Course: Course1>]>
course1.pre_req_courses.all()
>>> <QuerySet []>
How can I achieve this
I couldn't solve it with the m2m field.
It's a little complicated, but you can get the result you want with the code below.
models.py
from django.db import models
class CourseRelation(models.Model):
low_level = models.ForeignKey(
'course.Course',
models.CASCADE,
related_name='relations_me_low'
)
high_level = models.ForeignKey(
'course.Course',
models.CASCADE,
related_name='relations_me_high'
)
def __str__(self):
return '%s -> %s' % (self.low_level, self.high_level)
class Course(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
#property
def pre_req_courses(self):
course_ids = CourseRelation.objects.filter(high_level=self).values('low_level')
return Course.objects.filter(id__in=course_ids)
#property
def next_courses(self):
course_ids = CourseRelation.objects.filter(low_level=self).values('high_level')
return Course.objects.filter(id__in=course_ids)
shell
>>> python_course = Course.objects.create(name='Python')
>>> web_course = Course.objects.create(name='Web')
>>> django_course = Course.objects.create(name='Django')
>>> CourseRelation.objects.create(low_level=python_course, high_level=django_course)
<CourseRelation: Python -> Django>
>>> CourseRelation.objects.create(low_level=web_course, high_level=django_course)
<CourseRelation: Web -> Django>
>>> python_course.pre_req_courses
<QuerySet []>
>>> python_course.next_courses
<QuerySet [<Course: Django>]>
>>> django_course.pre_req_courses
<QuerySet [<Course: Python>, <Course: Web>]>
>>> django_course.next_courses
<QuerySet []>
update
When I read Abdul Aziz Barkat's comment, I realized that a single line would solve it.
pre_req_courses = models.ManyToManyField(
'self',
related_name='next_courses',
symmetrical=False
)
I want to owerride for my order. But I get an error because it is "ManytoMany" field.
views.py:
orderform = OrderForm()
if request.method == 'POST':
orderform = OrderForm(request.POST)
if orderform.is_valid() and int(orderform["customer"].value()) == customer[0].id:
test = orderform.save(commit=False)
orderitems = OrderItem.objects.filter(customer_id=customer[0].id)
test.orderitem.add(orderitems )
orderform.save()
return redirect('home')
models.py
class CustomerOrder(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
orderitem = models.ManyToManyField(OrderItem, related_name="orderitem")
dealer = models.ForeignKey(Dealer, default=1, on_delete=models.CASCADE)
status = models.CharField(
max_length=200,
choices=WORK_STATUS,
default="Waiting",
)
pay_method = models.CharField(
max_length=2,
choices=PAY_METHOD,
default=1,
)
First you have to save the record in the database and then add items to manyTomany. You can see in the documentation an example of what is happening to you.
What follows are examples of operations that can be performed using
the Python API facilities.
Create a few Publications:
>>> p1 = Publication(title='The Python Journal')
>>> p1.save()
>>> p2 = Publication(title='Science News')
>>> p2.save()
>>> p3 = Publication(title='Science Weekly')
>>> p3.save()
Create an Article:
>>> a1 = Article(headline='Django lets you build Web apps easily')
You can’t associate it with a Publication until it’s been saved:
>>> a1.publications.add(p1)
Traceback (most recent call last):
...
ValueError: "<Article: Django lets you build Web apps easily>"
needs to have a value for field "id" before this many-to-many
relationship can be used.
Save it!
>>> a1.save()
Associate the Article with a Publication:
>>> a1.publications.add(p1)
Your code should look like this
orderform = OrderForm()
if request.method == 'POST':
orderform = OrderForm(request.POST)
if orderform.is_valid() and int(orderform["customer"].value()) == customer[0].id:
test = orderform.save(commit=False)
orderitems = OrderItem.objects.filter(customer_id=customer[0].id)
orderform.save()
test.orderitem.add(orderitems ) # <- after save
return redirect('home')
I found out that django 1.7 supports now update_or_create() method in queryset.
But when I try it, it is not working. There is no object created when I try this:
models.py
class Model1(models.Model):
name = models.CharField(max_length=100)
status = models.CharField(max_length=100)
user = models.ForeignKey(User, null=True, blank=True)
class Model2(models.Model)
model = models.ForeignKey(Model1, null=True, blank=True)
field1 = models.CharField(max_length=100)
field2 = models.CharField(max_length=100)
user = models.ForeignKey(User, null=True, blank=True)
views.py
def ModelUpdate(request)
model1 = get_object_or_404(Model1, pk=request.POST['lid'])
model1.status =2
model1.save()
#based on the model1, we want to create or update model2
datadict ={'field1' : 1, 'field2':2,}
model2, created = Model2.objects.update_or_create(model=model1,
defaults=datadict)
if created:
print('model2 obj created') #for checking purpose
else:
print('model2 obj not created')
return render(request,'updated.html', {'update':'updated'})
I can see the message model2 obj created but the object was not saved in the database. What could be the problem?
UPDATE
Turns out it was my mistake. In the Model2, I defined the save method without returning super(Model2, self).save(*args, **kwargs)
That's why it didn't save the objects.
Maybe you verifying in the wrong way, because I created project with your models and everything works fine.
In my case I'm verifying that object was created/updated with objects.get() and printing values:
In [1]: from app1 import models
In [2]: m1 = models.Model1.objects.create(name=1, status=1)
In [3]: m1
Out[3]: <Model1: Model1 object>
In [4]: datadict ={'field1' : 1, 'field2':2,}
In [6]: model2, created = models.Model2.objects.update_or_create(model=m1, defaults=datadict)
In [7]: model2, created
Out[7]: (<Model2: Model2 object>, True)
In [8]: models.Model2.objects.get().field1, models.Model2.objects.get().field2
Out[8]: (u'1', u'2')
In [9]: datadict ={'field1' : 3, 'field2':4}
In [10]: model2, created = models.Model2.objects.update_or_create(model=m1, defaults=datadict)
In [11]: model2, created
Out[11]: (<Model2: Model2 object>, False)
In [12]: models.Model2.objects.get().field1, models.Model2.objects.get().field2
Out[12]: (u'3', u'4')
and
In [13]: models.Model2.objects.get().model.id
Out[13]: 1
In [14]: models.Model1.objects.get().id
Out[14]: 1
In Django's many-to-many relationships extra fields, we can add extra fields, as the code below (from https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany), my question is how could I get the extra field easily, is it possible to not query on the intermediary table directly? the exactly example is:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> p = beatles.members.all()[0]
>>> p
[<Person: Ringo Starr>]
I want to get the date_joined value of p, I know it can be done by
>>> Membership.objects.get(person=p, group=beatles).date_joined
datetime.date(1962, 8, 16)
but is it possible to get it simply just like:
>>> p.xxx(*args)
=============== models.py ================
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
From the documentation page you link to:
Another way to access the same information is by querying the many-to-many reverse relationship from a Person object:
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
I am using the following models for my first django site. But I am currently having problems with how to access the wishes of a user.
class Group(models.Model):
title = models.CharField(max_length=100)
users = models.ManyToManyField(User, related_name='group_users')
description = models.TextField()
added = models.DateTimeField()
owner = models.ForeignKey(User)
def __unicode__(self):
return self.title
class Wish(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User, related_name='wish_user')
bought = models.IntegerField(default=0)
bought_by = models.ForeignKey(User, related_name='wish_buyer')
added_by = models.ForeignKey(User, related_name='wish_adder')
cost = models.FloatField()
added = models.DateTimeField()
def __unicode__(self):
return self.name
def is_bought(self):
return self.bought % 2 == 1
def is_editable(self):
return self.added >= timezone.now() - datetime.timedelta(hours=1)
When I go to the django shell I get the following:
$ ./manage.py shell
>>> from django.contrib.auth.models import User
>>> from wish.models import Wish, Group
>>> user1 = User.objects.filter(id=1)[0]
>>> user1.group_set.all()
[]
>>> user1.wish_set.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'User' object has no attribute 'wish_set'
>>>
Why doesn't the User object get the wish_set like it does get the group_set ?
That's because you renamed them to wish_user, wish_buyer and wish_adder. Whereas for the group you have wish_set implicity from the owner property and the explicit group_users.
The related_name parameter tells Django how to name the reverse relation. If it's not given it will be <field name>_set