Resuing Django example:
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
How to I obtain all Articles that do not have publications?
Article.objects.filter(...)
Specify publications as None:
Article.objects.filter(publications=None)
Example:
>>> p1 = Publication.objects.create(title='1')
>>> p2 = Publication.objects.create(title='2')
>>> a1 = Article.objects.create(headline='a')
>>> a2 = Article.objects.create(headline='b')
>>> a3 = Article.objects.create(headline='c')
>>> a1.publications.add(p1)
>>> a1.publications.add(p2)
>>> a3.publications.add(p1)
>>> Article.objects.filter(publications=None)
[<Article: Article object>]
>>> _[0].headline
u'b'
Article.objects.filter(publications=None)
Define blank=True with publications field into Article model else it will not allow you to create article without publications.
publications = models.ManyToManyField(Publication, blank=True)
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')
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>]
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 have the following Bank model:
from django.db import models
class Bank(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=255)
identifier = models.CharField(unique=True, max_length=255)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
class Meta:
db_table = u'bank'
app_name = 'mcif'
Now look at this:
>>> from mcif.models import *
>>> b = Bank()
>>> b.name = "wee"
>>> b.identifier = "wee"
>>> b.save()
>>> b.id
>>>
If I understand how Django works, that Bank object is supposed to get updated with the id of the saved record. Any idea why this isn't happening?
Its a problem in Django when dealing with BigInt as Autoincrementing PK. Maybe this code snippet helps you solve this issue. Its a makeshift solution