How can you customize object creation in django? - python

In django rest framework, it's possible to make a function to customize the process of creating an object inside the serializer of that respective model, but I can't figure out how to do that in "vanilla" django, so to speak. What I need to do is take one field and do a bunch of stuff with it. encode it into a 256 character hash is all I have to worry about now. How can I go about doing what I need? I've been basing myself off of an online course and Django's documentation, but I either couldn't interpret it well enough or I just straight up haven't found it there. Here is the code I have so far, at least what I judge is relevant to the question. It's all in models.py:
class SpedFile(models.Model):
json_file = models.FileField(max_length=100)
sped_file = models.FileField(max_length=100)
integrity_hash = models.CharField(max_length=256)
line_counter = models.CharField(max_length=150000)
created_at = models.DateField(auto_now_add=True)
#classmethod
def create(cls, json_file):
file_bearer = json_file
m = hashlib.sha256()
m.update(file_bearer.encode('utf-8'))
integrity_hash = m.hexdigest()
new_object = cls(json_file=file_bearer, integrity_hash=integrity_hash)
return new_object

Related

How to create a custom function inside django model?

I have a django model
class UserInfluencerGroupList(models.Model):
list_name = models.CharField(max_length=255)
influencers = models.ManyToManyField(Influencer, blank=True)
user = models.ForeignKey(MyUser, on_delete = models.CASCADE)
def __str__(self):
return self.list_name
and my views function is:
def get_lists(request,user_email):
"""Get all the lists made by user"""
try:
user_instance = MyUser.objects.get(email=user_email)
except MyUser.DoesNotExist:
return HttpResponse(json.dumps({'message':'User not found'}),status=404)
if request.method == 'GET':
influencers_list = UserInfluencerGroupList.objects.all().order_by('id').filter(user=user_instance)
influencers_list = serializers.serialize('json',influencers_list, fields =['id','influencers','list_name'], indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True)
return HttpResponse(influencers_list,content_type='application/json',status=200)
else:
return HttpResponse(json.dumps({'message':'No lists found'}), status=400)
Apart from the usual data from list I also want to calculate the total_followers, total_likes and total_comments of each influencer in the list. The influencer model has fields for total_likes, comments and followers.
How should I write a function to calculate and display it along with all the other data that the list is returning
You should consider to use Django Rest Framework if you want to return a json of your own choice or/and if you're about to create your own rest api.
Alternative is to create the json all manually, i.e build the dictionary and then use json.dumps.
(If you really want to go "manual" see answer Convert Django Model to dict)
The django serializers does not support what you want to do:
option for serializing model properties (won't fix)
Quote for not fixing:
"I'm afraid I don't see the benefit of what you are proposing. The
serialization framework exists for the easy serialization of Django
DB-backed objects - not for the arbitrary serialization of _any_
object, and derived properties like the ones you are highlighting as
examples don't add anything to the serialized representation of a
DB-backed object..."

Django model set lookup very slow

I'm getting a very slow lookup in my Django models.
I have two tables:
class Scan(models.Model):
scan_name = models.CharField(max_length=32, unique=True, validators=[alphanumeric_plus_validator])
class ScanProcessingInfo(models.Model):
scan_name = models.CharField(max_length=32)
processing_name = models.CharField(max_length=64)
in_progress = models.BooleanField(default=False)
When I perform the following operation to get a list of all Scan objects which have a ScanProcessingInfo for a specific processing_name:
scans = models.Scan.objects.all()
scan_set = []
for scan in scans:
if self.set_type_definition.test_scan(scan, self.arg1, self.arg2):
scan_set.append(scan)
(test_scan routes to)
def get_proc_info_been_done(scan, spd_name):
try:
proc_info = models.ScanProcessingInfo.objects.get(scan_name = scan.scan_name)
except models.ScanProcessingInfo.DoesNotExist:
proc_info = None
if proc_info == None:
return False
return not proc_info.in_progress
the request takes about 10 seconds. There are 300 Scans in total and 10 ScanProcessingInfos. The db backend is an RDS MySQL db. I also expect someone will tell me off for using strings for the cross-table identifiers, but I doubt that's the cause here.
I'm sure I'm doing something obvious wrong, but would appreciate a pointer, thank you.
I think what you're asking is how to get all Scans for which a matching ScanProcessingInfo exists.
The first thing to do is to declare the actual relationship. You don't need to change your database (you should, but you don't have to); you can use your existing underlying field, but just tell Django to treat it as a foreign key.
class ScanProcessingInfo(models.Model):
scan = models.ForeignKey('Scan', to_field='scan_name', db_field='scan_name', on_delete=models.DO_NOTHING)
Now you can use this relationship to get all the scans in one go:
scan_set = Scan.objects.exclude(scanprocessinginfo=None)
Edit
To get all matching objects with a specific attribute, use the double-underscore syntax:
scan_set = Scan.objects.filter(scanprocessinginfo__processing_name=spd_name)
Use Many-to-one relationship.
scan_name = ForeignKey(Scan, related_name='processing_infos',on_delete=models.CASCADE)

Using JSON data in views

I've been working on Django-rest-framework for past few months. I did not quite understood how the json request can be used.Can you please help me, I got stuck here for months.
I have a third-party html snippet on another website and lets assume it sends this json data
[{"idcomment":1,"isFlagged":false,"isDeleted":false,"isApproved":true,"createdAt":"2015-11-22T12:39:33Z","numReports":0,"isEdited":false,"message":"xcvvzvc","isSpam":false,"isHighlighted":false,"ip_address":"","is_public":true,"tree_path":"0000000001","tone":"Neutral","forum":1,"parent":null,"topic":1,"last_child":null,"user":1}][{"idcomment":1,"isFlagged":false,"isDeleted":false,"isApproved":true,"createdAt":"2015-11-22T12:39:33Z","numReports":0,"isEdited":false,"message":"xcvvzvc","isSpam":false,"isHighlighted":false,"ip_address":"","is_public":true,"tree_path":"0000000001","tone":"Neutral","forum":1,"parent":null,"topic":1,"last_child":null,"user":1}]
My question: How can I use this json request data and do some verification like if the comment belongs to the correct topic.
I couldn't find any examples where its done. So I figured its possible in Flask by using something like this.
mod.route("/create/", methods=["POST"])
def create():
json = getJson(request)
check_required(json, ['date', 'thread', 'message', 'user', 'forum'])
uid = id_by_email(json['user'])
fid = id_by_sname(json['forum'])
if uid < 0 or fid < 0:
return send_resp(json)
if 'parent' in json:
parent = json['parent']
else:
parent = None
json['parent'] = None
if 'isApproved' in json:
approved = json['isApproved']
else:
approved = 0
json['isApproved'] = 0
if 'isHighlighted' in json:
highlighted = json['isHighlighted']
else:
highlighted = 0
json['isHighlighted'] = 0
if 'isEdited' in json:
edited = json['isEdited']
else:
edited = 0
json['isEdited'] = 0
if 'isSpam' in json:
spam = json['isSpam']
else:
spam = 0
json['isSpam'] = 0
if 'isDeleted' in json:
deleted = json['isDeleted']
else:
deleted = 0
json['isDeleted'] = 0
db.insert("""INSERT INTO posts (date,thread_id,message,user_id,forum_id,parent,approved,highlighted,edited,spam,deleted)
values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)""", (
json['date'], json['thread'], json['message'], uid, fid, parent, approved, highlighted, edited, spam, deleted))
pid = db.query("SELECT LAST_INSERT_ID() as id")[0]['id']
json['id'] = pid
return send_resp(json)
What is the alternative for something like this in django-rest-framework.
I am quite new, so please explain in simple language. I don't need any code, just searching how can I use json requests I get to the server.
It's a no-brainer I read the documentation several times
Disclaimer: I have also gonna all over through the django-rest-framework code
This job is handled by your Serializer Class :
The first thing we need to get started on our Web API is to provide a
way of serializing and deserializing the snippet instances into
representations such as json. We can do this by declaring serializers
that work very similar to Django's forms.
A serializer class is very similar to a Django Form class, and
includes similar validation flags on the various fields, such as
required, max_length and default.
If your serializer inherit of serializer.ModelSerializer then it use your model do validate your data like form class that inherit from form.ModelForm. And yes, you don't re-write any code to validate your data, and it seems to be magical. (DRY concept) But, of-course, you can define and override models validators in your serializer class.
I recommend you to re-read Django-Rest-Framework and specially Serializer part. It explain all serializers class that DRF provides with use cases.

Django - Checking the type of Multi-table inheritence Querysets

I'm trying to hold a kind of table of contents structure in my database. Simplified example:
models.py
class Section (models.Model):
title = models.CharField(max_length=80)
order = models.IntegerField()
class SectionClickable(Section):
link = models.CharField(max_length=80)
class SectionHeading(Section):
background_color = models.CharField(max_length=6)
views.py
sections = Section.objects.filter(title="Hello!")
for section in sections:
if(section.sectionheading):
logger.debug("It's a heading")
I need to do some processing operations if it's a SectionHeading instance, but (as in the Django manual), accessing section.sectionheading will throw a DoesNotExist error if the object is not of type SectionHeading.
I've been looking into alternatives to this kind of problem, and I'm skimming over Generic Foreign Keys in the contenttypes package. However, this seems like it would cause even more headaches at the Django Admin side of things. Could anyone advise on a better solution than the one above?
Edit: I avoided abstract inheritence because of the order field. I would have to join the two QuerySets together and sort them by order
well you could check the type:
if isinstance(section, SectionHeading)
but duck typing is generally preferred
edit:
actually, that probably won't work. the object will be a Section. but you can look for the attribute:
if hasattr(section, 'sectionheading')
or
try:
do_something_with(section.sectionheading)
except AttributeError:
pass # i guess it wasn't one of those
The solution I came up using involved an extra field pointing to the (rather useful) ContentType class:
class Section(models.Model):
name = models.CharField(max_length=50)
content_type = models.ForeignKey(ContentType,editable=False,null=True)
def __unicode__(self):
try:
return self.as_leaf_class().__unicode__()
except:
return self.name
def save(self, *args, **kwargs):
if(not self.content_type):
self.content_type = ContentType.objects.get_for_model(self.__class__)
super(Section, self).save(*args, **kwargs)
def as_leaf_class(self):
content_type = self.content_type
model = content_type.model_class()
if(model == Section):
return self
return model.objects.get(id=self.id)
If you're going through "base" object, I think this solution is pretty nice and comfortable to work with.
I've been using something similar to what second suggests in his edit:
class SomeBaseModel(models.Model):
reverse_name_cache = models.CharField(_('relation cache'), max_length=10,
null=True, editable=False)
def get_reverse_instance(self):
try:
return getattr(self, self.reverse_name_cache)
except AttributeError:
for name in ['sectionclickable', 'sectionheading']:
try:
i = getattr(self, name)
self.reverse_name_cache = name
return i
except ObjectDoesNotExist:
pass
Now, this isn't exactly pretty, but it returns the subclass instance from a central place so I don't need to wrap other statements with try. Perhaps the hardcoding of subclass reverse manager names could be avoided but this approach was enough for my needs.
OP here.
While second's answer is correct for the question, I wanted to add that I believe multi-table inheritence is an inefficient approach for this scenario. Accessing the attribute of the sub-class model would cause a query to occur - thus requiring a query for every row returned. Ouch. As far as I can tell, select_related doesn't work for multi-table inheritence yet.
I also ruled out ContentTypes because it wouldn't do it elegantly enough and seemed to require a lot of queries also.
I settled on using an abstract class:
class Section (models.Model):
title = models.CharField(max_length=80)
order = models.IntegerField()
class Meta:
abstract=True
ordering=['order']
Queried both tables:
section_clickables = SectionClickable.objects.filter(video=video)
section_headings= SectionHeading.objects.filter(video=video)
and joined the two querysets together
#Join querysets http://stackoverflow.com/questions/431628/how-to-combine-2-or-more-querysets-in-a-django-view
s = sorted(chain(section_headings, section_clickables), key=attrgetter('order'))
Lastly I made a template tag to check the instance:
from my.models import SectionHeading, SectionClickable
#register.filter()
def is_instance(obj, c):
try:
return isinstance(obj, eval(c))
except:
raise ObjectDoesNotExist('Class supplied to is_instance could not be found. Import it in the template tag file.')
so that in my template (HamlPy) I could do this:
- if s|is_instance:"SectionClickable"
%span {{s.title}}
- if s|is_instance:"SectionHeading"
%span{'style':'color: #{{s.color}};'}
{{s.title}}
The result is that I only used two queries, one to get the SectionClickable objects and one for the SectionHeading objects

Google App Engine Python Datastore

Basically what Im trying to make is a data structure where it has the users name, id, and datejoined. Then i want a "sub-structure" where it has the users "text" and the date it was modified. and the user will have multiple instances of this text.
class User(db.Model):
ID = db.IntegerProperty()
name = db.StringProperty()
datejoined = db.DateTimeProperty(auto_now_add=True)
class Content(db.Model):
text = db.StringProperty()
datemod= db.DateTimeProperty(auto_now_add = True)
Is the code set up correctly?
One problem you will have is that making User.ID unique will be non-trivial. The problem is that two writes to the database could occur on different shards, both check at about the same time for existing entries that match the uniqueness constraint and find none, then both create identical entries (with regard to the unique property) and then you have an invalid database state. To solve this, appengine provides a means of ensuring that certain datastore entities are always placed on the same physical machine.
To do this, you make use of the entity keys to tell google how to organize the entities. Lets assume you want the username to be unique. Change User to look like this:
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
Yes, that's really it. There's no username since that's going to be used in the key, so it doesn't need to appear separately. If you like, you can do this...
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
#property
def name(self):
return self.key().name()
To create an instance of a User, you now need to do something a little different, you need to specify a key_name in the init method.
someuser = User(key_name='john_doe')
...
someuser.save()
Well, really you want to make sure that users don't overwrite each other, so you need to wrap the user creation in a transaction. First define a function that does the neccesary check:
def create_user(username):
checkeduser = User.get_by_key_name(username)
if checkeduser is not None:
raise db.Rollback, 'User already exists!'
newuser = User(key_name=username)
# more code
newuser.put()
Then, invoke it in this way
db.run_in_transaction(create_user, 'john_doe')
To find a user, you just do this:
someuser = User.get_by_key_name('john_doe')
Next, you need some way to associate the content to its user, and visa versa. One solution is to put the content into the same entity group as the user by declaring the user as a parent of the content. To do this, you don't need to change the content at all, but you create it a little differently (much like you did with User):
somecontent = Content(parent=User.get_by_key_name('john_doe'))
So, given a content item, you can look up the user by examining its key:
someuser = User.get(somecontent.key().parent())
Going in reverse, looking up all of the content for a particular user is only a little trickier.
allcontent = Content.gql('where ancestor is :user', user=someuser).fetch(10)
Yes, and if you need more documentation, you can check here for database types and here for more info about your model classes.
An alternative solution you may see is using referenceproperty.
class User(db.Model):
name = db.StringProperty()
datejoined = db.DateTimeProperty(auto_now_add=True)
class Content(db.Model):
user = db.ReferenceProperty(User,collection_name='matched_content')
text = db.StringProperty()
datemod= db.DateTimeProperty(auto_now_add = True)
content = db.get(content_key)
user_name = content.user.name
#looking up all of the content for a particular user
user_content = content.user.matched_content
#create new content for a user
new_content = Content(reference=content.user)

Categories