Django - Select related or join on two different base models - python

I have two base models SiteData and Showoroom Service that have model structure as per the below.
I need the SiteData info but I also would like to get link_type from the showroomservice model if there is a matching ID.
ive tried a few things thus far, none are getting what I need, what is the best way to achieve this?
Thanks
select related
>>> nd = ShowroomService.objects.select_related('site').all()
>>> nd
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 229, in __repr__
return '<%s %r>' % (self.__class__.__name__, data)
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 590, in __repr__
u = six.text_type(self)
TypeError: __str__ returned non-string (type SiteData)
Combining :
>>> complete_data = site_data | monitoring_data
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 310, in __or__
combined.query.combine(other.query, sql.OR)
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 529, in combine
"Cannot combine queries on two different base models."
AssertionError: Cannot combine queries on two different base models.
chaining
>>> final_data = chain(monitoring_data, site_data)
>>> for i in final_data:
... '{} {}'.format(i.location,i.link_Type)
...
Traceback (most recent call last):
File "<console>", line 2, in <module>
AttributeError: 'ShowroomService' object has no attribute 'location'
sites.models.py
class SiteData(models.Model):
location = models.CharField(max_length=50)
site_type = models.ForeignKey(SiteTypes, verbose_name="Site Type", \
on_delete=models.PROTECT)
subnet = models.GenericIPAddressField(protocol='IPv4')
routed_subnet = models.GenericIPAddressField(protocol='IPv4', \
verbose_name="Routed Link Subnet", blank=True, null=True)
bgp_as = models.CharField(max_length=6, verbose_name="BGP AS Number")
opening_date = models.DateField(verbose_name="Showroom opening date")
last_hw_refresh_date = models.DateField(verbose_name="Date of latest hardware refresh", \
blank=True, null=True)
is_live = models.BooleanField(default=False, verbose_name="Is this a live site?")
tel = models.CharField(max_length=20, blank=True, null=True)
address = models.CharField(max_length=255, blank=True, null=True)
town = models.CharField(max_length=255, blank=True, null=True)
...
class Meta:
verbose_name = "Site Data"
verbose_name_plural = "Site Data"
ordering = ('location',)
permissions = (
("can_view", "Can View"),
("can_view_mgmt", "Can View Management"),
)
def __str__(self):
return self.location
monitoring.models.py
from sites.models import SiteData
class ShowroomService(models.Model):
site = models.ForeignKey(SiteData, verbose_name="Site", \
on_delete=models.PROTECT)
link_type = models.CharField(max_length=200, blank=True, null=True)
preference = models.CharField(max_length=200, blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True, blank=True, null=True)
dashboard = models.BooleanField(default=True, verbose_name="display on monitoring dashboard?")
class Meta:
verbose_name = "Showroom Service Data"
verbose_name_plural = "Showroom Service Data"
def __str__(self):
return self.site

You can pull all related objects using django's "related manager". Documentation is available here: https://docs.djangoproject.com/en/2.0/ref/models/relations/#related-objects-reference
By calling showroom_service_set on a SiteData model, you can get the set of child records for each SiteData.
Just to explain why the listed attempts failed as well:
your __str__ methods on your models need to return strings. If they don't, you'll get that exception.
The pipe operator | is used for ORing together queries in django. That chunk of code is attempting to combine a query for 2 different types of models.
With the chain attempt, you've created a list containing two different types of models. One of which doesn't have a location attribute.
Here's a chunk of code to get the link type for all ShowroomService models attached to a SiteData model:
for site_data in SiteData.objects.all():
for showroom in site_data.showroom_service_set.all():
print showroom.link_type
I'm not sure how django handles camel-casing with related objects, so showroom_service_set is my best guess. You might have to do a little leg work on this to figure out what the actual set is called.
EDIT: There's something called prefetch_related. Here's a SO answer about it; I think it'll get you what you're looking for: https://stackoverflow.com/a/13096423/769971

Related

Django getting "first_name" is invalid keyword argument for this function" TypeError when creating an instance of my model class

Using Django 1.11 and django-pyodbc-azure latest version if it is relevant.
I am new to Django and have been following along the 1.11 tutorial without any issues until this, and I am incredibly confused.
Here is my models.py:
from django.db import models
# Create your models here.
class Player(models.Model):
first_name = models.CharField(max_length=20, name='First Name')
last_name = models.CharField(max_length=20, name='Last Name')
def __str__(self):
return '{}, {} ({})'.format(self.last_name, self.first_name, self.id)
class Game(models.Model):
players = models.ManyToManyField(Player, name='Players')
def __str__(self):
return ' vs. '.join(self.players)
class Round(models.Model):
GIN = 'GI'
UNDERCUT = 'UN'
KNOCK = 'KN'
ENDING_ACITONS = (
(GIN, 'Gin'),
(UNDERCUT, 'Undercut'),
(KNOCK, 'Knock'),
)
game = models.ForeignKey(Game, on_delete=models.CASCADE, name='Parent Game')
winner = models.ForeignKey(Player, on_delete=models.CASCADE, name='Winning Player')
points = models.IntegerField(name='Points Awarded')
end = models.CharField(max_length=2, choices=ENDING_ACITONS)
def __str__(self):
return '{} awarded {} points via {}'.format(self.winner, self.points, self.end.name)
Now when I run manage.py shell and type:
from game.models import *
bobby = Player(first_name='Bobby', last_name='Fisher')
I am met with this error:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Users\mteper\PycharmProjects\GinRummy\venv\lib\site-packages\django\db\models\base.py", line 571, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'first_name' is an invalid keyword argument for this function
Any insight would be greatly appreciated, as, like I said earlier, I am new to Django and Python in general.
It is the name argument that is causing problems. You should set verbose_name instead.
class Player(models.Model):
first_name = models.CharField(max_length=20, verbose_name='First Name')
last_name = models.CharField(max_length=20, verbose_name='Last Name')

Django refering to same model instances in Abstract Model

I have an abstract model from which a couple of my main models are inherited. Main difficulty in this case is that I have a need in reference to the same model, like a ForeignKey to self. I have read that the ForeignKey is not possible in abstract models and GenericForeignKey can help, however I can`t really make it work.
As I understand structure should be something like following:
class BaseModel(models.Model):
versions = GenericRelation('self')
date_created = models.DateTimeField(default=datetime.datetime.now)
is_deleted = models.BooleanField(default=False)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.PositiveIntegerField(blank=True, null=True)
content_object = GenericForeignKey('content_type', 'object_id')
class FirstModel(BaseModel):
some_fields...
class AnotherModel(BaseModel):
another_fields...
But with this approach I get an error:
>>> item1 = FirstModel.objects.get(id=1)
>>> item2 = FirstModel.objects.get(id=2)
>>> item2.content_object = item1
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/home/michael/.virtualenvs/diagspecgen/lib/python3.6/site-packages/django/contrib/contenttypes/fields.py", line 245, in __set__
ct = self.get_content_type(obj=value)
File "/home/michael/.virtualenvs/diagspecgen/lib/python3.6/site-packages/django/contrib/contenttypes/fields.py", line 163, in get_content_type
return ContentType.objects.db_manager(obj._state.db).get_for_model(
AttributeError: 'ReverseGenericRelatedObjectsDescriptor' object has no attribute '_state'
Is that I am trying to reach is absolutely impossible and the only solution is to explicitly create needed fields in existing models?
I tried to replicate your problem with ForeignKey on a abstract model, but it seems to work fine with Django version 1.11.1:
class BaseModel(models.Model):
other = models.ForeignKey('self', null=True, blank=True)
class Meta:
abstract = True
class FirstModel(BaseModel):
pass
class AnotherModel(BaseModel):
pass
Using the models:
>>> fm1 = FirstModel.objects.create()
>>> fm2 = FirstModel.objects.create()
>>>
>>> fm1.other = fm2
>>> fm1.save()
The following assignment to other results in an error:
>>> am = AnotherModel.objects.create()
>>> am.other = fm1
ValueError: Cannot assign "<FirstModel: FirstModel object>": "AnotherModel.other" must be a "AnotherModel" instance.

csv import to manytomanyfield Django

I used below code to import csv file to django model containing manytomanyfield Release.metamodules
>>> from app.models import Metamodule,Release
>>> reldata = csv.reader(open('/root/Django-1.6.5/django/bin/dashboard/release.csv'),delimiter=',')
for row in reldata:
q = Release(number = row[0],
notes= row[1],
changes = row[2],
metamodules = Metamodule.objects.filter(name = row[3]))
try:
q.save()
except:
# if the're a problem anywhere, you wanna know about it
print "there was a problem with line"
Error:
Traceback (most recent call last):
File "<console>", line 5, in <module>
File "/usr/local/lib/python2.7/site-packages/django/db/models/base.py", line 416, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'metamodules' is an invalid keyword argument for this function
As the field is ManyToManyField i used objects.fileter to get multiple records. But it is returning error.Please help me to fix this issue
models.py:
class Metamodule(models.Model):
name = models.CharField(max_length=50)
version = models.IntegerField(default=0)
modulename = models.ForeignKey(Module)
createdate = models.DateField(auto_now=True, null=True)
createdby = models.CharField(max_length=50)
def __unicode__(self):
return unicode(self.name)
class Release(models.Model):
number = models.IntegerField(default=0)
notes = models.CharField(max_length=50)
changes = models.CharField(max_length=50)
metamodules = models.ManyToManyField(Metamodule)
def __unicode__(self):
return unicode(self.number)
You can't create your Release object like that. You cannot create m2m relations from unsaved objects. See here
Try something like this :
for row in reldata:
q = Release(number=row[0], notes=row[1], changes=row[2])
# You have to save the object before adding the m2m relations
q.save()
metamodules = Metamodule.objects.filter(name=row[3])
for metamodule in metamodules:
q.metamodules.add(metamodule)
There is probably a better way to do the for loop but this is what you want to achieve.

Saving files to upload field in Django using a Python script

Building an application to list reports for inspections. The actual inspection report is going to be made available for download. Saving the reports to the database using django-db-file-storage.
Lots of records to process, so writing a script to do everything in bulk. Testing in the manage.py shell throws an error.
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from inspections.models import InspectionInformation, RestaurantInformation
file = open('/docs/Data/2011/12/12-07-11_1498.pdf', 'r').read()
InspectionInformation(
insp_rest_permit=RestaurantInformation.objects.get(rest_permit=int('1814')),
insp_date='2011-12-12',
insp_score='100',
insp_inspector='Philip',
insp_report=default_storage.save('report.pdf', ContentFile(file))
).save()
Traceback
Traceback (most recent call last):
File "<console>", line 6, in <module>
File "/venv/lib/python2.7/site-packages/django/core/files/storage.py", line 48, in save
name = self.get_available_name(name)
File "/venv/lib/python2.7/site-packages/django/core/files/storage.py", line 74, in get_available_name
while self.exists(name):
File "/venv/lib/python2.7/site-packages/db_file_storage/storage.py", line 77, in exists
model_class_path, content_field, filename_field, mimetype_field, filename = name.split('/')
ValueError: need more than 1 value to unpack
Models
from django.db import models
class RestaurantInformation(models.Model):
rest_permit = models.IntegerField(unique=True, verbose_name='Permit')
rest_name = models.CharField(max_length=200, verbose_name='Name')
rest_address = models.CharField(max_length=200, verbose_name='Address')
rest_city = models.CharField(max_length=100, verbose_name='City')
rest_zip = models.IntegerField(verbose_name='Zip Code')
rest_owner = models.CharField(max_length=200, verbose_name='Owner')
rest_latitude = models.CharField(max_length=40, verbose_name='Latitude')
rest_longitude = models.CharField(max_length=40, verbose_name='Longitude')
class Meta:
ordering = ['rest_name']
def __unicode__(self):
return self.rest_name + ', ' + self.rest_address + ', ' + self.rest_city
class InspectionInformation(models.Model):
insp_rest_permit = models.ForeignKey(RestaurantInformation, null=False, to_field='rest_permit')
insp_score = models.DecimalField(verbose_name='Score', decimal_places=2, max_digits=5)
insp_date = models.DateField(verbose_name='Date')
insp_inspector = models.CharField(max_length=200, verbose_name='Inspector')
insp_report = models.FileField(upload_to='restaurants.InspectionFile/bytes/filename/mimetype',
blank=True, null=True, verbose_name='Inspection Report')
class Meta:
unique_together = ("insp_rest_permit", "insp_score", "insp_date")
ordering = ['insp_date']
class InspectionFile(models.Model):
bytes = models.TextField()
filename = models.CharField(max_length=255)
mimetype = models.CharField(max_length=50)
1.It looks like db_file_storage.storage.save() expects their custom format specified to be used with the model plus the filename e.g. "console.ConsolePicture/bytes/filename/mimetype" + filename.
So for your example instead of
'report.pdf'
it would be
'restaurants.InspectionFile/bytes/filename/mimetype/report.pdf'
I looked at the documentation and it isn't clear why it's being done this way as this violates DRY by making you enter the same thing twice, but they use the same format throughout the DatabaseFileStorage class.
2.It also looks like there's a bug in the save method (line 60) where
mimetype = content.file.content_type
should be changed to
mimetype = content.content_type
And the file you pass it should be something with a content_type attribute so probably a Django SimpleUploadedFile:
from django.core.files.uploadedfile import SimpleUploadedFile
file_ = SimpleUploadedFile('report.pdf', open('/docs/Data/2011/12/12-07-11_1498.pdf', 'r').read())
The reason I think this is a bug is that when I tried passing in a mock object that looked like "content.file.content_type" I got a Python core library exception later on.

AttributeError Exception raised when trying to bulk delete items in Django

I'm trying to bulk delete all of the comments on a dev instance of my Django website and Django is raising an AttributeException.
I've got the following code on a python prompt:
>>> from django.contrib.comments.models import Comment
>>> Comment.objects.all().delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/jeff/.virtualenvs/osl_main-website/lib/python2.6/site-packages/django/db/models/query.py", line 441, in delete
obj._collect_sub_objects(seen_objs)
File "/home/jeff/.virtualenvs/osl_main-website/lib/python2.6/site-packages/django/db/models/base.py", line 569, in _collect_sub_objects
sub_obj._collect_sub_objects(seen_objs, self, related.field.null)
File "/home/jeff/.virtualenvs/osl_main-website/lib/python2.6/site-packages/django/db/models/base.py", line 585, in _collect_sub_objects
delete_qs = rel_descriptor.delete_manager(self).all()
AttributeError: 'ReverseSingleRelatedObjectDescriptor' object has no attribute 'delete_manager'
I'm not sure as to why the delete statement is not working. Can anyone help me with why this isn't working and what I can do to fix it?
Additional details about my models:
I have another model called OslComment that inherits from Comment. I also have a Vote model that points to entries in OslComment.
BaseCommentAbstractModel
class BaseCommentAbstractModel(models.Model):
"""
An abstract base class that any custom comment models probably should
subclass.
"""
# Content-object field
content_type = models.ForeignKey(ContentType,
verbose_name=_('content type'),
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField(_('object ID'))
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
# Metadata about the comment
site = models.ForeignKey(Site)
Comment
class Comment(BaseCommentAbstractModel):
"""
A user comment about some object.
"""
# Who posted this comment? If ``user`` is set then it was an authenticated
# user; otherwise at least user_name should have been set and the comment
# was posted by a non-authenticated user.
user = models.ForeignKey(User, verbose_name=_('user'),
blank=True, null=True, related_name="%(class)s_comments")
user_name = models.CharField(_("user's name"), max_length=50, blank=True)
user_email = models.EmailField(_("user's email address"), blank=True)
user_url = models.URLField(_("user's URL"), blank=True)
comment = models.TextField(_('comment'), max_length=COMMENT_MAX_LENGTH)
# Metadata about the comment
submit_date = models.DateTimeField(_('date/time submitted'), default=None)
ip_address = models.IPAddressField(_('IP address'), blank=True, null=True)
is_public = models.BooleanField(_('is public'), default=True,
help_text=_('Uncheck this box to make the comment effectively ' \
'disappear from the site.'))
is_removed = models.BooleanField(_('is removed'), default=False,
help_text=_('Check this box if the comment is inappropriate. ' \
'A "This comment has been removed" message will ' \
'be displayed instead.'))
OslComment
class OslComment(Comment):
parent_comment = models.ForeignKey(Comment, blank=True, null=True, related_name='parent_comment')
inline_to_object = models.BooleanField(default=False)
edit_timestamp = models.DateTimeField()
transformed_comment = models.TextField(editable=False)
is_deleted_by_user = models.BooleanField(default=False)
Vote
class Vote(models.Model):
"""
A vote on an object by a User.
"""
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey('content_type', 'object_id')
vote = models.SmallIntegerField(choices=SCORES)
Misc information:
Python Version: 2.6.5
Operating System: Linux Mint 9 (Linux 2.6.32-21-generic)
Django: 1.2
Database driver: postgresql_psycopg2 (2.2.1)
Edited: Originally I thought you couldn't do delete() on a QuerySet and was going to recommend you iterate over the items, but apparently you can do bulk deletes like that. Trying to iterate over the QuerySet might give you a better clue as to what's wrong, though.

Categories