can I save models in this way in Django ? - python

first_obj = MyFirstModel()
second_obj = ImageModel()
first_obj.name = "newname"
first_obj.phonenr = "9898876"
second_obj.image = "new image"
first_obj.save()
first_obj.create(second_obj) #<------ can i do this?
would this save the second object? is it ever possible to do this?

I think you are getting confused, try this:
class ImageModel(models.Model):
image = models.ImageField()
class MyFirstModel(models.Model):
name = ...
image = models.ForeignKey(Image)
> image_model_instance = ImageModel()
> image_model_instance.save()
> first_model_instance = MyFirstModel(name="foo")
> first_model_instance.image = image_model_instance
> first_model_instance.save()
There is a create() function, but it is used for creating and saving new instances of a model:
first_model_instance = MyFirstModel.objects.create(Name="foo")
so the same as:
first_model_instance = MyFirstModel()
first_model_instance.save()

Related

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.

save ImageField mongoengine

I have following class definition in mongoengine orm:
import mongoengine as me
class Description(me.Document):
user = me.ReferenceField(User, required=True)
name = me.StringField(required=True, max_length=50)
caption = me.StringField(required=True, max_length=80)
description = me.StringField(required=True, max_length=100)
image = me.ImageField()
in my post method of my tornado web requesthandler:
from PIL import Image
def post(self, *args, **kwargs):
merchant = self._merchant
data = self._data
obj_data = {}
if merchant:
params = self.serialize() # I am getting params dict. NO Issues with this.
obj_data['name'] = params.get('title', None)
obj_data['description'] = params.get('description', None)
path = params.get('file_path', None)
image = Image.open(path)
print image # **
obj_data['image'] = image # this is also working fine.
obj_data['caption'] = params.get('caption', None)
obj_data['user'] = user
des = Description(**obj_data)
des.save()
print obj_data['image'] # **
print des.image # This is printing as <ImageGridFsProxy: None>
** print obj_data['image'] and print image are printing following:
<PIL.PngImagePlugin.PngImageFile image mode=1 size=290x290 at 0x7F83AE0E91B8>
but
des.image still remains None.
Please suggest me what is wrong here.
Thanks in advance to all.
You can not just put PIL objects into a field with obj.image = image that way. You must do:
des = Description()
des.image.put(open(params.get('file_path', None)))
des.save()
In other words, ImageField should be filled with file object after creating an instance by calling put method.

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