Django foreignkey between two databases - django

I'm looking to connect two SQLite tables together (oh dear).
I found this solution : How to use django models with foreign keys in different DBs? , I adapted it to my models and my code (I think). I have no bad answers from django. However, I would like to modify the entry with the admin view of django, and when I try to add the entry with the foreign key of another database, I get this answer:
Exception Type: OperationalError at /admin/users/character/add/
Exception Value: no such table: books
How to adapt to fix it?
models database default
from django.db import models
from users.related import SpanningForeignKey
from books.models import Books
class Character(models.Model):
last_name = models.fields.CharField(max_length=100)
first_name = models.fields.CharField(max_length=100)
book = SpanningForeignKey('books.Books', null=True, on_delete=models.SET_NULL)
def __str__(self):
return f'{self.first_name} {self.last_name}'
models external database
from django.db import models
# Create your models here.
class Books(models.Model):
title = models.TextField()
sort = models.TextField(blank=True, null=True)
timestamp = models.TextField(blank=True, null=True) # This field type is a guess.
pubdate = models.TextField(blank=True, null=True) # This field type is a guess.
series_index = models.FloatField()
author_sort = models.TextField(blank=True, null=True)
isbn = models.TextField(blank=True, null=True)
lccn = models.TextField(blank=True, null=True)
path = models.TextField()
flags = models.IntegerField()
uuid = models.TextField(blank=True, null=True)
has_cover = models.BooleanField(blank=True, null=True)
last_modified = models.TextField() # This field type is a guess.
class Meta:
managed = False
db_table = 'books'
app_label = 'books'
class Languages(models.Model):
lang_code = models.TextField()
class Meta:
managed = False
db_table = 'languages'
app_label = 'books'
class BooksLanguagesLink(models.Model):
book = models.ForeignKey(Books, null=True, on_delete=models.SET_NULL, db_column='book')
lang_code = models.ForeignKey(Languages, null=True, on_delete=models.SET_NULL, db_column='lang_code')
item_order = models.IntegerField()
class Meta:
managed = False
db_table = 'books_languages_link'
app_label = 'books'
admin books
from django.contrib import admin
from books.models import Books, Languages
class BooksModelAdmin(admin.ModelAdmin):
using = 'calibre_db'
def save_model(self, request, obj, form, change):
obj.save(using=self.using)
def delete_model(self, request, obj):
obj.delete(using=self.using)
def get_queryset(self, request):
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs):
return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)
# Register your models here.
admin.site.register(Books, BooksModelAdmin)

Related

Filter options in one to one field django admin

I have this 2 models
from django.db import models
def get_upload_path(instance, filename):
return '{0}/{1}'.format(instance.imovel.id, filename)
# Create your models here.
class Imovel(models.Model):
nome = models.CharField(max_length=50)
descricao = models.CharField(max_length=800)
area = models.IntegerField()
quartos = models.SmallIntegerField(null=True, blank=True)
banheiros = models.SmallIntegerField()
disponivel_aluguel = models.BooleanField()
disponivel_venda = models.BooleanField()
valor_aluguel = models.DecimalField(max_digits=15, decimal_places=2)
valor_venda = models.DecimalField(max_digits=15, decimal_places=2)
valor_condominio = models.DecimalField(max_digits=15, decimal_places=2)
valor_iptu = models.DecimalField(max_digits=15, decimal_places=2)
capa = models.OneToOneField('ImagemImovel', related_name='capa', on_delete=models.DO_NOTHING, null=True, blank=True)
def __str__(self):
return self.nome
class Meta:
db_table = 'imovel'
class ImagemImovel(models.Model):
imovel = models.ForeignKey(Imovel, related_name='imagens', on_delete=models.CASCADE)
nomeImagem = models.CharField(max_length=20)
imagem = models.ImageField(upload_to=get_upload_path)
def __str__(self):
return self.nomeImagem
class Meta:
db_table = 'imagemImovel'
I have houses and it's pictures and a field named 'capa' to say which one is the main picture.
The problem is when I add a house through django admin, save and come back to choose the main one it let me choose images from other houses. How could I filter it to just show images that are related to this specific house?
My django admin file
from django.contrib import admin
from .models import ImagemImovel, Imovel
# Register your models here.
class ImagemImovelAdmin(admin.TabularInline):
model = ImagemImovel
class ImovelAdmin(admin.ModelAdmin):
inlines = (ImagemImovelAdmin, )
admin.site.register(Imovel, ImovelAdmin)
I changed my ImovelAdmin class so I can get the id from the model using the get_form function and use it in a filter for the queryset
class ImovelAdmin(admin.ModelAdmin):
inlines = (ImagemImovelAdmin, )
id_for_formfield = None
def get_form(self, request, obj=None, **kwargs):
if obj:
self.id_for_formfield = obj.id
return super(ImovelAdmin, self).get_form(request, obj, **kwargs)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "capa" and self.id_for_formfield is not None:
kwargs["queryset"] = ImagemImovel.objects.filter(imovel=self.id_for_formfield)
return super(ImovelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
admin.site.register(Imovel, ImovelAdmin)

return same product with multiple id

Right now I'm returning a product by passing a code over url
class Product(APIView):
def get_product(self, code):
try:
prod = ProductModel.objects.get(code=code)
return prod
except Product.DoesNotExist:
raise Http404
def get(self, request, code, format=None):
product = self.get_product(code)
serializer = ProductSerializer(product)
return Response(serializer.data)
url
path('product/<code>/', views.Product.as_view()),
model:
class Product(models.Model):
code = JSONField(default=dict, null=True, blank=True)
description = models.TextField(blank=True, null=True, default='')
category = models.TextField(blank=True, null=True, default='')
marketing_text = models.TextField(blank=True, null=True, default='')
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
this will return product if it's in the database, simple stuff but now I've added a JSON field in the ProductModel with multiple codes ["05017303032619", "05017303032626"], so I want to check do I have this codes and still return the item, basically return the same item by passing one of this codes over url.
You can use an ArrayField instead of a JSONField for that.
models.py
from django.contrib.postgres.fields import ArrayField
class Product(models.Model):
code = ArrayField(models.CharField(max_length=200), blank=True)
...
views.py
class Product(APIView):
def get_product(self, code):
try:
return ProductModel.objects.filter(code__contains=code).first()
except Product.DoesNotExist:
raise Http404
def get(self, request, code, format=None):
product = self.get_product(code)
serializer = ProductSerializer(product)
return Response(serializer.data)

Django Model Save created by and modified by

I am running django 1.8, I am trying to save the current logged in user in the created by and modified by fields in my database. I have tried many different combination of getting this to work, but I am not running into any luck. I have to code working with hard coding in a user id like so:
#python_2_unicode_compatible # only if you need to support Python 2
class Project(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
jobNumber = models.CharField(max_length=8)
shopOut = models.DateTimeField(null=True)
shopIn = models.DateTimeField(null=True)
completion = models.DateTimeField(null=True)
installation_date = models.DateTimeField(null=True)
contractor = models.ForeignKey(Contractor, on_delete=models.CASCADE, default=101)
created_by = models.ForeignKey(User, related_name='Project_created_by')
created_date = models.DateTimeField(auto_now_add=True)
modified_by = models.ForeignKey(User, related_name='Project_modified_by')
modified_date = models.DateTimeField(auto_now=True)
assigned_to = models.ForeignKey(User, related_name='Project_assigned_to', default=1)
status = models.ForeignKey('Status', related_name='Project_status', default=1)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.id:
self.created_by = User.objects.get(id=1)
#self.created_by = User.objects.get(id=kwargs['request'].user)
#self.created_by = User.objects.get(id=request.user)
self.modified_by = User.objects.get(id=1)
#self.modified_by = User.objects.get(id=kwargs['request'].user)
#self.modified_by = User.objects.get(id=request.user)
super(Project, self).save(*args, **kwargs)
year = datetime.datetime.now().year
self.jobNumber = '{}{:04d}'.format(year, self.id)
self.modified_by = User.objects.get(id=1)
#self.modified_by = User.objects.get(id=kwargs['request'].user)
#self.modified_by = User.objects.get(id=request.user)
super(Project, self).save(*args, **kwargs)
If I try any of the code commented out:
self.created_by = User.objects.get(id=kwargs['request'].user)
or
self.created_by = User.objects.get(id=request.user)
I get the following error:
KeyError at /admin/project/project/add/
'request'
or
NameError at /admin/project/project/add/
global name 'request' is not defined
Once again my question is how do I save the current logged in user in my created_by and modified_by fields?
Any help would be greatly appreciated!
After searching a little more I found this post I followed most of their code, but here is mine:
This is my app folder structure:
myapp
project
admin.py # changed this
models.py # changed this
...
myapp
setting.py
url.py
...
my new admin.py
from django.contrib import admin
from . import models
class ProjectAdmin(admin.ModelAdmin):
fields = ('name', 'jobNumber', 'contractor', 'assigned_to', 'status')
def save_model(self, request, obj, form, change):
instance = form.save(commit=False)
if not hasattr(instance, 'created_by'):
instance.created_by = request.user
instance.modified_by = request.user
instance.save()
form.save_m2m()
return instance
admin.site.register(models.Project,ProjectAdmin)
models.py
import datetime
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.auth.models import User
from contractor.models import Contractor
#python_2_unicode_compatible # only if you need to support Python 2
class Project(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
jobNumber = models.CharField(max_length=8)
shopOut = models.DateTimeField(null=True)
shopIn = models.DateTimeField(null=True)
completion = models.DateTimeField(null=True)
installation_date = models.DateTimeField(null=True)
contractor = models.ForeignKey(Contractor, on_delete=models.CASCADE, default=101)
created_by = models.ForeignKey(User, related_name='Project_created_by')
created_date = models.DateTimeField(auto_now_add=True)
modified_by = models.ForeignKey(User, related_name='Project_modified_by')
modified_date = models.DateTimeField(auto_now=True)
assigned_to = models.ForeignKey(User, related_name='Project_assigned_to', default=1)
status = models.ForeignKey('Status', related_name='Project_status', default=1)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.id:
super(Project, self).save(*args, **kwargs)
year = datetime.datetime.now().year
self.jobNumber = '{}{:04d}'.format(year, self.id)
super(Project, self).save(*args, **kwargs)
I guess the trick is catching the request in the admin.py file. Thanks solarissmoke for your input!
you can use django-currentuser package.
for example:
from django_currentuser.middleware import get_current_authenticated_user
class Project(models.Model):
....
self.modifier = get_current_authenticated_user()
if not self.id:
self.creator = get_current_authenticated_user()
....

Django forms target foreign key

I have a form for submitting an order. Multiple items have been attached to a catalog object, I'd like to have the form dropdown contain options for all of the items attached to the foreign key, instead of the foreign key Catalog name of Available. I know how to access these in the view, using the related name, is this possible in forms?
Here is my current form:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit
from . import models
class OrderListForm(forms.ModelForm):
class Meta:
fields = ('order_lines',)
model = models.Order
def __init__(self, *args, **kwargs):
super(OrderListForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
'order_lines',
ButtonHolder(
Submit('create', 'Create')
)
)
Here is my model:
class Catalog(models.Model):
products = models.CharField(max_length=200)
def __unicode__(self):
return self.products
class Issue(models.Model):
catalog = models.ForeignKey(Catalog, related_name='issue_products')
Volume = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
return unicode(self.catalog)
class Annual(models.Model):
catalog = models.ForeignKey(Catalog, related_name='annual_products')
year_id = models.IntegerField(max_length=4)
start_date = models.CharField(max_length=6)
end_date = models.CharField(max_length=6)
def __unicode__(self):
return unicode(self.year_id)
class Annual_Issue(models.Model):
annual_id = models.ForeignKey(Annual, related_name='annual_ids')
issue_id = models.ForeignKey(Issue, related_name='issues')
def __unicode__(self):
return self.annual_id
class Article(models.Model):
catalog = models.ForeignKey(Catalog, related_name='article_products')
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
proquest_link = models.CharField(max_length=200, blank=True, null=True)
ebsco_link = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
order_lines = models.ForeignKey(Issue, related_name='items_ordered')
you can access all the Annuals and Articles that are in the same catalog by using:
c = Catalog.objects.get(....
c.article_products_set.all()
c.annual_products_set.all()

ContentType Issue -- Human is an idiot - Can't figure out how to tie the original model to a ContentType abstracted 'Favorite' model

Originally started here: Django IN query as a string result - invalid literal for int() with base 10
I have a number of apps within my site, currently working with a simple "Blog" app. I have developed a 'Favorite' app, easily enough, that leverages the ContentType framework in Django to allow me to have a 'favorite' of any type... trying to go the other way, however, I don't know what I'm doing, and can't find any examples for.
I'll start off with the favorite model:
favorite/models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
class Favorite(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
user = models.ForeignKey(User)
content_object = generic.GenericForeignKey()
class Admin:
list_display = ('key', 'id', 'user')
class Meta:
unique_together = ("content_type", "object_id", "user")
Now, that allows me to loop through the favorites (on a user's "favorites" page, for example) and get the associated blog objects via {{ favorite.content_object.title }}.
What I want now, and can't figure out, is what I need to do to the blog model to allow me to have some tether to the favorite (so when it is displayed in a list it can be highlighted, for example).
Here is the blog model:
blog/models.py
from django.db import models
from django.db.models import permalink
from django.template.defaultfilters import slugify
from category.models import Category
from section.models import Section
from favorite.models import Favorite
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Blog(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=140, editable=False)
author = models.ForeignKey(User)
homepage = models.URLField()
feed = models.URLField()
description = models.TextField()
page_views = models.IntegerField(null=True, blank=True, default=0 )
created_on = models.DateTimeField(auto_now_add = True)
updated_on = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('blog.views.show', [str(self.slug)])
def save(self, *args, **kwargs):
if not self.slug:
slug = slugify(self.title)
duplicate_count = Blog.objects.filter(slug__startswith = slug).count()
if duplicate_count:
slug = slug + str(duplicate_count)
self.slug = slug
super(Blog, self).save(*args, **kwargs)
class Entry(models.Model):
blog = models.ForeignKey('Blog')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=140, editable=False)
description = models.TextField()
url = models.URLField(unique=True)
image = models.URLField(blank=True, null=True)
created_on = models.DateTimeField(auto_now_add = True)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
slug = slugify(self.title)
duplicate_count = Entry.objects.filter(slug__startswith = slug).count()
if duplicate_count:
slug = slug + str(duplicate_count)
self.slug = slug
super(Entry, self).save(*args, **kwargs)
class Meta:
verbose_name = "Entry"
verbose_name_plural = "Entries"
Any guidance?
The django doc on it is here: Reverse generic relations. Basically on the Blog model itself you can add a GenericRelation...
class Blog(models.Model):
favorites = generic.GenericRelation(Favorite)
For a given blog you can find all of the Favorite models that are associated with it...
b = Blog.objects.get(slug='hello-world-blog-slug')
all_blog_favorites = b.favorites.objects.all()
Or see if the current user has the blog favorited...
user_has_blog_favorited = b.favorites.objects.filter(user=request.user).exists()