AttributeError: 'list' object has no attribute 'objects' - python

I am trying to run the following which is throwing an
AttributeError: 'list' object has no attribute 'objects'
script.py
#Get Dota2 Item Rarities
dotaItemRarityUrl = 'http://api.steampowered.com/IEconDOTA2_570/GetRarities/v1?'
dotaItemRarityPayload = {'key': settings.SOCIAL_AUTH_STEAM_API_KEY,
'language': 'en',
}
dotaItemRarityInfo = requests.get(dotaItemRarityUrl, params=dotaItemRarityPayload)
dotaItemRarity = dotaItemRarityInfo.json()
dotaItemRarity = dotaItemRarity['result']['rarities']
print(dotaItemRarity)
#print(dotaItemQualities)
#Populate Database With Item Rarities that do NOT exist already
for rarity in dotaItemRarity:
print rarity
irarityId = rarity['id']
irarityProperName = rarity['localized_name']
irarityInternalName = rarity['name']
irarityColor = rarity['color']
q = dotaItemRarity.objects.filter(rarityId=irarityId)
print q
if len(q) == 0:
newRarity = dotaItemRarity(rarityId=irarityId,
rarityProperName=irarityProperName,
rarityInternalName=irarityInternalName,
rarityColor=irarityColor)
newRarity.save()
models.py
class dotaItemRarity(models.Model):
rarityId = models.IntegerField(max_length=3,primary_key=True)
rarityProperName = models.CharField(max_length=60)
rarityInternalName = models.CharField(max_length=50)
rarityColor = models.CharField(max_length=30)
def __unicode__(self):
return self.rarityInternalName
I am using south to handle migrations and have tried multiple options to fix this e.g. removing the tables and rebuilt them. As far as I can tell this should work, can anyone point me in the right direction.

dotaItemRarity is a list, and it has no objects attribute:
q = dotaItemRarity.objects.filter(rarityId=irarityId)
That's because you bound it to a list from your JSON result:
dotaItemRarity = dotaItemRarityInfo.json()
dotaItemRarity = dotaItemRarity['result']['rarities']
It is not a Django model, as you appear to expect it to be.
If you had the dotaItemRarity Django model imported into script.py, then the name is no longer bound to that model, as you replaced it with the list.
Rename the list to use a different name that doesn't mask the model.
Note that the Python style guide recommends that you use CamelCase names for classes (including Django models), to avoid such mistakes.
Following PEP 8 to refactor your code a little, as well as using some clearer naming an practices:
models.py:
class DotaItemRarity(models.Model):
rarity_id = models.IntegerField(max_length=3, primary_key=True)
rarity_proper_name = models.CharField(max_length=60)
rarity_internal_name = models.CharField(max_length=50)
rarity_color = models.CharField(max_length=30)
def __unicode__(self):
return self.rarity_internal_name
script.py:
#Get Dota2 Item Rarities
url = 'http://api.steampowered.com/IEconDOTA2_570/GetRarities/v1'
payload = {'key': settings.SOCIAL_AUTH_STEAM_API_KEY, 'language': 'en'}
response = requests.get(url, params=payload)
rarities = response.json()['result']['rarities']
for rarity in rarities:
rarity_id = rarity['id']
try:
DotaItemRarity.get(rarity_id=rarity_id)
except DotaItemRarity.DoesNotExist:
new_rarity = DotaItemRarity(
rarityId=rarity_id,
rarity_proper_name=rarity['localized_name'],
rarity_internal_name=rarity['name'],
rarity_color=rarity['color'])
new_rarity.save()

Related

Perform CRUD operations on product class?

I'm a newbie to Django-oscar and I'm trying to develop a simple CRUD operation on Product. I've forked the catalogue app and created a views.py file
I fired the query Product.objects.create(title='Hello') and a product does get created with the following error:
AttributeError: 'NoneType' object has no attribute 'attributes'
product_title = 'MyPhone'
upc=987654321
product_class = ProductClass.objects.get_or_create(name='Phone')
def createProduct(request):
line1
product.name = product_title
product.product_class = product_class
product.upc=upc
product.save()
When I put product=Product() in line1 I get the following error:
Cannot assign "(, False)": "Product.product_class" must be a "ProductClass" instance.
When I put product = Product.objects.create(upc=upc) I get the following error :
NoneType' object has no attribute 'attributes'
Anyone guide me on how to write a simple create operation?
ProductClass, Product, Category, ProductCategory = get_classes(
'catalogue.models', ('ProductClass', 'Product', 'Category',
'ProductCategory'))
create_from_breadcrumbs = get_class('catalogue.categories', 'create_from_breadcrumbs')
def _create_item(product_class, category_str, upc, title,
description, stats):
# Ignore any entries that are NULL
if description == 'NULL':
description = ''
# Create item class and item
product_class, __ = ProductClass.objects.get_or_create(name=product_class)
try:
item = Product.objects.get(upc=upc)
stats['updated_items'] += 1
except Product.DoesNotExist:
item = Product()
stats['new_items'] += 1
item.upc = upc
item.title = title
item.description = description
item.product_class = product_class
item.save()
# Category
cat = create_from_breadcrumbs(category_str)
ProductCategory.objects.update_or_create(product=item, category=cat)
return item
This is the actual way to manipulate products with provided information to the function in django oscar. For better design decisions you need to follow this convention. Modify it as you want. Let me know if you want more help. Thank you.

How to speed up writing in a database?

I have a function which search for json files in a directory, parse the file and write data in the database. My problem is writing in database, because it take around 30 minutes. Any idea how can I speed up writting in a database? I have few quite big files to parse, but parsing the file is not a problem it take around 3 minutes. Currently I am using sqlite but in the future I will change it to PostgreSQL.
Here is my function:
def create_database():
with transaction.atomic():
directory = os.fsencode('data/web_files/unzip')
for file in os.listdir(directory):
filename = os.fsdecode(file)
with open('data/web_files/unzip/{}'.format(filename.strip()), encoding="utf8") as f:
data = json.load(f)
cve_items = data['CVE_Items']
for i in range(len(cve_items)):
database_object = DataNist()
try:
impact = cve_items[i]['impact']['baseMetricV2']
database_object.severity = impact['severity']
database_object.exp_score = impact['exploitabilityScore']
database_object.impact_score = impact['impactScore']
database_object.cvss_score = impact['cvssV2']['baseScore']
except KeyError:
database_object.severity = ''
database_object.exp_score = ''
database_object.impact_score = ''
database_object.cvss_score = ''
for vendor_data in cve_items[i]['cve']['affects']['vendor']['vendor_data']:
database_object.vendor_name = vendor_data['vendor_name']
for description_data in cve_items[i]['cve']['description']['description_data']:
database_object.description = description_data['value']
for product_data in vendor_data['product']['product_data']:
database_object.product_name = product_data['product_name']
database_object.save()
for version_data in product_data['version']['version_data']:
if version_data['version_value'] != '-':
database_object.versions_set.create(version=version_data['version_value'])
My models.py:
class DataNist(models.Model):
vendor_name = models.CharField(max_length=100)
product_name = models.CharField(max_length=100)
description = models.TextField()
date = models.DateTimeField(default=timezone.now)
severity = models.CharField(max_length=10)
exp_score = models.IntegerField()
impact_score = models.IntegerField()
cvss_score = models.IntegerField()
def __str__(self):
return self.vendor_name + "-" + self.product_name
class Versions(models.Model):
data = models.ForeignKey(DataNist, on_delete=models.CASCADE)
version = models.CharField(max_length=50)
def __str__(self):
return self.version
I will appreciate if you can give me any advice how can I improve my code.
Okay, given the structure of the data, something like this might work for you.
This is standalone code aside from that .objects.bulk_create() call; as commented in the code, the two classes defined would actually be models within your Django app.
(By the way, you probably want to save the CVE ID as an unique field too.)
Your original code had the misassumption that every "leaf entry" in the affected version data would have the same vendor, which may not be true. That's why the model structure here has a separate product-version model that has vendor, product and version fields. (If you wanted to optimize things a little, you might deduplicate the AffectedProductVersions even across DataNists (which, as an aside, is not a perfect name for a model)).
And of course, as you had already done in your original code, the importing should be run within a transaction (transaction.atomic()).
Hope this helps.
import json
import os
import types
class DataNist(types.SimpleNamespace): # this would actually be a model
severity = ""
exp_score = ""
impact_score = ""
cvss_score = ""
def save(self):
pass
class AffectedProductVersion(types.SimpleNamespace): # this too
# (foreign key to DataNist here)
vendor_name = ""
product_name = ""
version_value = ""
def import_item(item):
database_object = DataNist()
try:
impact = item["impact"]["baseMetricV2"]
except KeyError: # no impact object available
pass
else:
database_object.severity = impact.get("severity", "")
database_object.exp_score = impact.get("exploitabilityScore", "")
database_object.impact_score = impact.get("impactScore", "")
if "cvssV2" in impact:
database_object.cvss_score = impact["cvssV2"]["baseScore"]
for description_data in item["cve"]["description"]["description_data"]:
database_object.description = description_data["value"]
break # only grab the first description
database_object.save() # save the base object
affected_versions = []
for vendor_data in item["cve"]["affects"]["vendor"]["vendor_data"]:
for product_data in vendor_data["product"]["product_data"]:
for version_data in product_data["version"]["version_data"]:
affected_versions.append(
AffectedProductVersion(
data_nist=database_object,
vendor_name=vendor_data["vendor_name"],
product_name=product_data["product_name"],
version_name=version_data["version_value"],
)
)
AffectedProductVersion.objects.bulk_create(
affected_versions
) # save all the version information
return database_object # in case the caller needs it
with open("nvdcve-1.0-2019.json") as infp:
data = json.load(infp)
for item in data["CVE_Items"]:
import_item(item)

Python populating a database with one-to-many relationship

I'm a beginner, so please go easy on me. I am working on a script so that I don't have to keep entering in data when I decide to drop the database. My entire script works well, except when I'm dealing with a one-to-many relationship. It will not save to the database. Can anyone tell me what I am doing wrong or point me in the right direction?
SCRIPT:
try:
pmod.Instrument.objects.get(title='kjkjsdfsadfs')
except pmod.Instrument.DoesNotExist:
u = pmod.Instrument()
u.title = 'Bach 42 Trombone'
u.price = 550.00
u.soundDescription = 'Good'
u.functionalityDescription = 'Good'
u.damageDescription = 'Good'
u.accessoryDescription = 'Good'
u.customerName = 'Jake'
u.customerEmail = 'ks#gmail.com'
u.instrumentCategory = 1
print('Good2')
u.save()
print('Instrument1 saved')
MODEL:
class Category(models.Model):
instrumentCategory=models.CharField(max_length=50,blank=True,null=True)
def __str__(self):
return self.instrumentCategory
class Instrument(models.Model):
title = models.CharField(help_text='title',max_length=50,blank=True,null=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
soundDescription=models.CharField(max_length=1000,blank=True,null=True)
functionalityDescription=models.CharField(max_length=1000,blank=True,null=True)
damageDescription=models.CharField(max_length=1000,blank=True,null=True)
accessoryDescription=models.CharField(max_length=1000,blank=True,null=True)
customerName=models.CharField(max_length=50,blank=True,null=True)
customerEmail=models.EmailField(max_length=254,help_text='Enter valid email address')
instrumentCategory=models.ForeignKey(Category)
u.instrumentCategory = 1
That's not how a models.ForeignKey field works in Django. You need to get an instance of the Category object and assign that to u.instrumentCategory.
u.instrumentCategory = pmod.Category.objects.get(id=1)
You may try :
u.instrumentCategory_id = 1

GAE - Model not saving while another model doing something similar does?

I'm having trouble getting a model to save (or be put()) correctly. The interesting part is that a model doing a very similar save before it works. Below are the relevant parts of the code. At the two logging points the first correctly returns the email of the user. However, the second one results in the error AttributeError: 'NoneType' object has no attribute 'c_user'. Obviously the setting and un-setting of the variables in this is not the correct way to do things, I've just added these to hunt down the problem to discover that the model isn't being saved. Any suggestions? Thank you much!
class Source(db.Model):
current_user = db.UserProperty()
class SourceMember(db.Model):
c_user = db.UserProperty()
x_position = db.IntegerProperty()
y_position = db.IntegerProperty()
...
user = users.get_current_user()
if user:
source_key = self.request.get('g')
if not source_key:
source_key = user.user_id()
source = Source(key_name = source_key,
current_user = user)
source.put()
else:
source = Source.get_by_key_name(source_key)
source = None
source = Source.get_by_key_name(source_key)
logging.warning(source.current_user)
if source:
sourceMember = SourceMember.get_by_key_name(user.user_id() + source_key)
if not sourceMember:
sourceMember = SourceMember(parent = source.key(),
key_name = user.user_id() + source_key,
c_user = user,
x_position = None,
y_position = None)
sourceMember.put()
sourceMember = None
sourceMember = SourceMember.get_by_key_name(user.user_id() + source_key)
logging.warning(sourceMember.c_user)
When you create the SourceMember you're giving it a parent, but then when you get it, the parent is missing. Source doesn't have a parent, so getting it just from its id works.

Retrieving a set of model objects that are indirectly related

I have 4 models:
class TransitLine(models.Model):
name = models.CharField(max_length=32)
class Stop(models.Model):
line = models.ForeignKey(TransitLine, related_name='stops')
class ExitType(models.Model):
name = models.CharField(max_length=32)
people_limit = models.PositiveSmallIntegerField()
class Exits(models.Model):
TOKEN_BOOTH = 0
GATE = 1
REVOLVING_DOOR = 2
EXIT_TYPES = (
(TOKEN_BOOTH, 'Token booth'),
(GATE, 'Gate'),
(REVOLVING_DOOR, 'Revolving door'),
)
name = models.CharField(max_length=32)
stop = models.ForeignKey(Stop, related_name='exits')
type = models.ForeignKey(ExitType, related_name='exits')
I have one TransitLine object. I want to retrieve all the unique ExitType objects that are related to the Stop objects of the TransitLine (that was a mouth full).
Some semi-pseudo code of what I want to do:
tl = TransitLine.objects.get(id=1)
exit_types = []
for s in tl.stops:
exit_types.append([e.type for e in s.exits])
unique_exit_types = list(set(exit_types))
Obviously, prefer to do this in one QuerySet call. Any suggestions?
I would try something like this:
ExitType.objects.filter(exits__stop__line=line).distinct()

Categories