How can I define the ManyToManyField name in django? - python

I have this relationship
Class Item(models.Model):
pass
Class Category(models.Model):
items = models.ManyToManyField(Item)
I can define the field name as items for category and access it via category.items but I want to define a field name for Item too as item.categories rather than the default item.category
How can I achieve it?
Update
Tried
items = models.ManyToManyField(Item, related_name = "categories")
But I get
TypeError: Direct assignment to the reverse side of a many-to-many set is prohibited. Use categories.set() instead.
on Item.object.create(**data)

When you call Item.objects.create(), you need to omit the categories from the args. Then afterwards you can call set() to set the categories.
item = Item.objects.create()
item.categories.set(categories)
If you want to add to existing categories (rather than overwriting what’s there), call add() instead:
item = Item.objects.create()
item.categories.add(category)
Note: both add() and set() save the update to the database, so you don’t need to call item.save() afterwards
EDIT
It looks like with the default name, you can pass in a list of categories to the call to create() and it even seems like it works because you can access the list of categories in the attribute category:
category = Category.objects.create()
item = Item.objects.create(category=[category])
print(item.category)
# output: [<Category: Category object(1)>]
The problem with this is category is not how you set or access category objects on an item, it’s category_set, and that’s empty.
To see this, after running the above code fetch the item from the database, you can see that the category is not associated with the item (it wasn’t saved):
item = Item.objects.get(id=item.id)
print(item.category_set)
# output: []
(And if you try to do item.category, you get an attribute error.)
It’s confusing that Django lets you provide the category argument in a call to create() with the default related name, but fails with an error when the related_name is set. IMO it should have an error in both cases, because clearly passing an m2m list as an argument to create() does not work: you have to call set() or add().
Source: Many-to-Many relations

The thing about many to many field is not an actual field. If you take a look at the generated schema you wouldnt find the field as a column in either of the table. What happens in the back is django creates a ItemCatagory table.
class ItemCatagory(models.Model):
item = modes.ForegnKeyField(Item, related_name="catagories", on_delete... )
catagory = models.ForegnKeyField(Item, related_name="items", on_delete... )
catagory.items will give u the ItemCatagory RelatedObject and if u do catagoty.items.all() it will give u QuerySet[ItemCatagory]. so the default model.save() method woont add those rship. so u would have to overide save method on either of the models.

See, ManyToManyField can't make reverse relationship with related model as python is interpreted language, so it can't read model class of previous one. Instead, you can do one thing ...
# models.py
class Item(models.Model):
item_name = models.CharField(max_length=255, default="")
def __str__(self):
return self.item_name
class Category(models.Model):
category_name = models.CharField(max_length=255, default="")
items = models.ManyToManyField(Item)
def __str__(self):
return self.category_name
After that, you can list down your requirements in views.py file.
# views.py
def get_items_by_categories(request):
# Here, you will receive a set of items ...
get_categories = Category.objects.all()
# Filter out items with respect to categories ...
get_items_list = [{"category": each.category_name, "items": each.items} for each in get_categories]
return render(request, "categories.html", {"data": get_items_list})
Iterate your items with categories in categories.html file.
{% for each in data %}
{% for content in each %}
{{content.category}}
{% for item in content.items.all %}
{{item.item_name}}
{% endfor %}
{% endfor %}
{% endfor %}
I hope this solution will help you ..
Thank You !

Related

Chaining Django models: how to format results on the template according to the specific model

I have a view that allows me to work with two different models at once, thanks to itertools chain. I'm rendering the instances of the two chained models inside a table in my template, and I'd need the rows of the table to be formatted differently in case the instances are from one model as opposed to the other.
So basically: I'm chaining two models and displaying their instances in a table, and all the rows of the table that contain instances from model A should be formatted with a yellow background and all the rows containing instances from model B should have a blue background instead.
This is the view:
class BaseView(generic.ListView):
template_name = 'base/base_list.html'
context_object_name = 'base_list'
def get_queryset(self):
queryset = Document.objects.order_by('due_date')
return queryset
def get_context_data(self, **kwargs):
context = super(BaseView, self).get_context_data(**kwargs)
context['object_list'] = sorted(
itertools.chain(Program.objects.all(), Document.objects.all()),
key=attrgetter('validity_date'),
reverse=True)
return context
In logic, what I'd need in the template would be something like this:
if
object in object_list ***belongs*** to Program.objects.all()
(etc)
else
(etc)
The question is: how should I express that belongs?
I've also looked into template tags but could not find the right way to go.
Thank you in advance.
As I mentioned in the comments, you should look for a way of identifying the model itself rather than checking if it is in a list. There is a built-in way of accessing the model name, but unfortunately that is inside the _meta attribute and you're not allowed to use attributes that start with underscores in a template.
So instead I would recommend simply adding one to your class definitions:
class Program(models.Model):
model_name = 'Program'
...
Now you can just do:
{% if object.model_name == 'Program' %}
...
{% else %}
...
{% endif %}

Django - get data from foreign key

I'm working on a Django project and attempting to create some linked models for my data which In think is working, but I cannot seem to work out how to access the linked data.
class One(models.Model)
name = models.CharField(max_length=50)
list = models.ArrayField(models.CharField(max_length=50), blank=True)
def __str__(self):
return self.name
class Many(models.Model)
name = models.CharField(max_length=50)
related = models.ForeignKey(One, null=True, blank=True)
def __str__(self):
return self.name
This is the general relationship I have set up.
What I am trying to do is, in a template have access to a list of all 'Ones', and via each of those, can access each Many and it's related attributes. I can see how to access the attributes for a single 'One', but not how to pass all of them and their related 'Many' models and the related attributes for each. Essentially the output I'd like would have a drop down list with the One's, and when this is submitted some Javascript will use the list in the 'Many' model to do some stuff.
Any advice would be much appreciated.
If you already have the objects of One model class, you can access the many objects using many_set (refer: backward relations):
{% for one_obj in one_objs %}
{% for m_obj in one_obj.many_set.all %}
# do stuff with m_obj here
{% endfor %}
{% endfor %}
One important thing to note here is that this will execute a db query for each m_obj. To make this efficient, you could prefetch the many_set with one_objs in your view.
In your view, use prefetch_related:
one_objs = One.objects.all().prefetch_related('many_set')
You can use Django's "prefetch_related" and Django's "related_name".
Also, this question has been answered here.
Though, here is what you might want, first, change your foreign key definition to this :
related = models.ForeignKey(One, null=True, blank=True, related_name='relateds')
Then you can reverse-fetch the foreign keys:
one = One.objects.get(name="TheOneYouWant").prefetch_related('relateds')
manys = one.relateds
Reverse lookups are accessible through an object's ___set attribte. So to get all the "Many" objects for a given "One" you could do one.many_set
Django reverse lookup of foreign keys
Regarding usage in a template, sets are accessible by adding "all" (since the set returns a queryset, you can run queries against it, including in the template)
Access ForeignKey set directly in template in Django
See the relevant section of the Django Documentation: https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward

Django: How to return all models associated with a ForeignKey including all attributes of those models?

I have an app that I want to simply display all the URL links a page has associated with it when that page is visited.
It's similar to reddit in that there are many userpages (aka subreddits) and each page has an infinite possible amount of submitted links associated with it. The newlinkposts records are associated with a certain page via a ForeignKey.
Given a page, wow can I get all the related newlinkpost objects (including their corresponding likes, link comment, and post date) returned, in order to display them in a template?
My newlinkpost object is defined as follows:
class newlinkpost(models.Model):
newlink_tag = models.ForeignKey('userpagename') #tags link to which userpage it belongs to
link_comment = models.CharField(max_length=128) #comment to go along with post
post_date = models.DateField(auto_now=True, auto_now_add=False, null=False) #submission datestamp. later make it track editable posts if edit function is implemented
url = models.URLField(max_length = 1024, null=False) #actual submitted link
link_likes = models.IntegerField(null=False, default=0) #need to later create like button which will +1 the value
def __unicode__(self):
return self.url
When you add a ForeignKey within a model, as well as creating an attribute in the source model (in your case, newlinkpost) allowing you to find the one associated object, Django also creates a corresponding attribute inside the target model (in your case apparently userpagename).
By default this attribute is named after the source table, so in your case it will be newlinkpost_set.
That allows you to ask the question you're looking to answer: which newlinkpost objects have this userpagename?:
all_links = userpagename_instance.newlinkpost_set.all()
If you wish to apply additional filters, you can use the filter method instead:
some_links = userpagename_instance.newlinkpost_set.filter(...)
The newlinkpost_set attribute contains a RelatedManager object, which is a subtype of Manager, allowing you to use the same set of methods you could use on newlinkpost.objects, along with some additional methods allowing you to create new related objects.
Here's an example view using this technique: (this assumes you've got the model classes imported into the views module):
from django.shortcuts import render
def user_page(request, user_id):
page = userpagename.get(pk=user_id)
links = page.newlinkpost_set.all()
return render(
request,
"myapp/user_page.html",
{
page: page,
links: links,
}
)
...and here's an example of using that "links" variable in the template:
<ul>
{% for link in links %}
<li><a href="{{ link.url }}">{{ link.link_comment }} - {{ link.link_likes }} likes</li>
{% endfor %}
</ul>
You just use the reverse relationship.
my_userpagename.newlinkpost_set.all()

Using one model to filter another model in Django

I'm trying to access the information in my gadb_action model based on the action_ids in my gadb_vote model. I'm initially only getting the information for a particular legislator and then attempting to get the bills associated with the actions that legislator has voted on.
Right now, my action_list is only storing action_ids, but not the related information from the gadb_action model that I want to use in my template.
What is the best way to store that information outside of the for loop to be accessed by the template? Is there a way to write to an empty QuerySet?
Thanks in advance for any and all help!
view
def each_member(request,legislator_id):
each_member = get_object_or_404(gadb_legislator, legislator_id=legislator_id)
each_vote = gadb_vote.objects.filter(legislator_id=legislator_id)
action_list = []
for i in each_vote:
action = gadb_action.objects.filter(action_id=i.action_id)
action_list.append(action)
context = {
'each_member': each_member,
'each_vote': each_vote,
'action_list': action_list
}
return render(request, "eachmember.html", context)
models
class gadb_action(models.Model):
action_id = models.IntegerField(unique=False, max_length=4, primary_key=True)
bill_id = models.IntegerField(unique=False, max_length=12)
class gadb_vote(models.Model):
vote_id = models.IntegerField(unique=False, max_length=11,primary_key=True)
legislator_id = models.IntegerField(unique=False, max_length=11)
action_id = models.IntegerField(unique=False, max_length=11)
template
{% for i in action_list %}
{{i.bill_id}}
{{i.action_id}}
{% endfor %}
Your models are broken.
For a start, although it's not directly related to the question, you need to define your primary keys as AutoFields so that they are autoincremented every time a new entity is added. Otherwise you'll get all sorts of errors when you save a new row. (Even better, don't define the PK at all, and let Django add it automatically.)
Secondly, as lalo says, you should have ForeignKeys from Action to Bill, and from Vote to Action and Vote to Legislator. That way you can get the relevant information with a single query, and follow the foreign keys as required in your template.
(Also, Django already includes the app name in the underlying table name: no need to prefix everything with 'gadb'.)
class Action(models.Model):
bill = models.ForeignKey(Bill)
class Vote(models.Model):
legislator = models.ForeignKey(Legislator)
action = models.ForeignKey(Action)
View:
def each_member(request,legislator_id):
actions = Action.objects.filter(vote__legislator_id=legislator_id)
return render(request, "eachmember.html", {'action_list': actions})
Template:
{% for action in actions %}
{{ action.bill.name }}
{{ action.someotherfield }}
{% endfor %}

Queryset object has no attribute 'Name'

I am working on my first django project and i am having problems displayin 'categories' from my database onto a webpage as a list. I am getting the error "object has no attribute 'Name'. My code so far is:
Model:
class Category(models.model):
name = models.Charfield(max_length=128)
def __unicode__(self):
return self.Name + ": " +str(self.id)
Views:
from django.shortcuts import render_to_response, redirect
from forms.models import Form, Group, Flow, Gate, Field, Event, Category
from django.core.context_processors import csrf
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
def homepage (request):
CatName = Category.objects.order_by('id')
output = {
'category_name': CatName.Name,
}
return render_to_response('forms/formsummary.html', output)
HTML:
<div>{{ category_name }}</div>
Can anybody point me in the right direction?
In Django, when you use the ORM to query for objects, there are two possibilities (excluding each case returning nothing):
Query returns just one objects: if so, you queried using the get() method of the manager.
Query returns a collection: if so, you queried by using an all(), filter() or any method like those.
In this case, your query returned a collection of Category objects, you can do a couple of things about this, you can either generate a list with only the names by using a list comprehension:
cnames = [c.name for c in Category.objects.all()]
Or you can iterate the list using a for loop and do whatever you need to do with each object.
Django already orders your data by the id field, so, I guess there is no need to specify an ordering in this case.
Later, when your view is returning, you can deliver the list to your template and iterate it to extract what you need, for example.
In your view:
def get_categories(request):
categories = Category.objects.all()
context = {'categories': categories}
return render_to_response('template.html', RequestContext(request, context))
Then, in your template:
{% for c in categories %}
<p>{{c.name}}</p>
{% endfor %}
Here's some useful documentation
Django Templates
Django Querysets
Hope this helps.
It seems like case sensitive,
def__unicode__(self):
return self.Name + ": " +str(self.id)
^
name
CatName is a collection of Category instances. The CatName object does not have a name property because it is not a Category object. It contains Category objects.
you can iterate through your collection and display each categories name:
for category in CatName:
print category.name
It is good to at least read through QuerySet documentation even if you don't fully grasp it yet.
if you want just the most recent category you could do something like:
def homepage (request):
most_recent_category = Category.objects.order_by('-id')[0]
output = {
'category_name': most_recent_category.name
}
return render_to_response('forms/formsummary.html', output)

Categories

Resources