Table1
sett_ num | Sett_typ
-----------------------------
2014232 N
2014232 S
2014232 O
Table2
stt_type_code | stt_typ_name
----------------------------
N Normal
S OPTIONS
O Index
this how the database looks for two table, here in table 1 i need display "Normal instead of N by referring the Table 2"
I have achieved this but the problem is the field i have made this change is not searchable and filters are not working properly
so I need to implement foreign key here can please you help me to solve this problem.
the model and admin look like this
Model.py(table 1)
class DLVR(models.Model):
sett_type = models.CharField(max_length=35, editable=False)
sett_num = models.CharField(max_length=7, editable=False)
Model.py(Table 2)
class Sttlmnt_typ_Master(models.Model):
stt_typ_code = models.CharField(max_length=10, editable=True)
stt_typ_name = models.CharField(max_length=35, editable=True)
Admin.py
class DLVRAdmin(admin.ModelAdmin):
list_display = ('sett_num','sett_type')
search_fields=['sett_num','sett_type']
def sett_type_display(self, obj):
if Sttlmnt_typ_Master.objects.filter(stt_typ_code=obj.sett_type).first():
sett_type = Sttlmnt_typ_Master.objects.filter(stt_typ_code=obj.sett_type).first()
return sett_type.stt_typ_name
else:
return obj.sett_type
This is the way i need to implement in foreign key way can anyone help? and please give me examples in model and admin.
Add primary_key parameter to Sttlmnt_typ_Master.stt_typ_code and then change DLVR.sett_type to foreign key:
class Sttlmnt_typ_Master(models.Model):
stt_typ_code = models.CharField(max_length=10, primary_key=True)
stt_typ_name = models.CharField(max_length=35)
def __unicode__(self):
return self.stt_typ_name
class DLVR(models.Model):
sett_type = models.ForeignKey(Sttlmnt_typ_Master)
sett_num = models.CharField(max_length=7)
Admin will be as simple as:
class DLVRAdmin(admin.ModelAdmin):
list_display = ['sett_type', 'sett_num']
search_fields=['sett_num','sett_type__stt_typ_name']
To set raw data to DLVR.sett_type (for example while import from CSV) add _id to field name:
DLVR.objects.create(sett_type_id='O', sett_num='2014232')
Related
I want to create a queryset that references three related models, and allows me to filter. The SQL might look like this:
SELECT th.id, th.customer, ft.filename, fva.path
FROM TransactionHistory th
LEFT JOIN FileTrack ft
ON th.InboundFileTrackID = ft.id
LEFT JOIN FileViewArchive fva
ON fva.FileTrackId = ft.id
WHERE th.customer = 'ACME, Inc.'
-- AND ft.filename like '%storage%' --currently don't need to do this, but seeing placeholder logic would be nice
I have three models in Django, shown below. It's a bit tricky, because the TransactionHistory model has two foreign keys to the same model (FileTrack). And FileViewArchive has a foreign key to FileTrack.
class FileTrack(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
filename = models.CharField(db_column="filename", max_length=128)
class Meta:
managed = False
db_table = "FileTrack"
class TransactionHistory(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
customer = models.CharField(db_column="Customer", max_length=128)
inbound_file_track = models.ForeignKey(
FileTrack,
db_column="InboundFileTrackId",
related_name="inbound_file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
outbound_file_track = models.ForeignKey(
FileTrack,
db_column="OutboundFileTrackId",
related_name="outbound_file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
class Meta:
managed = False
db_table = "TransactionHistory"
class FileViewArchive(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
file_track = models.ForeignKey(
FileTrack,
db_column="FileTrackId",
related_name="file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
path = models.CharField(db_column="Path", max_length=256)
class Meta:
managed = False
db_table = "FileViewArchive"
One thing I tried:
qs1 = TransactionHistory.objects.select_related('inbound_file_track').filter(customer='ACME, Inc.')
qs2 = FileViewArchive.objects.select_related('file_track').all()
qs = qs1 & qs2 # doesn't work b/c they are different base models
And this idea to use chain doesn't work either because it's sending two separate queries an I'm not altogether sure if/how it's merging them. I'm looking for a single query in order to be more performant. Also it returns an iterable, so I'm not sure I can use this in my view (Django Rest Framework). Lastly x below returns a TransactionHistory object, so I can't even access the fields from the other two models.
from itertools import chain
c = chain(qs1 | qs2) # great that his this lazy and doesn't evaluate until used!
type(c) # this returns <class 'itertools.chain'> and it doesn't consolidate
x = list(c)[0] # runs two separate queries
type(x) # a TransactionHistory object -> so no access to the Filetrack or FileViewArchive fields
Any ideas how I can join three models together? Something like this?:
qs = TransactionHistory.objects.select_related('inbound_file_track').select_related('file_track').filter(customer='ACME, Inc.', file_track__filename__contains='storage')
More info: this is part of a view that will look like below. It returns a querysets that is used as part of a Django Rest Framework view.
class Transaction(generics.ListAPIView):
serializer_class = TransactionSerializer
def filter_queryset(self, queryset):
query_params = self.request.query_params.copy()
company = query_params.pop("company", [])[0]
filename = query_params.pop("filename", [])[0]
# need code here that generate filtered queryset for filename and company
# qs = TransactionHistory.objects.select_related('inbound_file_track').select_related('file_track').filter(customer='ACME, Inc.', file_track__filename__contains='storage')
return qs.order_by("id")
Based from the sql query you shared, you are filtering based on the inbound_file_track file name. So something like this should work:
TransactionHistory.objects.select_related(
'inbound_file_track',
).prefetch_related(
'inbound_file_track__file_track_id',
).filter(
customer='ACME, Inc.', inbound_file_track___filename__contains='storage',
)
I have tables that share information in a single related table via foreign keys. The relationships work as expected, however, I'm trying to figure out how to automatically populate fields that are then used to filter the results. I hope the example below illustrates what I'm trying to do.
In the Models:
class UtilType(models.Model):
name = models.CharField()
description = models.CharField()
# following boolean fields used to filter table
is_address = models.BooleanField(default=False)
is_phone = models.BooleanField(default=False)
is_email = models.BooleanField(default=False)
is_domain = models.BooleanField(default=False)
class Address(models.Model):
address_type = models.ForeignKey(
UtilType,
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="addresses",
limit_choices_to={'is_address': True}
)
class PhoneType(models.Model):
phone_type = models.ForeignKey(
UtilType,
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="addresses",
limit_choices_to={'is_phone': True}
)
... more models with similar schema
In the Admin:
class ContactPhoneNumberInline(admin.StackedInline):
model = PhoneNumber
min_num = 0
max_num = 5
extra = 0
exclude = ["company"]
fields = (
("phone_type", "country", "phone_number"),
)
class ContactEmailAddressInline(admin.StackedInline):
model = EmailAddress
min_num = 0
max_num = 5
extra = 0
exclude = ["company"]
fields = (
("email_type", "email_address"),
)
.... more inlines w/ similar structure
#admin.register(Contact)
class ContactAdmin(admin.ModelAdmin):
fields = (
"company",
("name_first", "name_middle", "name_last",),
("name_salutation", "name_suffix", "title"),
)
inlines = [
ContactPhoneNumberInline,
ContactEmailAddressInline,
ContactDomainInline,
ContactAddressInline
]
When editing a contact, the action is as expected. I can add information to each type and the types show filtered as directed in the ForeignKeys.
However, the admin window for UtilType has the boolean selection fields: is_address, is_phone, is_email, is_domain so the user must select this to be filtered correctly. I can hide these fields, with the exclude method.
But how do I automatically populate the right boolean (=True) based on which inline is currently being used?
Would it be best to use a save override method in the models, in the admin, or is there a better way to do this?
I haven't found a way to do this in the Django admin. If someone knows how it would be good information. I'll deal with the action in the front end once it's developed. I'm not sure it's worth the effort in the admin.
With this models:
class Vine(models.Model):
autor = models.ForeignKey(Viner,related_name='autor')
titulo = models.CharField(max_length=450)
estado = models.CharField(choices=ESTADOS_VINE, max_length=30)
objects = models.Manager()
custom_object = managers.VineManager()
and the model for the votes
class Voto(models.Model):
user = models.ForeignKey(MyUser)
submit_date = models.DateTimeField(auto_now_add=True)
vine = models.ForeignKey(Vine)
valoracion = models.BooleanField(default=False)
and the class for the Favorites (This is working fine yet)
class Favorito(models.Model):
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='favoritos')
I have this 'query' in Django.
vines = Vine.custom_object.filter(estado=2).\
annotate(favoritosCount=Count('favoritos', distinct=True)).\
filter(voto__valoracion=False).annotate(disLikesCount=Count('voto', distinct=True))\
.annotate(likesCount=Count('voto', distinct=True)).filter(voto__valoracion=True)
But the second filter is not working because of the first.
Basically what I want is to get the sum of 'positive votes' - 'negative votes' as a field and order by it.
Could anyone please help me?
Thank you in advance
AFAIK you can't do that query with the ORM. You might be able to do it with a raw query.
I think It's easier if you add a count field to your Vine model and order by it. Then update that count field every time there's a new Voto.
Something like this:
from django.db.models import F
class Vine(models.Model):
...
votos = models.IntegerField()
class Meta:
ordering = ('votos',)
class Voto(models.Model):
...
def save(self):
"""When saving new Voto instance, update related Vine."""
if not self.pk:
new_vote = 1 if self.valoracion else -1
self.vine.update(votos=F('votos') + new_vote)
return super(Voto, self).save()
PS: If you want to know more about that F expression.
I'm trying to access a field of a foreign key within a Tabular Inline in the Django Admin.
Despite my best efforts I can't seem to get it working. My current code is:
class RankingInline(admin.TabularInline):
model = BestBuy.products.through
fields = ('product', 'account_type', 'rank')
readonly_fields = ('product', 'rank')
ordering = ('rank',)
extra = 0
def account_type(self, obj):
return obj.products.account_type
Which results in:
'RankingInline.fields' refers to field 'account_type' that is missing from the form.
I have also tried using the model__field method, which I used as:
fields = ('product', 'product__account_type', 'rank')
Which results in:
'RankingInline.fields' refers to field 'product__account_type' that is missing from the form.
The models are defined as so:
class Product(BaseModel):
account_type = models.CharField(choices=ACCOUNT_TYPE_OPTIONS, verbose_name='Account Type', max_length=1, default='P')
class Ranking(models.Model):
product = models.ForeignKey(Product)
bestbuy = models.ForeignKey(BestBuy)
rank = models.IntegerField(null=True, blank = True)
class BestBuy(BaseModel):
products = models.ManyToManyField(Product, through='Ranking')
class BaseModel(models.Model):
title = models.CharField(max_length = TODO_LENGTH)
slug = models.CharField(max_length = TODO_LENGTH, help_text = """The slug is a url encoded version of your title and is used to create the web address""")
created_date = models.DateTimeField(auto_now_add = True)
last_updated = models.DateTimeField(auto_now = True)
What am I doing wrong?
I think what you are looking for is nested inlines since you want to expand "Product" as inline within RankingInline. At present Django does not have such feature built in. This question is relevant: Nested inlines in the Django admin?
You can also look at "Working with many-to-many intermediary models" section in Django DOC. That might be useful.
Actually Django will show you a small green '+' button besides the inline product field entry which you can use to create a new product to assign to your current entry for BestBuy. This might be an alternative for you to use.
You simply need to add the method-field to readonly_fields:
readonly_fields = ('product', 'rank', 'account_type')
Your new field account_type should be defined in ModelAdmin (i.e. RankingAdmin) not in TabularInline (i. e. RankingInline). It should be only accessed from TabularInline.
I imported my (PHP) old site's database tables into Django. By default it created a bunch of primary key fields within the model (since most of them were called things like news_id instead of id).
I just renamed all the primary keys to id and removed the fields from the model. The problem then came specifically with my News model. New stuff that I add doesn't appear in the admin. When I remove the following line from my ModelAdmin, they show up:
list_display = ['headline_text', 'news_category', 'date_posted', 'is_sticky']
Specifically, it's the news_category field that causes problems. If I remove it from that list then I see my new objects. Now, when I edit those items directly (hacking the URL with the item ID) they have a valid category, likewise in the database. Here's the model definitions:
class NewsCategory(models.Model):
def __unicode__(self):
return self.cat_name
#news_category_id = models.IntegerField(primary_key=True, editable=False)
cat_name = models.CharField('Category name', max_length=75)
cat_link = models.SlugField('Category name URL slug', max_length=75, blank=True, help_text='Used in URLs, eg spb.com/news/this-is-the-url-slug/ - generated automatically by default')
class Meta:
db_table = u'news_categories'
ordering = ["cat_name"]
verbose_name_plural = "News categories"
class News(models.Model):
def __unicode__(self):
return self.headline_text
#news_id = models.IntegerField(primary_key=True, editable=False)
news_category = models.ForeignKey('NewsCategory')
writer = models.ForeignKey(Writer) # todo - automate
headline_text = models.CharField(max_length=75)
headline_link = models.SlugField('Headline URL slug', max_length=75, blank=True, help_text='Used in URLs, eg spb.com/news/this-is-the-url-slug/ - generated automatically by default')
body = models.TextField()
extra = models.TextField(blank=True)
date_posted = models.DateTimeField(auto_now_add=True)
is_sticky = models.BooleanField('Is this story featured on the homepage?', blank=True)
tags = TaggableManager(blank=True)
class Meta:
db_table = u'news'
verbose_name_plural = "News"
You can see where I've commented out the autogenerated primary key fields.
It seems like somehow Django thinks my new items don't have news_category_ids, but they definitely do. I tried editing an existing piece of news and changing the category and it worked as normal. If I run a search for one of the new items, it doesn't show up, but the bottom of the search says "1 News found", so something is going on.
Any tips gratefully received.
EDIT: here's my ModelAdmin too:
class NewsCategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {"cat_link": ("cat_name",)}
list_display = ['cat_name', '_cat_count']
def _cat_count(self, obj):
return obj.news_set.count()
_cat_count.short_description = "Number of news stories"
class NewsImageInline(admin.TabularInline):
model = NewsImage
extra = 1
class NewsAdmin(admin.ModelAdmin):
prepopulated_fields = {"headline_link": ("headline_text",)}
list_display = ['headline_text', 'news_category', 'date_posted', 'is_sticky'] #breaking line
list_filter = ['news_category', 'date_posted', 'is_sticky']
search_fields = ['headline_text']
inlines = [NewsImageInline]
The answer you are looking for I think would lie in the SQL schema that you altered and not in the django models.
It could probably have something to do with null or blank values in the news_category_id, or news that belongs to a category that doesn't exist in the news_category. Things I'd check:
You have renamed the primary key on the News category from news_category_id to id. Does the foreign key on the News also map to news_category_id and not anything else?
Are all the values captured in the news.news_category also present in news_category.id
Also, as an aside, I don't see any reason why you need to rename the primary keys to id from something that they already are. Just marking them primary_key=True works just fine. Django provides you a convenient alias pk to access a model's integer primary key, irrespective of what the name of the field actually is.