Django query for multiple fields with list values - django

I have below Django model
class Post(models.Model):
author = models.ForeignKey(CustomUser,on_delete=models.CASCADE,)
title = models.CharField(max_length=200,null=True)
text = models.TextField()
post_url = models.URLField(max_length = 200, blank = True)
post_tier = models.ForeignKey(Tiers, on_delete=models.CASCADE, null= True)
post_tier_value = models.IntegerField(default=0)
slug = models.SlugField(unique=True, blank=True)
I have author_list = [author1#gmail.com, author2#gmail.com] and tier_value_list = [2000,3000]. I want to query in the above model for (author = author1#gmail.com and post_tier_value <= 2000) or (author = author2#gmail.com and post_tier_value <= 3000).
Can someone help me how to make query for this?

Use Q() operator
from django.db.models import Q
author_list = ['author1#gmail.com', 'author2#gmail.com']
tier_value_list = [2000, 3000]
query = Q()
for author, value in zip(author_list, tier_value_list):
query = query | Q(author=author, post_tier_value__lte=value)
Post.objects.filter(query)
Note: I have used author__email which is a nested lookup since the author_list contain the email_ids

Related

How to import a object of another model (A) inside model (B) in Django?

I want to create a new object in ModelB when specific condition are met in ModelA. I am new to Django so that I am unable to figure out how exactly I can achieve this.
For example I have two models(Product and ProductVariant), when specific condition on ProductVariant is met then I want to calculate new object value in Product model.
My Product model is like this:
PRODUCT_TYPE = (
('s', 'simple'),
('v', 'varaible')
)
class Products(models.Model):
name = models.CharField(max_length=250,null=True, blank=True,)
slug = models.SlugField(max_length=200, unique=True,null=True)
short_description = HTMLField()
description = HTMLField()
category = models.ForeignKey(Categories, related_name="products",on_delete=models.SET_NULL,null=True,blank=True,)
brand = models.ForeignKey(Brands,on_delete=models.CASCADE, default=None, null=True, blank=True,)
warranty_support = HTMLField()
product_type = models.CharField(choices=PRODUCT_TYPE, default='simple', max_length=50)
And my Product Attribute Model is like this:
class ProductVariant(models.Model):
product = models.ForeignKey(Products,on_delete=models.CASCADE)
variant = models.ForeignKey(ProductAttribute,on_delete=models.CASCADE, null = True, default=None)
managed_stock = models.IntegerField(choices=STOCK_MANAGED, default=0)
stock = models.IntegerField(default=None)
stock_threshold = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
sku = models.CharField(max_length= 250, default=None)
sale_price = models.DecimalField(max_digits=10, decimal_places=2)
sale_start_date=models.DateField(auto_now_add=False, auto_now=False, default=None)
sale_end_date=models.DateField(auto_now_add=False, auto_now=False,default=None)
I am trying to create regular_price and sale_price on Product model if product_type is variable and if sale_end_date is greater than today. I want to set the price from the variant which has the lowest price.
I tried doing like this on Product model:
def clean(self):
if self.product_type == 'varaible' and ProductVariant.objects.filter(product=self, variant_count__gt = 1):
self.min_price = ProductVariant.objects.filter(product=self).Min('price')
self.max_price = ProductVariant.objects.filter(product=self).Max('price')
but I am not able to achieve what I want,
How can I do this?
After some research and analysis I found solution to my problem, I am posting the solution here so that someone with similar problem could be benefited.
#property
def get_price(self):
result = dict()
variants = ProductVariant.objects.filter(product=self)
count = variants.count()
if count > 1:
min_variant = variants.order_by('price').first()
max_variant = variants.order_by('-price').first()
result['min_price'] = min_variant.price
result['max_price'] = max_variant.price
elif count == 1:
variant = variants.first()
if variant.sale_price:
result['price'] = variant.price
result['sale_price'] = variant.sale_price
sale_variant = variants.order_by('sale_price').first()
result['lowest_sale_price'] = sale_variant.sale_price
result['regular_price'] = sale_variant.price
today = datetime.date.today()
if variant.sale_start_date <= today and variant.sale_end_date >= today:
result['sale_end_date'] = variant.sale_end_date
else:
result['price'] = variant.price

Sub query result in Django not looping from drop down select box

This is the error am getting:
QuerySet.annotate() received non-expression(s): 17
What I want is a subquery that will do something similar to the
select * from inecdb.announced_pu_results
where polling_unit_uniqueid in
(
select uniqueid from polling_unit
where lga_id = (select uniqueid from lga where uniqueid= 17)
);
The subquery
obj3 = Pu_results.objects.filter(polling_unit_uniqueid__in=Subquery(Unit.objects.filter(lga_id=obj1)))
is not displaying any result please can any one help
This is my view
if request.method == 'POST':
selected_item = request.POST.get('item_id') #This is from html select box
obj = Lga.objects.get(lga_id=selected_item)
obj1 = obj.lga_id
obj3 = Pu_results.objects.filter(polling_unit_uniqueid__in=Subquery(Unit.objects.filter(lga_id=obj1)))
for obt in obj3:
print(obt.party_score) #I want looping results here
This is my Model
from django.db import models
from django.urls import reverse
#from django.urls import reverse
class Unit(models.Model):
uniqueid = models.IntegerField(primary_key=True)
polling_unit_id = models.IntegerField(blank=False)
ward_id = models.IntegerField(default=False)
lga_id = models.IntegerField(default=False)
uniquewardid = models.IntegerField(default=True)
polling_unit_number = models.CharField(max_length=50, unique=True)
polling_unit_name = models.CharField(max_length=51)
#pulling_unit_number = models.CharField(max_length=50)
polling_unit_description = models.CharField(max_length=300)
lat = models.CharField(max_length=255)
long = models.CharField(max_length=255)
entered_by_user = models.CharField(max_length=50)
date_entered = models.DateTimeField(blank=False)
user_ip_address = models.CharField(max_length=50)
def get_absolute_url(self):
#return f"/products/{self.id}/"
return reverse("polling:inec-pull-result", kwargs={"uniqueid": self.uniqueid})
class Lga(models.Model):
uniqueid = models.AutoField(primary_key=True)
lga_id = models.IntegerField()
lga_name = models.CharField(max_length=50)
state_id = models.IntegerField()
lga_description = models.TextField(blank=True, null=True)
entered_by_user = models.CharField(max_length=50)
date_entered = models.DateTimeField()
user_ip_address = models.CharField(max_length=50)
class Meta:
db_table = 'lga'
class Article(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
active = models.BooleanField(default=True)
You need to make sure that the queryset you use for the subquery returns just one column, use values() for that. Note that Subquery isn't needed:
units = Unit.objects.filter(lga_id=obj1).values('uniqueid')
obj3 = Pu_results.objects.filter(polling_unit_uniqueid__in=units)
Read the documentation for the in lookup for a more detailed explanation of passing a QuerySet to in.
This also works:
obj3 = Pu_results.objects.filter(
polling_unit_uniqueid__in = Subquery(
Unit.objects.values('uniqueid').filter(lga_id=obj1)
)
)

How to use update_or_create with defaults argument

I have the model League
class League(models.Model):
league = models.IntegerField(primary_key=True)
league_name = models.CharField(max_length=200)
country_code = models.ForeignKey("Country",null=True, on_delete=models.SET_NULL)
season = models.ForeignKey("Season", null=True,on_delete = models.SET_NULL, to_field = "season")
season_start = models.DateField(null = True) season_end = models.DateField(null = True)
league_logo = models.URLField(null = True) league_flag = models.URLField(null = True)
standings = models.IntegerField(null=True)
is_current = models.IntegerField(null=True)
I created objects from this model. After it i needed to add some additional fields to League model after adding those fields League object became so
class League(models.Model):
league = models.IntegerField(primary_key=True)
league_name = models.CharField(max_length=200)
country_code = models.ForeignKey("Country",null=True, on_delete=models.SET_NULL)
season = models.ForeignKey("Season", null=True,on_delete = models.SET_NULL, to_field = "season")
season_start = models.DateField(null = True) season_end = models.DateField(null = True)
league_logo = models.URLField(null = True) league_flag = models.URLField(null = True)
standings = models.IntegerField(null=True)
is_current = models.IntegerField(null=True)
cover_standings = models.BooleanField(null=True)
cover_fixtures_events = models.BooleanField(null=True)
cover_fixtures_lineups = models.BooleanField(null=True)
cover_fixtures_statistics = models.BooleanField(null=True)
cover_fixtures_players_statistics = models.BooleanField(null=True)
cover_players = models.BooleanField(null=True)
cover_topScorers = models.BooleanField(null=True)
cover_predictions = models.BooleanField(null=True)
cover_odds = models.BooleanField(null=True)
lastModified = models.DateTimeField(auto_now=True)
I did migrations and added these fields to db schema. Now i want to add to these added fields values. I read about
update_or_create method and tried to use it for updating League model objects
leagues_json = json.load(leagues_all)
data_json = leagues_json["api"]["leagues"]
for item in data_json:
league_id = item["league_id"]
league_name = item["name"] country_q =Country.objects.get(country = item["country"])
season = Season.objects.get(season = item["season"])
season_start = item["season_start"]
season_end = item["season_end"]
league_logo = item["logo"]
league_flag = item["flag"]
standings = item["standings"]
is_current = item["is_current"]
coverage_standings = item["coverage"]["standings"]
coverage_fixtures_events = item["coverage"]["fixtures"]["events"]
coverage_fixtures_lineups = item["coverage"]["fixtures"]["lineups"]
coverage_fixtures_statistics = item["coverage"]["fixtures"]["statistics"]
coverage_fixtures_plaers_statistics = item["coverage"]["fixtures"]["players_statistics"]
coverage_players = item["coverage"]["players"]
coverage_topScorers = item["coverage"]["topScorers"]
coverage_predictions = item["coverage"]["predictions"]
coverage_odds = item["coverage"]["odds"]
b = League.objects.update_or_create(league = league_id,
league_name = league_name,
country_code = country_q,season = season,
season_start = season_start,
season_end = season_end,
league_logo = league_logo,
league_flag = league_flag,
standings = standings,
is_current = is_current,
cover_standings = coverage_standings,
cover_fixtures_events = coverage_fixtures_events,
cover_fixtures_lineups = coverage_fixtures_lineups,
cover_fixtures_statistics= coverage_fixtures_statistics,
cover_fixtures_players_statistics = coverage_fixtures_players_statistics,
cover_players= coverage_players,
cover_topScorers = coverage_topScorers,
cover_predictions = coverage_predictions,
cover_odds = coverage_odds)
While i am trying to update objects by above method i get an error
django.db.utils.IntegrityError: duplicate key value violates unique constraint "dataflow_league_pkey"
DETAIL: Key (league)=(1) already exists.
I read about defaults argument of update_or_create method but didn't understand how to useit in my case. Can anyone help me
If you use update_or_create like this, first of all, your code will search the row in db with that all parameters.
I think you want to search league by league id and it works like this
You create the dict by any way of defaults, I just copy your code
defaults = dict(
league_name=league_name,
country_code=country_q,
season=season,
season_start=season_start,
season_end=season_end,
league_logo=league_logo,
league_flag=league_flag,
standings=standings,
is_current=is_current,
cover_standings=coverage_standings,
cover_fixtures_events=coverage_fixtures_events,
cover_fixtures_lineups=coverage_fixtures_lineups,
cover_fixtures_statistics=coverage_fixtures_statistics,
cover_fixtures_players_statistics=coverage_fixtures_players_statistics,
cover_players=coverage_players,
cover_topScorers=coverage_topScorers,
cover_predictions=coverage_predictions,
cover_odds=coverage_odds)
And use this defaults to update or create league with particular id
League.objects.update_or_create(defaults=defaults, league=league_id)
This code will find league with league_id and update it with data which you passed as the defaults parameter
OR
This code will create new league with that id and these params
You can use update_or_create like this
if exist, it return obj and created false
if not exist, it return obj and created true.
obj, created = League.objects.update_or_create(defaults=defaults, league=league_id)

get post by name of user or by id

i have this model
class Post(models.Model):
auth = models.ForeignKey(settings.AUTH_USER_MODEL,default=1)
title = models.CharField(max_length=120)
DESCSPECSOFT = (
(u'Null','Null'),
(u'Phone',u'Phone'),
(u'Car',u'Car'),
(u'Laptop',u'Laptop'),
(u'jops',u'Jops'),
(u'Electronic',u'Electronic'),
(u'Clothes',u'Clothes'),
(u'Makeup',u'Makeup'),
(u'Furnishings',u'Furnishings'),
(u'books',u'books'),
(u'sports',u'sports'),
(u'Property',u'Property'),
(u'Other',u'Other'),
)
City = (
(u'Null','Null'),
(u'Kosti',u'Kosti'),
(u'Khartoum',u'Khartoum'),
(u'Rabbik',u'Rabbik'),
(u'Duwaim',u'Duwaim'),
(u'Sinnar',u'Sinnar'),
(u'Bahri',u'Bahri'),
(u'Omdurman',u'Omdurman'),
(u'Sawakin',u'Sawakin'),
(u'Port Sudan',u'Port Sudan'),
(u'Kasala',u'Kasala'),
(u'Madani',u'Madani'),
(u'Alabid',u'Alabid'),
)
Case = (
(u'Null','Null'),
(u'New',u'New'),
(u'Old',u'Old'),
(u'Second Hand',u'Second Hand'),
(u'Other',u'Other'),
)
Type = models.CharField(choices=DESCSPECSOFT, default='Null',blank = False,null = False,max_length=120)
company = models.CharField(max_length=120)
dis = models.TextField(default="in here you w,ll write all the discribtion about your product")
image = models.ImageField(null=True,blank=True,width_field="width_field", height_field="height_field")
width_field = models.IntegerField(default=0)
height_field = models.IntegerField(default=0)
case = models.CharField(choices=Case, default=99,blank = False,null = False,max_length=120)
price = models.BigIntegerField(default=0)
city = models.CharField(choices=City, default='Null',blank = False,null = False,max_length=120)
address = models.CharField(max_length=120)
draft = models.BooleanField(default=False)
#pup = models.DateField(auto_now=False,auto_now_add=False ,null=False)
date = models.DateTimeField(auto_now=True ,auto_now_add=False)
puplis = models.DateTimeField(auto_now=False ,auto_now_add=True)
objects = PostManager()
def __str__(self):
return self.title
def __unicode__(self):
return self.title
any user can add a post but i want the user name show in the data base means the user how add the post because every post show the admin name not the user how add the post can someone show me haw can i fix this ???
sorry my en is bad ...

Making table report from non-related GeoDjango models

I have this 2 models:
class BuildingStructure(models.Model):
bldg_name = models.CharField(max_length=100)
height = models.FloatField()
code = models.CharField(max_length=25)
block_name = models.CharField(max_length=75)
bldg_type = models.CharField(max_length=50)
brgy_locat = models.CharField(max_length=50)
geom = models.MultiPointField(srid=32651, null=True, blank=True)
objects = models.GeoManager()
def __unicode__(self):
return self.bldg_name
class FloodHazard(models.Model):
gridcode = models.IntegerField()
hazard = models.CharField(max_length=6)
date_field = models.CharField(max_length=50)
geom = models.MultiPolygonField(srid=32651, null=True, blank=True)
objects = models.GeoManager()
def __unicode__(self):
return self.hazard
hazard field in the model has the following values: 'High', 'Medium', 'Low'.
I wanted to create a report in a table format(HTML) like this:
I tried this so far:
getgeom = FloodHazard.objects.get(id=512).geom
getgeom_medium = FloodHazard.objects.get(id=620).geom
getgeom_low = FloodHazard.objects.get(id=638).geom
response_data = {}
response_data["medium"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom_medium).values( 'brgy_locat').annotate(countmedium=Count('brgy_locat')))
response_data["high"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom).values('brgy_locat').annotate( counthigh=Count('brgy_locat')))
response_data["low"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom_low).values('brgy_locat').annotate( countlow=Count('brgy_locat')))
result = {}
for category in response_data.values():
for element in category:
key = element.pop('brgy_locat')
if key not in result:
result[key] = {"loc":key}
result[key].update(element)
json_result = result.values()
return HttpResponse(list(json.dumps(json_result)), content_type='application/json')
The above code works fine as I am able to get my intended output. But as you examine it, I tried one id in each hazard type. So my problem now is to use filter to get all the ids and used it as reference in my GeoQuerySet. Any help will be appreciated. I'm trying to pass the data as JSON in my template because I'm using datatables.
This is how I get all the ids for e.g. hazard type "high"
reference = FloodHazard.objects.filter(hazard='High')
ids = reference.values_list('id', flat=True)
for id in ids:
#something has to be done here...