Data not getting inserted in db in django - django

Hi I am trying to select data from a dropdown list and then save it in Category model.There is no problem in retrieving the data but when i check it using Category.objects.all(), I get this
<QuerySet [<Category: Category object>, <Category: Category object>, <Category: Category object>, <Category: Category object>]>
models.py:
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
user = models.ForeignKey(User)
category= models.CharField(max_length=100)
views.py:
def get_category(request):
cname = request.POST.get("dropdown1")
user = request.session.get('user')
obj=Category(user_id=user,category=cname)
obj.save()
return HttpResponse("Registeration succesfull")
With get_category i am trying to save entry selected from dropdown.It works fine but i guess nothing is being stored in the db.
I tried running this
Category.objects.get(category = "abc")
I get this error:
DoesNotExist: Category matching query does not exist.
Can someone tell if this is not the right way to insert data in db.

you are getting category object in Category.objects.all() because you have not specified any string or unicode name for the instances.
in your model append these
class Category(models.Model):
user = models.ForeignKey(User)
category= models.CharField(max_length=100)
def __str__(self):
return self.category
you can also replace __str__ with __unicode__
now the category names will be visible in the queryset.

Related

Django foreign key issue with django-import-export library (IntegrityError at /import/ FOREIGN KEY constraint failed)

I'm relatively new to Django and not an advanced programmer, so please pardon my ignorance.
What is working:
I have a Django application that uses one main model which connects to two secondary models with foreign keys. The application can correctly create companies from template and from admin, and can correctly display the "niche" drop-down field using a foreign key to the Category model and can correctly display the images using a foreign key from the CompanyImage model.
What is not working:
The django-import-export library can correctly import an XLS document from front end and from admin, but ONLY if I disable the Category and CompanyImage model that are relying on foreign keys. The library does import correctly with the default user=models.ForeignKey(User) in my main Company model, but the foreign keys that connect to the secondary models are causing a foreign key error: IntegrityError at /import/ FOREIGN KEY constraint failed.
What I need
The XLS sheet I am importing does not import the fields that use a foreign key, so I would like to disable those fields to avoid the foreign key error. It would be nice to import a niche/category field, but I can do without.
What I've tried
I've spent two days trying to fix this problem.
I've tried reading the django-import-export documentation.
I've tried adding list_filter and exclude in class Meta for the Resource model.
I've read through Dealing with import of foreignKeys in django-import-export.
I've read through foreign key in django-import-export.
I would be very grateful someone can help steer me in the right direction. Thank you.
Models.py
from django.db import models
from django.contrib.auth.models import User
from phonenumber_field.modelfields import PhoneNumberField
#had to use pip install django-phone-verify==0.1.1
from django.utils import timezone
import uuid
from django.template.defaultfilters import slugify
class Category(models.Model):
kind = models.CharField(verbose_name='Business Type',max_length=100,blank=True,)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.kind
class Company(models.Model):
#BASIC
title = models.CharField(verbose_name='company name',max_length=100,blank=True)
contact = models.CharField(verbose_name='director',max_length=100,blank=True)
phone_number = PhoneNumberField(blank=True)
email = models.EmailField(max_length=200,blank=True)
email_host = models.CharField(max_length=200,blank=True)
website = models.URLField(max_length=200,blank=True)
facebook = models.URLField(max_length=200,blank=True)
memo = models.TextField(blank=True)
niche = models.ForeignKey(Category, default=0000,on_delete=models.SET_DEFAULT)
#UPLOADS
profile_picture = models.ImageField(upload_to='prospects/images/', blank=True)
image = models.ImageField(upload_to='prospects/images/', blank=True)
file = models.FileField(upload_to='prospects/uploads', blank=True)
#TIME
date = models.DateField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
datecompleted = models.DateTimeField(null=True, blank=True) #null for datetime object
#BOOLIANS
important = models.BooleanField(default=False)
cold = models.BooleanField(default=False, verbose_name='these are cold leads')
warm = models.BooleanField(default=False, verbose_name='these are warm leads')
hot = models.BooleanField(default=False, verbose_name='these are hot leads')
#USER
user = models.ForeignKey(User, on_delete=models.CASCADE,null=True,blank=True)
#TEST MODEL
decimal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, default=00.00)
integer = models.IntegerField(blank=True, default=0000)
positive_int = models.PositiveIntegerField(null=True, blank=True, default=0000)
positive_small_int = models.PositiveSmallIntegerField(null=True, blank=True, default=0000)
#ADMIN CONSOLE
class Meta:
verbose_name_plural = "Companies"
def __str__(self):
if self.title == "":
print('empty string')
return "No Name"
elif type(self.title) == str:
return self.title
else:
return "No Name"
# this makes the title appear in admin console instead of object number
class CompanyImage(models.Model):
company = models.ForeignKey(Company, default=None, on_delete=models.CASCADE)
image = models.FileField(upload_to = 'prospects/images/',blank=True)
def __str__(self):
return self.company.title
resource.py
from import_export import resources
# from import_export import fields
from import_export.fields import Field
from import_export.fields import widgets
from .models import Company
from django.utils.encoding import force_str, smart_str
# The following widget is to fix an issue with import-export module where if i import any number from an xls file, it imports as a float with a trailing ,0
#could keep it a number and use trunc function to take away decimal but will make string
class DecimalWidget(widgets.NumberWidget):
def clean(self, value, row=None, *args, **kwargs):
print()
print(f"type of value is {type(value)}")
print()
if self.is_empty(value):
return ""
elif type(value) == float:
new_string = force_str(value)
seperator = '.'
new_string_witout_0 = new_string.split(seperator, 1)[0]
print()
print(f"the new type of value is {type(value)}")
print(f"the new value is {value}")
print()
return new_string_witout_0
else:
print("Aborting! it's not a float or empty string. will just return it as it is.")
return value
print()
print(f"type of value is {type(value)}")
print(f" the value returned is {value}")
print()
class CompanyResource(resources.ModelResource):
title = Field(attribute='title', column_name='name',widget=DecimalWidget())
contact = Field(attribute='contact', column_name='contact',widget=DecimalWidget())
phone_number = Field(attribute='phone_number', column_name='phone',widget=DecimalWidget())
# niche = Field(attribute='niche', column_name='niche',widget=DecimalWidget())
class Meta:
model = Company
exclude = ('niche')
fields = ('id','title','contact','phone_number', 'email','email_host','website','facebook')
export_order = ['id','title','contact','phone_number', 'email','email_host','website','facebook']
# fields = ( 'id', 'weight' )
admin.py
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export import resources
# from import_export import resources
from .models import Company,Category, CompanyImage
from.resources import CompanyResource
class CompanyResource(resources.ModelResource):
class Meta:
model = Company
class CompanyImageAdmin(admin.StackedInline):
model = CompanyImage
class CompanyAdmin(ImportExportModelAdmin):
resource_class = CompanyResource
inlines = [CompanyImageAdmin]
# Register your models here.
admin.site.register(Category)
admin.site.register(Company,CompanyAdmin)
#admin.register(CompanyImage)
class CompanyImageAdmin(admin.ModelAdmin):
pass
views.py
def importcompanies(request):
if request.method == 'GET':
return render(request, 'prospects/import.html')
else:
file_format = request.POST['file-format']
company_resource = CompanyResource()
dataset = Dataset()
new_companies = request.FILES['myfile']
if file_format == 'CSV':
imported_data = dataset.load(new_companies.read().decode('utf-8'),format='csv')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
elif file_format == 'XLSX':
imported_data = dataset.load(new_companies.read(),format='xlsx')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
elif file_format == 'XLS':
imported_data = dataset.load(new_companies.read(),format='xls')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
if result.has_errors():
messages.error(request, 'Uh oh! Something went wrong...')
else:
# Import now
company_resource.import_data(dataset, dry_run=False)
messages.success(request, 'Your words were successfully imported')
return render(request, 'prospects/import.html')
You have CompanyResource defined in two places, so this could be the source of your problem. Remove the declaration from admin.py and see if that helps.
As you say, fields and exclude are used to define which model fields to import. fields is a whitelist, whilst exclude is a blacklist, so you shouldn't need both.
Set up a debugger (if you haven't already) and step through to find out what is going on (this can save days of effort).
If it is still not working, please update your answer and try to be specific about the nature of the issue (see how to ask).

Creating a unique object using DateField()

I would just like to create a model that essentially prevents the same date being selected by two different users (or the same user).
E.g if User1 has selected 2019-01-10 as a "date" for a booking, then User2 (or any other Users) are not able to create an object with that same date.
I have created a very basic model that can allow different Users to create an object using the DateField(). Using the Django admin page, I can create different instances of objects by two different Users (admin and Test_User).
In order to try to ensure that a new object can't be created if that date has already been used by a different object I have tried the following approach:
a compare function that utilizes __dict__.
models.py
from __future__ import unicode_literals
from django.db import models, IntegrityError
from django.db.models import Q
from django.contrib.auth.models import User
from datetime import datetime
class Booking(models.Model):
date = models.DateField(null=False, blank=False)
booked_at = models.DateTimeField(auto_now_add=True)
booking_last_modified = models.DateTimeField(auto_now=True)
class PersonalBooking(Booking):
user = models.ForeignKey(User, on_delete=models.CASCADE)
def compare(self, obj):
excluded_keys = 'booked_at', '_state', 'booking_last_modified', 'user',
return self._compare(self, obj, excluded_keys)
def _compare(self, obj1, obj2, excluded_keys):
d1, d2 = obj1.__dict__, obj2.__dict__
for k,v in d1.items():
if k in excluded_keys:
continue
try:
if v != d2[k]:
pass
except IntegrityError as error:
print(error)
print('Date already selected by different User. Please select another date.')
admin.py
from django.contrib import admin
from . import models
from .models import Booking, PersonalBooking
class PersonalBookingAdmin(admin.ModelAdmin):
list_display = ('format_date', 'user', )
def format_date(self, obj):
return obj.date.strftime('%d-%b-%Y')
format_date.admin_order_field = 'date'
format_date.short_description = 'Date'
def user(self, obj):
return obj.user()
user.admin_order_field = 'user'
user.short_description = 'User'
admin.site.register(models.PersonalBooking, PersonalBookingAdmin)
It didn't work as I had hoped, objects with the same date could still be created by the same or different users. Perhaps there is a simpler way? Or maybe I need to use the Q() class? I am not very familiar with it.
Any help is greatly appreciated.
Thanks.
You could do this validation at the database level by setting the unique attribute to True in your model's field.
class Booking(models.Model):
date = models.DateField(null=False, blank=False, unique=True)
booked_at = models.DateTimeField(auto_now_add=True)
booking_last_modified = models.DateTimeField(auto_now=True)
But this would present issues if the field was changed later to store time.
If you are going to be storing the time as well, you could override the model's default save function to check that there isn't another Booking with the same date (__date) each time it is saved. exists() returns True if there is a match, so this will throw a ValidationError if there is a match.
from django.core.exceptions import ValidationError
class Booking(models.Model):
date = models.DateTimeField(null=False, blank=False)
booked_at = models.DateTimeField(auto_now_add=True)
booking_last_modified = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
# Make sure there are no bookings on the same day
if Booking.objects.exclude(pk=self.pk).filter(date__date=self.date.date).exists():
raise ValidationError('There cannot be two bookings with the same date.')
super(Booking, self).save(*args, **kwargs)
Try this
https://docs.djangoproject.com/en/2.1/ref/models/fields/#unique-for-date
For user column set unique_for_date=True

Auto Populate Slug field django

I have a model defined and over 100+ entries of data in my DB. I would like to auto populate a slug field and see it show up in the admin, since adding new entries for 100+ fields is not something I would like to do.
AutoSlug() field doesnt seem to be working when I add it to my model and make the migrations, prepopulated_fields = {'slug': ('brand_name',)} does not work using it within my admin.py and as well I have tried to add the default field on the slug as my desired field name within the Model but to no avail the solution didnt work.
Is their any other suggestions on how to get the slug filed pre-populated?
class Brand(models.Model):
brand_name = models.CharField(unique=True, max_length=100, blank=True, default="", verbose_name=_('Brand Name'))
slug = models.SlugField(max_length=255, verbose_name=_('Brand Slug'), default=brand_name)
You can try adding a save method to the Brand class.
from django.utils.text import slugify
class Brand(models.Model):
...
def save(self, *args, **kwargs):
self.slug = slugify(self.brand_name)
super(Brand, self).save(*args, **kwargs)
then run:
python manage.py shell
>>>from app.models import Brand
>>>brands = Brands.objects.all()
>>>for brand in brands:
>>> brand.save()
Also, I would change brand_name var to just name.
I think it's better to add a pre_save signal on the Brand model.
from django.dispatch import receiver
from django.db.models import signals
from django.contrib.auth import get_user_model
from django.utils.text import slugify
#receiver(signals.pre_save, sender=<model name>)
def populate_slug(sender, instance, **kwargs):
instance.slug = slugify(instance.brand_name)```
I think I have an idea, which would do the job, however I am not sure if that would be the best way to do it.
I would use slugify function. I would create the view which - after it was called - would get all model's objects, iterate over them and populate each model's slug field using django.utils.text.slugify function with model's brand_name as a value.

Testing model - how to create records

according to https://docs.djangoproject.com/en/1.9/topics/testing/overview/ :
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
I want to create setUp to my model class:
class Post(models.Model):
author = models.ForeignKey('auth.User')
tags = models.ManyToManyField('blogUserPlane.Tag')
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
This is my NOT WORKING setUp:
def setUp(self):
Post.objects.all().create(author=User(), tag=models.ManyToManyField('blogUserPlane.Tag'), title="title1", text="text1", created_date=None, published_date=None)
What is correct way to create records of model with ManyToManyField and ForeginKey?
If you want to enter a value in a ForeignKey or ManyToMany field ,you first need to import that value .
For example if you want to enter a value in author field ,
from django.contrib.auth.models import User
user = User.objects.get(username = 'your_username')
Post.objects.create(author = user)
To save M2M
Save some values in the link table
`tag = blogUserPlane.Tag()
...
tag.save()`
To save Foreign key
from django.contrib.auth.models import User
post = Post()
post.author = User
...
post.tags.add(tag)
post.save()

django ForeignKey model filter in admin-area?

Hi I need really very very simple example. First my models:
#This my student models
from django.db import models
SEX_CHOICES= (
('M', 'Male'),
('F', 'Female'),
)
class Students(models.Model):
student_name = models.CharField(max_length=50)
student_sex = models.CharField(max_length=8, choices=SEX_CHOICES)
student_city = models.Charfield(max_length=50)
student_bio = models.TextField()
def __unicode__(self):
return self.student_name
O.K. Let see my ClassRooms Model.
#This my ClassRooms models
from django.db import models
from myproject.students.models import *
class ClassRooms(models.Model):
class_number= models.CharField(max_length=50)
class_student_cities = models.ForeignKey(Students)
class_year = models.DateField()
def __unicode__(self):
return self.class_number
How can i show in the class_student_cities area the Students.student_city datas? I guess that about django-admin area. When i do it withclass_student_cities = models.ForeignKey(Students) i just see in that area the Students.student_name data (ex: John Smith). I want to see JUST Students.student_cities data (ex: NewYork). Can you give me a little example?
Should i use something like that:
class_student_cities = models.ForeignKey(Students.student_cities)
Many Thanks!
Try redifinition unicode method.
def __unicode__(self):
return self.student_city
So you'll see in the field student city.
Well, I tried to remake your application to set data with forms class. Something like this in admin.py in your application:
from django.contrib import admin
from django import forms
from myapp.models import *
class ClassRoomsAdminForm(forms.ModelForm):
class Meta:
model = ClassRoom
def __init__(self, *arg, **kwargs):
super(ClassRoomsAdminForm, self).__init__(*arg, **kwargs)
self.fields[' class_student_cities'].choices = [(csc.id,csc.student_city) for csc in Students.objects.all()
class ClassRoomsAdmin(admin.ModelAdmin):
form = ClassRoomsAdminForm
admin.site.register(ClassRooms,ClassRoomsAdmin)
Maybe you'll need to fix something, but I hope it will work. You will set init function to your forms, so in admin panel you set all choices to everything you keep in your Students model. csc.id you'll need to make this object iterable (cities aren't unique) and then you can choose everything from Students model to set in the field.