With Django I can use the OneToOneField like this to create a relationship:
user = models.OneToOneField('auth.User')
How can I make a model (example below) that would get the current site_id when trying to upload an image:
class Image(models.Model):
site = # something here
user = models.OneToOneField('auth.User')
image = models.ImageField(upload_to='headers')
image_thumbnail = ImageSpecField(source='image', processors=[ResizeToFit(1920)], format='JPEG', options={'quality': 90})
image_admin_thumb = ImageSpecField(source='image', processors=[ResizeToFit(300)], format='JPEG', options={'quality': 80})
name = models.CharField(max_length=50)
date = models.DateTimeField(auto_now=True)
You can do one of 2 things:
You can use the get_current_site shortcut, but this would require the request object
You can get the Site object from settings.SITE_ID - this would need an additional lookup though.
For the second case, the usage would be something like this:
from django.contrib.sites.models import Site
from django.conf import settings
def set_current_site():
return Site.objects.get(pk=settings.SITE_ID)
and in the models:
site = models.ForeignKey(Site, default=set_current_site)
Related
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).
I have created models.py, views.py, and urls.py and later on accordingly updated data.html file but when I click on the delete button it gives me an error. so the error file also attached for reference. Help appreciated and waiting for resolution.
error file
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/delete/
Using the URLconf defined in student.urls, Django tried these URL patterns, in this order:
admin/
[name='index']
export/ [name='export']
export-pdf [name='export-pdf']
register/ [name='register']
login/ [name='login']
home/ [name='home']
logout/ [name='logout']
upload/ [name='upload']
result/ [name='result']
dashbord/ [name='dashbord']
data/ [name='data']
delete/<int:id>
^static/(?P<path>.*)$
The current path, delete/, didn’t match any of these.
You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
urls.py
path('data/', views.data, name='data'),
path('delete/<int:id>', views.delete),
data.html
<a href="/edit/{{ student.id }}" class="btn btn-success"><span>Edit</span></a
Delete
views.py
def data(request):
data1 = Contact.objects.all()
# myFilter = OrderFilter()
dict = {
"data1":data1
}
return render(request, 'data.html', context=dict)
# Delete Data
def delete(request):
data1 = Contact.objects.all(id=id)
data1.delete()
return redirect("/data")
model.py
from django.db import models
from django.db.models.fields import CharField
from django.contrib import admin
# Create your models here.
class Contact(models.Model):
name = models.CharField(max_length=50, default="")
contact = models.CharField(max_length=50, default='')
address = models.TextField(max_length=50, default='')
program = models.CharField(max_length=50, default='')
email = models.CharField(max_length=50, primary_key=True, null=False, unique=True)
w3review = models.TextField(max_length=60, default="")
def __str__(self):
return self.name
class Cv(models.Model):
filename = models.CharField(max_length=20)
upload = models.FileField(upload_to='cv')
def __str__(self):
return self.filename
I think you didnt specify the id number after
http://127.0.0.1/delete:8000/--id-here--
I think you need to use get() method instead of all() method. You code should be something like this:
def delete(self, request, id):
data1 = Contact.objects.get(id=id)
data1.delete()
return redirect("/data")
And you must specify the id number according to #Ariel's Answer.
I would really appreciate some help on this because I'm completely stuck. I've started up a simple django app (trying to make an instagram clone). However, when I try to display the post objects (which I created in the django admin page) nothing is displayed in index.html, so I tried printing out the objects in the views.py and it's returning to me an empty query set. I don't quite understand what I'm doing wrong and why I can't access the objects? When I print out the username I am able to get that, but then nothing for both post and stream objects. Please I'm so stuck any advice would be appreciated.
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.template import loader
from django.http import HttpResponse
# Create your views here.
from post.models import post, stream
#login_required
# we are getting all of the string objects that are created for the user
def index(request):
user = request.user
print(user)
posts = stream.objects.filter(user=user)
print(posts)
group_ids = []
#then looping through and getting post id to a list
for posted in posts:
group_ids.append(posted.post_id)
print(group_ids)
#then filtering them so that you can display it in the index
#selecting a specific post by id
post_items = post.objects.filter(id__in=group_ids).all().order_by('-date')
template = loader.get_template('index.html')
context = {'post_items' : post_items}
return(HttpResponse(template.render(context, request)))
models.py
from django.db import models
from django.contrib.auth.models import User
import uuid
# Create your models here.
from django.db.models.signals import post_save
from django.utils.text import slugify
from django.urls import reverse
def user_directory_path(instance,filename):
# this file is going to be uploaded to the MEDIA_ROOT /user(id)/filename
return('user_{0}/{1}'.format(instance.user.id,filename))
class tag(models.Model):
title = models.CharField(max_length = 80, verbose_name = 'tag')
slug = models.SlugField(null = False, unique = True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
# for when people click on the tags we can give them a url for that
# def get_absolute_url(self):
# return(reverse('tags', args = [self,slug]))
def __str__(self):
return(self.title)
def save(self,*args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return(super().save(*args, **kwargs))
class post(models.Model):
# will create a long id for each post
id = models.UUIDField(primary_key=True, default = uuid.uuid4, editable = False)
image = models.ImageField(upload_to = user_directory_path, verbose_name= 'image', null = True)
caption = models.TextField(max_length = 2000, verbose_name = 'caption')
date = models.DateTimeField(auto_now_add = True)
tags = models.ManyToManyField(tag, related_name='tags')
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField()
def get_absolute_url(self):
return reverse('postdetails', args=[str(self.id)])
# def __str__(self):
# return(self.user.username)
class follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower')
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following')
class stream(models.Model):
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='stream_following')
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(post, on_delete=models.CASCADE)
date = models.DateTimeField()
def add_post(sender, instance,*args, **kwargs):
# here we are filtering all the users that are following you
post = instance
user = post.user
followers = follow.objects.all().filter(following=user)
for follower in followers:
streams = stream(post=post, user=follower.follower, date = post.date, following = user)
streams.save()
post_save.connect(stream.add_post, sender=post)
output from print statements
user
<QuerySet []>
[]
I figured it out. It wasn't an issue with the code, but the way that I was creating posts in the admin panel. So because you can only view posts from users that you are following, the posts that I was creating weren't showing up. So I had to create another user, and follow that user, then have the new user post something. Then the post shows up in the page!
This is for a game mod filesharing site. I have Apps Mods and Games. Each hold, you guessed it, Mods and Games!
Here is my Mods model:
from django.db import models
# Register storage backend TODO
def mod_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/<game>/<filename>
# Example code from https://docs.djangoproject.com/en/1.9/ref/models/fields/
return 'user_{0}/{1}'.format(instance.user.id, filename)
# Create your models here.
class Mods(models.Model):
title = models.CharField(max_length=30)
author = models.CharField(max_length=30)
game = models.ForeignKey(
'games.Games',
on_delete=models.CASCADE,
)
website = models.URLField()
repoWebsite = models.URLField()
upload = models.FileField(upload_to=mod_directory_path)
Here is my Games model:
from django.db import models
# Create your models here.
class Games(models.Model):
title = models.CharField(max_length=30)
developer = models.CharField(max_length=30)
website = models.URLField()
slug = models.SlugField()
I want to autoset the mod_directory_path to the slug of the Games model.
For example, if Mod item "Dynamic War Sandbox" has a ForeignKey of a unique ID pointing to the Arma 3 game, I want the file upload path to be based on the slug of the database entry for Arma 3.
MEDIA_ROOT/arma-3/<filename>.
How would I do this?
Something like this should work. The only requirement is that the game already exists in your database before the mod is being created.
def mod_directory_path(instance, filename):
slug = instance.game.slug
return os.sep.join([slug, filename])
My models.py
from django.db import models
from django.contrib.auth.models import User
class Song(models.Model):
uploader = models.ForeignKey(User)
date_uploaded = models.DateTimeField(auto_now=True)
song_file = models.FileField(upload_to='music/', max_length=100)
artist = models.CharField(max_length=75, blank=True)
title = models.CharField(max_length=100, blank=True)
genre = models.CharField(max_length=100, blank=True)
def __unicode__(self):
return u'%s' % (self.song_file)
My admin.py
from django.contrib import admin
from uploader.models import Song
from django.db import models
class SongAdmin(admin.ModelAdmin):
list_display = ('song_file', 'title', 'artist', 'genre', 'uploader')
search_fields = ('song_file', 'uploader', 'genre', 'title')
fields = ('song_file', 'title', 'artist', 'genre')
admin.site.register(Song, SongAdmin)
The file gets uploaded (I see it in my media folder) but it doesnt display in my admin page and when the file does get uploaded I get:
'bool' object has no attribute 'has_header' when uploading via a FileField in my admin
Am I missing something obvious here? Pretty new to django.
Turns out it was an issue with Pinax. Updated to the latest git and everything works now!
Found this somewhere else on the net, the problem is in the HideSensitiveFieldsMiddleware and the way to work around it (for debug) is to just comment out that middleware like so
"pinax.middleware.security.HideSensistiveFieldsMiddleware",
+# "pinax.middleware.security.HideSensistiveFieldsMiddleware",
in your settings file, probably should leave that middleware in for non debug environments