ForeignKey uneditable in Django Admin - django

Something that has worked perfectyle until recently has stopped working. A model that has a foreignkey to another object isn't editable as expected in the standard django admin. The problem is this: ForeignKeys to some model aren't editable in de admin interface, though they should be, although a label does appear in the admin page.
It looks like this:
The HTML-code for the bit where the foreignkey to the Story-model should be edited:
<div class="form-row field-story">
<div>
<label for="id_story" class="required">Story:</label>
</div>
</div>
2 relevant models with their respective unicode defs:
class Question(models.Model):
question = models.CharField(max_length = 200)#the Actual question
correct_answer = models.ForeignKey(Answer, verbose_name = 'Correct Answer', related_name = 'Correct answer')
incorrect_answers = models.ManyToManyField(Answer, verbose_name = 'Distractor options', related_name = 'Incorrect answers')
story = models.ForeignKey(Story)
def __unicode__(self):
try:
return self.question.decode('latin-1') + '(%i)'%(self.id)
except:
return str(self.id)
class Story(models.Model):
class Meta:
verbose_name_plural = 'Stories'
author = models.ForeignKey(User, blank = True, null = True, on_delete = models.SET_NULL, editable = False)
name = models.CharField(max_length = 150, verbose_name = 'Name/Summary')
story = models.TextField(verbose_name = 'Story', max_length = 13 * 54)#the actual story
publish = models.BooleanField(default = False, help_text = 'If this is published, it will be uneditable.')
date_added = models.DateTimeField (auto_now_add = True, editable = False)#date of reply
ready = models.BooleanField(default = False, help_text = 'Whether the author thinks this is ready')
erf = models.CharField(max_length = 20, verbose_name = 'ERF label', editable = False, blank = True, null = True)
def __unicode__(self):
try:
return "'"+self.name.encode( 'latin-1') + "'"
except:
return "Story with unicode name or something: %i" %(self.id)
In admin.py:
admin.site.register(Question, )
Looking at what works and what doesn't, I'm beginning to feel it has got something to do with the Story-model. Other foreignkey relationships are functioning fine. Of course, the fact that the foreignkey isn't editable means the object can't be saved from the admin, even though MySQL shows that there is a valid story_id in the question table.
I remember having used this and that this worked fine. I suspect unicode-problems somewhere, but I can't imagine what exactly, let alone how to fix them. Can anybody help?
PS. What happens at ForeignKey field will not appear in Django admin site isn't the case here, I think.

Urgh.. looking for other foreignfield problems, I encountered ForeignKey field problem in Django. In the comments to the question, it is stated by Daniel Roseman that the unicode defs on models should return unicode. Tried that, and my problem was solved.
Grrr.. Unicode... You win this time!

Related

Author page in django migrations and questions

I want to make a website for eBooks with a page that has all the books published by one of the authors. The problem is that I have no idea how to do that. I will mention that I am a beginner.
I tried this int the model file
class Author(models.Model):
author = models.TextField()
class Product(models.Model):
…
author=models.ForeignKey(Author,on_delete=models.CASCADE)
The result in the terminal was:
File "/home/user/petnet/petnet-env/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 264, in check_constraints
raise IntegrityError(
django.db.utils.IntegrityError: The row in table 'store_product' with primary key '2' has an invalid foreign key: store_product.author_id contains a value 'anonim' that does not have a corresponding value in store_author.id.
I think this is caused by the act that I made the author field later and there were already authors fields from before, but then, when I tried to revert back to what I had before doing this, I got some errors regarding migrations.
Also the views were:
def author_detail(request, slug):
author = get_object_or_404(Author, slug=slug)
products = author.products.filter(status=Product.ACTIVE)
return render(request, 'store/author_detail.html', {
'author':author,
'products':products
})
But I am also curious if there is a chance I could use only this for models so I could use the form for adding a product in a much easier way.
class Product(models.Model):
DRAFT = 'draft'
WAITING_APPROVAL = 'waitingapproval'
ACTIVE = 'active'
DELETED = 'deleted'
STATUS_CHOICES = (
(DRAFT, 'Ciorna'),
(WAITING_APPROVAL, 'Asteapta aprobare'),
(ACTIVE, 'Activ'),
(DELETED, 'Sters')
)
user = models.ForeignKey(User, related_name='products',on_delete=models.CASCADE)
category=models.ForeignKey(Category, related_name='products',on_delete=models.CASCADE)
title = models.CharField(max_length=50)
image = models.ImageField(upload_to='uploads/product_images/', blank=True, null=True)
editie = models.IntegerField()
editura = models.CharField(max_length=50)
description = models.TextField(blank=True)
author = models.TextField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=50)
status = models.CharField(max_length=50, choices=STATUS_CHOICES, default=ACTIVE)

Django admin inline "add more item" button not working

Trying to learn stacked inlines in Django. Have a very basic setup
For admin.py
from django.contrib import admin
from .models import Picture, Review
class ReviewInline(admin.StackedInline):
model = Review
save_on_top = True
fields = ["reviewer"]
##admin.register(Picture)
class PictureAdmin(admin.ModelAdmin):
save_on_top = True
fields = ["painter"]
inlines = [ReviewInline,]
admin.site.register(Review)
admin.site.register(Picture, PictureAdmin)
For models.py
from django.db import models
class Picture(models.Model):
painter = models.CharField(("painter"), max_length=255)
def __str__(self):
return self.painter
class Review(models.Model):
picture = models.ForeignKey(Picture, on_delete=models.CASCADE)
reviewer = models.CharField( max_length=255)
extra = 0
def __str__(self):
return self.reviewer
As can be seen there is no "add more item" button. I think this might be a JS issue but am not sure(I do have JS enabled in browser)
Anyone has any idea?
I beleive you have the extra=0 in the wrong class, it should be in the Inline not the Model...
Remove extra=0 from the model
class Review(models.Model):
picture = models.ForeignKey(Picture, on_delete=models.CASCADE)
reviewer = models.CharField( max_length=255)
# extra = 0 <---- remove this
def __str__(self):
return self.reviewer
Add it to the Inline:
class ReviewInline(admin.StackedInline):
model = Review
save_on_top = True
extra = 0
fields = ["reviewer"]
Justification comes from this snippet from this example:
#admin.register(Painter)
class PainterAdmin(admin.ModelAdmin):
save_on_top = True
fields = ["name"]
inlines = [PictureInline]
class ReviewInline(admin.StackedInline):
model = Review
extra = 0
fields = ["reviewer", "comment"]
Edit: Second thought you may also want to get rid of the save_on_top from the inline as well?
Clearing my Google Chrome cache solved it! I got a clue after realizing that the example worked in Microsoft Edge.

How to write a model method that references another model?

I would like to create a model method that will take the "user" (which is a CharField) for
a given review and then return the "quote" associated with that user that is defined as part
of UserProfile. I am trying to create both the method as well as the template. The things I've tried so far haven't seemed to work.
I know the best way to do this is probably make the "user" field within
Reviewbackup a ForeignKey to user, but I'd like to know how to be able to do it with a
method so I can learn.
models.py
class Reviewbackup(models.Model):
review = models.CharField('Review', max_length = 2000)
user = models.CharField('Username', max_length = 200)
rating = models.IntegerField(max_length=2, choices=RATING_OPTIONS)
product = models.ForeignKey(Productbackup)
def __unicode__(self):
return self.review
class UserProfile(models.Model):
user = models.OneToOneField(User)
quote = models.CharField('About', max_length = 200, null=True, blank=True)
website = models.URLField('Personal website/blog', null=True, blank=True)
facebook = models.URLField('Facebook profile page', max_length = 200, null=True, blank=True)
twitter = models.URLField('Twitter profile page', max_length = 200, null=True, blank=True)
youtube = models.URLField('YouTube channel page', max_length = 200, null=True, blank=True)
views.py
def view_reviews(request, product_name):
product = get_object_or_404(Productbackup, url_friendly=product_name)
product_id = product.id
#get reviews for the this product
reviews = Reviewbackup.objects.filter(product_id=product_id).order_by("-created_on")
return render_to_response('reserve/templates/view_reviews.html', {'reviews':reviews},
context_instance=RequestContext(request))
template
{% for review in reviews %}
{{review.user}}
<br>{{review.user.userprofile.quote}}
{% endfor %}
If condition of the problem says "not to use a ForeignKey for user, but use CharField for username" you may add the method to your Reviewbackup model like:
def get_user_quote(self):
return UserProfile.objects.get(user__username=self.user).quote
and use it in the template:
{{ review.get_user_quote }}
But you really should replace your user field to ForeignKey

django display content of a manytomanyfield

I started using django framework just a few days ago and i desperately need some help with my application.
It consists of client,project,admin,and admin payment classes where the admin_payment holds the ids of the admins and projects among other stuff.
My question is how i can display the "administrator's name" of each "project" in my admin listing of projects? the project class itself does not hold the administrator ids (the Admin_Payment does)
Currently i have the following structure: (striped down)
models.py
class Admin(models.Model):
admin_name = models.CharField(unique = True, blank = False, null = False, max_length = 128, verbose_name = u'admin full name')
def __unicode__(self):
return self.admin_name
class Meta:
ordering = ('id',)
verbose_name = u'Admin Info'
class Project(models.Model):
client = models.ForeignKey(Client, verbose_name = u'Client')
description = models.ForeignKey(Description, verbose_name = u'project description')
admins = models.ManyToManyField(Admin, verbose_name = u'Administrators', through = 'Admin_Payment')
class Admin_Payment(models.Model):
admin = models.ForeignKey(Admin, verbose_name = u'Administrator')
project = models.ForeignKey(Project, verbose_name = u'project')
admin.py (striped down)
class AdminInline(admin.TabularInline):
model = Admin
class ProjectAdmin(admin.ModelAdmin):
radio_fields = {'position': admin.HORIZONTAL, 'solution': admin.HORIZONTAL}
inlines = [AdminInline, ]
list_display = ['client','description','admin_name']
Clients and Descriptions appear correctly in the project listing but the admin names are not
Any help is appreciated
(sorry if i posted anything that doesnt make sense , i am a newbie in python and django)
Displaying the contents of ManyToMany field isn't supported by default by django, because the database will be queried for each row of the results. You can display it yourself by adding a method to your Project-model:
class Project(models.Model):
....
def admin_names(self):
return ', '.join([a.admin_name for a in self.admins.all()])
admin_names.short_description = "Admin Names"
and put admin_names in your list_display fields!

Django: ManyToMany Inline Admin view error

Here are the model definitions:
class ItemBrand(models.Model):
name = models.CharField(max_length = 30, unique = True)
def __unicode__(self):
return self.name
class WantedItem(models.Model):
name = models.CharField(max_length = 120)
description = models.TextField()
created = models.DateTimeField(auto_now = False, auto_now_add = True)
expires = models.DateTimeField(auto_now = False, auto_now_add = False)
type = models.ForeignKey(ItemType, related_name = "type wanted")
GENDER_CHOICES = (
(1, 'Male'),
(2, 'Female')
)
gender = models.IntegerField(choices = GENDER_CHOICES)
brands = models.ManyToManyField(ItemBrand, related_name = "wantedbrands", symmetrical = False)
colors = models.ManyToManyField(ItemColor)
sizes = models.ManyToManyField(ItemSize)
creator = models.ForeignKey(User, related_name = "wishlist creator")
def __unicode__(self):
return self.name
Here is the AdminModel code:
class BrandsInline(admin.TabularInline):
model = WantedItem.brands.through
class WantedItemAdmin(admin.ModelAdmin):
list_display = ('name', 'created', 'expires', 'type', 'gender', 'creator')
search_fields = ('name', 'description')
list_filter = ('created', 'brands',)
ordering = ('-created',)
inlines = [
BrandsInline,
]
exclude = ('brands',)
This is pulled basically right from the Django docs, and here's the error I am getting:
'ReverseManyRelatedObjectsDescriptor' object has no attribute 'through'
I am at a total loss... any ideas? Even if I literally create a linker table and set the "through" attribute in the Model I get the same error.
Broken?
You need to upgrade Django to the trunk.
Using inlines with many-to-many fields is new in the django development version (see docs).
Using a simplified version of your models, I get the same error as you for Django 1.1.1, but it works on the trunk (revision 11785).
As an aside, you don't need to specify symmetrical = False on your ItemBrand ManyToMany field. The symmetrical option is only intended for recursive relationships eg User <-> User.
You may want to have a look at the documentation on related names, and think about renaming them to something more logical as well. If creator is a User object, and want to get the set of wishlists they have created, the default when related_name is not specified is
creator.wishlist_set.all()
with your choice for related_name (when you add the underscore), this changes to
creator.wishlist_creator.all()
but I would recommend related_name='wishlists', in which case you would use
creator.wishlists.all()
While it may not be the cause of your error, spaces in the related_name attribute are invalid so I'd try removing those first.
"type wanted" => "type_wanted"
"wishlist creator" => "wishlist_creator"