One QuerySet for two tables (one to many related) - django

I have created one to many relationship (two tables) such that every user has its own IP connections list. Every user has many connections.
My models are shown below:
class Conn(models.Model):
src_ip = models.CharField(max_length=18, unique=False,default=None,blank=True,null=True)
src_port = models.CharField(max_length=6, unique=False,default=None,blank=True,null=True)
dst_ip = models.CharField(max_length=18, unique=False,default=None,blank=True,null=True)
dst_port = models.CharField(max_length=6, unique=False,default=None,blank=True,null=True)
proto = models.CharField(max_length=6, unique=False,default=None,blank=True,null=True)
start_data = models.CharField(max_length=18, unique=False,default=None,blank=True,null=True)
r_user = models.ForeignKey(User, on_delete=models.CASCADE)
class User(models.Model):
e_user = models.CharField(max_length=15, unique=False,default=None,blank=True,null=True)
e_dev = models.CharField(max_length=15, unique=False,default=None,blank=True,null=True)
e_session = models.CharField(max_length=9, unique=False,default=None,blank=True,null=True)
e_start = models.CharField(max_length=20, unique=False,default=None,blank=True,null=True)
e_stop = models.CharField(max_length=20, unique=False,default=None,blank=True,null=True)
e_summary = models.CharField(max_length=20, unique=False,default=None,blank=True,null=True)
e_ip = models.CharField(max_length=20, unique=False,default=None,blank=True,null=True)
I'm trying to get all Users with their connections (Conn) in one QuerySet and then display everything in template. So far I can display every User without any problems with
q=Users.objects.all()
and passing the QuerySet to the template.
The question may be a bit not smart but how can I query all Users including related connections (Conn) as one QuerySet and then enumerate this connections in a form?

Use prefetch_related:
users = User.objects.all().prefetch_related('conn_set')
Now for each user you can look at its conn_set and see the Conn objects linked to it. Assuming you pass users to your template as a context variable users, something like this should work:
{% for user in users %}
{{ user.e_user }}
{% for connection in user.conn_set.all }}
{{ connection.src_ip }}
{% endfor %}
{% endfor %}
Adjust fields and add other markup to suit your needs.
From the documentation, prefetch_related
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
If this had been a one-to-one relationship or if you'd been trying to look things up in the other direction, finding all Conn objects along with the related User, you could have used select_related, which is even more efficient.
Note that you can also clean up some of your fields by choosing more appropriate field types. For example, consider GenericIPAddressField for src_ip and dst_ip.

Related

Django foreign key not getting data

I have two tables defined in my models:
class Products(models.Model):
productsid = models.AutoField(primary_key=True)
product_number = models.CharField(db_index=True, max_length=15)
title = models.CharField(max_length=255, default=None, null=True, blank=True)
date = models.DateField(db_index=True, default=datetime.date.today, null=True, blank=True)
class ProductFlag(models.Model):
product_number = models.CharField(db_index=True, max_length=15)
company = models.ForeignKey(Company, db_index=True, on_delete=models.SET_NULL, null=True)
productid = models.ForeignKey(Products, db_column='productsid', db_index=True, on_delete=models.SET_NULL, null=True)
I want to get the the 'title' from Products when I query ProductFlag.
In my views, I make this query:
productflags = ProductFlag.objects.filter(company__companyid=self.kwargs.get('company_id')).order_by('product_number')
I thought that I could then reference the title field in my template by looping through {% for product in productflags %} and
grabbing {{ product.productid.title }}, but I get nothing at all. Looking at it in the Django shell, it seems that my productid is always "None" (and my database definitely had data in productsid). I have no issue with the company foreign key. What am I doing wrong?
My apologies, I had a typo. I am referencing product.productid.title inside the loop in my template; product_number was in error. I have double-checked my database as well, and there is data in all the fields referenced.
I don't know that this will help, but in the django shell I get this behavior:
testflags = ProductFlag.objects.filter(company__companyid=43).order_by('product_number') gets a queryset of about seven. If I then try to access testflags[0].company.companyname, I get the actual company name. On the other hand, if I try to access testflags[0].productid.title, I get "AttributeError: 'NoneType' object has no attribute 'title'".
Also, if I try "testflags = ProductFlag.objects.select_related('productid').filter(company__companyid=43).order_by('product_number')" the query sees the column names in Products, but accessing them with productid, gives that AttributeError.
In pgAdmin, this query works just fine:
SELECT a.product_number, b.title
FROM productflag AS a
INNER JOIN products AS b
ON a.product_number = b.product_number
AND a.company_id = 43;
Thanks--
Al
From your snippet here:
{% for product in productflags %}
{{ product_number.productid.title }}
{% endfor %}
It looks like you're referencing the wrong variable name, because on loop, it's declared as product but you then go on to use product_number?
Try changing product_number to product or vice-versa.
Edit: Based on the new information it seems you have a typo in the filter part of your query. Try company_id rather than companyid.
.filter(company__company_id=43)
I believe the issue is in your loop. You need to access the title with
{{ product.productid.title }}
This is assuming the query set contains some data.
Thanks to everyone. You got me to look more closely at my code. It seems that my ProductFlag table was not being properly populated with the productid; so it was using a null value for its foreign key relationship with Products... No valid key = no valid data.

Django models many to many relations

I'm moving my first steps with django and I'm trying to figure out a thing.
Suppose that we have a model.py made like this where NameEffect has a many to many relation
class Name(models.Model):
nameid = models.IntegerField()
name = models.CharField(max_length=255)
class Effect(models.Model):
effectid = models.IntegerField()
effect = models.TextField()
class NameEffect(models.Model):
nameid = models.IntegerField()
effectid = models.IntegerField()
start = models.PositiveIntegerField()
strand = models.PositiveIntegerField()
and I want to create a QuerySet where every entry contains name,effect,start,strand of the researched name. Fact is that the only solution I found was using raw SQL queries but I can't understand how to do it with the django models approach
You haven't defined any relationships here at all. You should identify the fields as ForeignKeys - and also define the implicit many-to-many relationship explicitly (although you don't actually need it for this particular query, but it'll definitely come in useful).
class Name(models.Model):
nameid = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255)
effects = models.ManyToManyField('Effect', through='NameEffect')
class Effect(models.Model):
effectid = models.IntegerField(primary_key=True)
effect = models.TextField()
class NameEffect(models.Model):
name = models.ForeignKey('Name', db_column='nameid')
effect = models.ForeignKey('Effect', db_column='effectid')
start = models.PositiveIntegerField()
strand = models.PositiveIntegerField()
Now you can can query NameEffect directly to get the result you want.
data = NameEffect.objects.values('name__name', 'effect__effect', 'start', 'strand')
Also note, unless you know you really need just these fields, you should avoid using values and just query NameEffect using select_related:
name_effects = NameEffect.objects.select_related('name', 'effect')
and then access the values when you need them, eg in a template:
{% for obj in name_effects %}
{{ obj.name.name }}
{{ obj.effect.effect }}
{{ obj.start }}
{{ obj.strand }}
{% endif %}

Django template 'IF' condition

I want to do something like
{% if "sumit" in feed.like.person.all %}
But this gives me TemplateSyntaxError. How can I do this in Djagno ?
(Basically, I want to check if 'sumit' exists in feed.like.person.all)
Here are my relevant models.
class Feed(models.Model):
name = models.CharField(max_length=120)
text = models.CharField(max_length=1200)
timestamp = models.DateTimeField(auto_now=True, auto_now_add=False)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
class Like(models.Model):
feed = models.OneToOneField(Feed)
counter = models.PositiveIntegerField()
person = models.ManyToManyField(settings.AUTH_USER_MODEL, null=True, blank=True)
I think you intended to check the following:
# check if current user likes a feed
{% if request.user in feed.like.person.all %}
But if you are checking this for multiple feeds, then this method becomes inefficient. For multiple feeds, better approach is to use Annotations as mentioned by #AKS.
Your approach to check if a user likes a feed within the templates by querying for each feed is very inefficient.
I would suggest using Conditional Expressions to annotate each feed while fetching the queryset:
from django.db.models import BooleanField, Case, When, Value
feeds = Feed.objects.all().annotate(
is_liked=Case(
When(like__person=request.user, then=Value(True)),
default=Value(False),
output_field=BooleanField()))
This way you would be getting everything in one query only. And, then in the template you can just check is_liked on the feed:
{% if feed.is_liked %}You like this.{% endif %}
I haven't really executed this query but looking at the documentation it would be something similar.

Django prefetch_related failing to pass data to template

I have two Django models:
class Product(models.Model):
name = models.CharField(max_length=80, null=True)
is_active = models.BooleanField(default=False, null=False)
class Image(models.Model):
url = models.CharField(max_length=255, unique=True, null=False)
product = models.ForeignKey('Product', related_name='images')
I have a specific set of products. Each product has multiple images. The initial call looks something like:
product_list = product_list.filter(is_active=True).prefetch_related('images')
The product_list then gets whittled down depending on filters that are applied.
When I try to use the product_list within the display layer (template), I iterate the list of products. I can access all the product's fields except its images.
{{ product.images.0.id }} ==> empty
{{ product.images }} ==> returns Image.None
Running the code through the debugger, I can see the Image SQL query being executed, it's just that none of the data is passed to the template. There definitely is data there, as I can verify the query running it through my SQL client. Does any one know why this is happening? How do I get access to the Images for a given product?
I solved my issue. The prefetched data had to accessed like: product.images.all.0.id

django many to many get attributes from other object

So I've been using django for a while now, and it's great. I've recently come across a little bit of a problem, and I'm sure there's a crappy way to get it to work, but what I've found with Django is that they've usually built in all sorts of mechanisms to do things for you. So what I'm not finding is this:
Here are my models:
class LandmarkGroup(models.Model):
Name = models.CharField(max_length=150)
Description = models.CharField(max_length=300, blank=True)
IsActive = models.BooleanField(default=True)
landmarks = models.ManyToManyField('Landmark', blank=True, null=True)
def __unicode__(self):
return self.Name
class Landmark(models.Model):
Name = models.CharField(max_length=150)
Description = models.CharField(max_length=300, blank=True)
Polygon = models.PolygonField()
IsActive = models.BooleanField(default=True)
objects = models.GeoManager()
def __unicode__(self):
return self.Name
I also have another model 'Team' that has a ManyToMany with LandmarkGroup, but I'm not going to post it here. I have a view where I query for all the landmarks that have a landmarkgroup that has a team with the same team id as the one I passed in:
def mobile_startup(request):
...
landmarkGroups = LandmarkGroup.objects.filter(team=device.team, IsActive=True)
landmarks = Landmark.objects.filter(landmarkgroup__team=device.team, IsActive=True)
...
return render_to_response('webservice/mobile_startup.html', {'landmarks': landmarks, 'landmarkGroups': landmarkGroups})
Everything works, the only problem I'm having is, I'm returning this all as JSON to the mobile app, and I want to provide the landmarkGroup id for the landmark, so in my template I've been trying to:
"landmarkGroup" : {{ landmark.landmarkgroup.id }} }
but that's not working. Does anyone know any way I can get the landmarkGroup ID for each landmark in my set? Do I need to extract it when I do the query? I know I can reference each landmarkGroup in the query because I can do 'landmarkgroup__team=device.team', but I need to able to reference this object in the template
LandmarkGroup.landmarksis a ManyToManyField,therefore one Landmark can belong to multiple groups.
You should be able to output them in your template like this:
{% for group in landmark.landmarkgroup_set.all %}{{ group.pk }}{% endfor %}
The first group belonging to the landmark should be accessible through {% landmark.landmarkgroup_set.all.0 %}