Django ORM Object has no attribute '_set' - python

I assumed Django automatically created the _set for me but I'm the following error.
for dep_badge in self.badge.badge_set.all():
AttributeError: 'Badge' object has no attribute 'badge_set'
Models:
class Badge(RewardBase):
"""
Represents a Badge.
"""
name = models.CharField(max_length=60, help_text="Name of the badge")
description = models.TextField(max_length=150)
reputation_value = models.IntegerField(help_text="Value given in accumulate reputation", default=0)
reputation_prerequisite = models.IntegerField(help_text="Point value needed to obtain", default=0)
difficulty_level = models.IntegerField(choices=STATUS_TYPES, default=STATUS_EASY,
help_text="Badge difficulty")
class Award(RewardBase):
"""
Representation of a badge awarded to a user.
"""
description = models.CharField(max_length=100, choices=STATUS_TYPES, default=STATUS_GENERAL)
value = models.IntegerField(default=0)
read = models.BooleanField(default=False, help_text="Has the user read this?")
created = models.DateTimeField(blank=True, null=True, editable=False)
hidden = models.BooleanField(default=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
badge = models.ForeignKey("Badge")
def save(self, *args, **kwargs):
super(Award, self).save(*args, **kwargs)
for dep_badge in self.badge.badge_set.all():
dep_badge.check_prerequisites(self.user, sel
f.badge, self)

Badge has no badge_set.No foreign key to itself. Maybe u mean award_set?

It looks like you intend to do
self.badge.award_set.all()
instead. badge_set is looking for a reverse relationship to the Badge model, which does not exist.

Related

How to add Two auto-generated field in one model in Django

I am in need to create two auto-generated fields:
1st field is ID and I am taking the position that is equivalent to id or we can say it is also an auto-generated field in the model.
here is the code which I am integrating:
class DeviceControl(models.Model):
vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE)
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
position = model.[what do I write here to make it auto generated or equal to id]
def __str__(self):
return self.name
please help me to solve this.
You can override the save method to set the initial value of position:
class DeviceControlPolicy(models.Model):
vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE)
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
position = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.position == None:
self.position = self.id
# You need to call save two times since the id value is not accessible at creation
super().save()

How to autopopulate a field in models.py

I have a class named Property with a field property_type, i wana autofill this field when i create one of the other models who have onetoone relationship with Property
I want the when i create a Apartment in django admin for exp the property_type in Property should autofill with the "Apartment", when i create Villa in django admin it should autofill with "villa"
class Property(models.Model):
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="agent_of_property")
district_id = models.ForeignKey(District, on_delete=models.CASCADE)
slug = models.SlugField(max_length=255, unique=True)
property_type = models.CharField(choices=PROPERTY_TYPE, max_length=20)
title = models.TextField(verbose_name="Titulli", help_text="Vendos titullin e njoftimit", max_length=500)
description = models.TextField(verbose_name="Pershkrimi", help_text="Vendos pershkrimin",max_length=1000)
address_line = models.CharField(verbose_name="Adresa", help_text="E nevojeshme",max_length=255)
price = models.IntegerField()
area = models.IntegerField()
views = models.IntegerField(default=0)
documents = models.CharField(verbose_name="Dokumentacioni", help_text="Dokumentat", max_length=255)
status = models.BooleanField(default=True)
activity = models.CharField(max_length=20, choices=ACTION_OPTION)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Prona"
verbose_name_plural = "Pronat"
def get_absolute_url(self):
return reverse("pronat:property_detail", args=[self.slug])
def __str__(self):
return self.title
class Apartment(Property):
property_id = models.OneToOneField(Property, on_delete=models.CASCADE, parent_link=True, primary_key=True)
floor = models.IntegerField(default=0)
room_num = models.IntegerField(default=0)
bath_num = models.IntegerField(default=0)
balcony_num = models.IntegerField(default=0)
class Meta:
verbose_name = "Apartament"
verbose_name_plural = "Apartamentet"
def save(self, *args, **kwargs):
self.property_type = "Apartment"
class Villa(Property):
property_id = models.OneToOneField(Property, on_delete=models.CASCADE, parent_link=True, primary_key=True)
living_room = models.IntegerField(default=1)
floors = models.IntegerField(default=1)
room_num = models.IntegerField(default=1)
bath_num = models.IntegerField(default=1)
balcony_num = models.IntegerField(default=0)
class Meta:
verbose_name = "Vila"
verbose_name_plural = "Vilat"```
I don't understand what your are doing. If you are inheriting from Property models in Apartment just remove OneToOneField and your save method would be
def save(self, *args, **kwargs):
self.property_type = 'Apartment'
super().save(*args, **kwargs)
But if you really want to use OneToOneField, replace Property inherit with models.Model and your save method should look like this.
def save(self, *args, **kwargs):
self.property_id.property_type = 'Apartment'
self.property_id.save()
super().save(*args, **kwargs)
For 2nd case you can also use django signal
from django.db.models.signal import post_save
# ...
def populate_property_type(sender, created, instance, **kwargs):
if sender.__name__ == 'Apartment':
instance.property_id.property_type = 'Apartment'
instance.property_id.save()
# condition for Villa
post_save.connect(populate_property_type, sender=Apartment)
post_save.connect(populate_property_type, sender=Villa)
I would suggest that you should add field in Appartment table with the name appartment_type and remove property_type from Property. But If you don't want to do that then Two ways are possible for your case.
1.When you are adding values from Django admin, you should also add the property_type from Admin.In that case you don't need to override save method.
Register your Property and Appartment Table in one view.
Make the admin Tables of Property and Appartment for admin view. Then register it like this way i-e
admin.site.register(PropertyAdmin, AppartmentAdmin)
and add values into both tables.
2: Simply override the save method and add this
def save(self, *args, **kwargs):
self.property_id.property_type = 'Apartment' # you should add other field in Appartment table just avoid hard coded 'Apartment'
self.property_id.save()
super().save(*args, **kwargs)

foreign key in django-import-export

First of all pardon me for my poor English. I'm using django-import-export to upload excel file into my student model that has foreign key relationship with university model
student.. models.py:
class Student(models.Model):
institution = models.ForeignKey(University, on_delete=models.CASCADE)
id = models.CharField(max_length=200, primary_key=True)
first_name = models.CharField(max_length=200)
middle_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
age = models.IntegerField()
faculty = models.CharField( max_length=200, null=True, blank=True)
program = models.CharField( max_length=200, null=True, blank=True)
def __str__(self):
return self.first_name
university.. models.py:
class University(models.Model):
name = models.CharField(max_length=300)
email = models.EmailField(max_length=255, unique=True)
phone_no1 = PhoneNumberField()
phone_no2 = PhoneNumberField(blank=True)
fax_no = PhoneNumberField()
website = models.URLField(max_length=200)
pob = models.IntegerField()
city = models.CharField(max_length=200, blank=True)
logo = models.ImageField(upload_to="logos/", blank=True, null=True)
def __str__(self):
return self.name
After reading django-import-export documentation about ForeignKeyWidget
I edited my resources.py file as following and it works fine when I upload excel file that contain institution id and other student information
resources.py
class StudentResource(resources.ModelResource):
institution = fields.Field(
column_name='institution',
attribute ='institution',
widget = ForeignKeyWidget(University, 'id')
)
class Meta:
model=Student
But I don't want to include institution id into my excel file while I am uploading, because I can find the institution id from Registrar Staff logged in since the RegistrarStaff model has foreign key relationship with university model
class RegistrarStaff(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key = True)
university = models.ForeignKey(University, on_delete=models.CASCADE, null=True)
phone_number = models.CharField(max_length=20)
def __str__(self):
return str(self.user)
This is the way I able to find institution id based on whose university Registrar Staff is logged in and passed the value into resource like on number 4 in views.py
views.py:
def upload(request):
if request.method == 'POST':
loged=request.user.id
univ = RegistrarStaff.objects.get(pk=loged).university_id
student_resource = StudentResource(institution=univ)
dataset = Dataset()
new_student = request.FILES['myfile']
if not new_student.name.endswith('xlsx'):
messages.info(request,'Wrong format')
return render(request, 'upload.html')
imported_data = dataset.load(new_student.read(), format='xlsx')
for data in imported_data:
value = Student(
data[0],
data[1],
data[2],
data[3],
data[4],
data[5],
)
value.save()
return render(request, 'upload.html')
And I intialized it in resources.py as follow
resources.py:
class StudentResource(resources.ModelResource):
def __init__(self, *args, **kwargs):
self._institution=kwargs.pop('institution', None)
super().__init__(*args, **kwargs)
print(self._institution)
class Meta:
model=Student
So, is there anyway I can set the value of institution id = self._institution so as to able to upload excel file that doesn't contain institution id????
You are on the right lines. The way to do this is to pass the institution instance (or id) into the constructor, which is what you have already. All you need to do is to set the institution instance onto the Student model instance before it is saved:
class StudentResource(resources.ModelResource):
def __init__(self, *args, **kwargs):
self._institution=kwargs.pop('institution', None)
super().__init__(*args, **kwargs)
print(self._institution)
def before_save_instance(self, instance, using_transactions, dry_run):
setattr(instance, "institution", self._institution)
class Meta:
model=Student
However, you are bypassing the django-import-export framework by calling Student.save() directly. Don't do this. Use the framework to handle instance creation for you (docs):
result = student_resource.import_data(imported_data, dry_run=True)

Direct assignment to the forward side of a many-to-many set is prohibited

I'm trying to write a script that will fill database from json file. It looks like this:
class Command(BaseCommand):
def handle(self, *args, **options):
categories = load_from_json('categories')
ProductCategory.objects.all().delete()
for category in categories:
new_category = ProductCategory(**category)
new_category.save()
restaurants = load_from_json('restaurants')
Restaurant.objects.all().delete()
for restaurant in restaurants:
category_name = restaurant['category']
_category = ProductCategory.objects.get(name=category_name)
restaurant['category'] = _category
new_restaurant = Restaurant(**restaurant)
new_restaurant.save()
When i run it, django throws an error: Direct assignment to the forward side of a many-to-many set is prohibited. Use category.set() instead.
My models looks like this:
class ProductCategory(models.Model):
name = models.CharField(verbose_name='наименование категории', max_length=64, unique=True)
image = models.ImageField(upload_to='category_images', blank=True)
description = models.TextField(verbose_name='описание категории', blank=True)
def __str__(self):
return self.name
class Restaurant(models.Model):
name = models.CharField(verbose_name='наименование ресторана', max_length=64, unique=True)
description = models.TextField(verbose_name='описание категории', blank=True)
image = models.ImageField(upload_to='restaurant_images', blank=True)
category = models.ManyToManyField(ProductCategory)
def __str__(self):
return self.name
Looks like many people have encountered with this problem, but i struggle with finding a solution to this.

Django not assigning any primary key

When saving my table Django does not seem to be assigning any primary key? I'm I missing something?
class Campaign(models.Model):
campaignid = models.CharField(max_length=255, primary_key=True, db_column='campaignID')
name = models.CharField(max_length=105)
active = HibernateBooleanField(default=False)
created = models.DateTimeField()
modified = models.DateTimeField(null=True, blank=True)
companyid = models.ForeignKey(Company, null=True, db_column='companyID', blank=True)
class Meta:
db_table = u'campaign'
def __unicode__(self):
return self.name
Ok as my model was generated from an existing table using guid I had to keep it as CharField adding this seemed to work:
def save(self, *args, **kwargs):
if not self.campaignid:
self.campaignid = hashlib.sha1(str(random.random())).hexdigest()
super(Campaign, self).save(*args, **kwargs)

Categories

Resources