admin template for manytomany - python

I have a manytomany relationship between publication and pathology. Each publication can have many pathologies. When a publication appears in the admin template, I need to be able to see the many pathologies associated with that publication. Here is the model statement:
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]
class Publication(models.Model):
pubtitle = models.TextField()
pathology = models.ManyToManyField(Pathology)
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
Here is the admin.py. I have tried variations of the following, but always
get an error saying either publication or pathology doesn't have a foreign key
associated.
from myprograms.cpssite.models import Pathology
class PathologyAdmin(admin.ModelAdmin):
# ...
list_display = ('pathology', 'id')
admin.site.register(Pathology, PathologyAdmin)
class PathologyInline(admin.TabularInline):
#...
model = Pathology
extra = 3
class PublicationAdmin(admin.ModelAdmin):
# ...
ordering = ('pubtitle', 'year')
inlines = [PathologyInline]
admin.site.register(Publication,PublicationAdmin)
Thanks for any help.

Unless you are using a intermediate table as documented here http://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models, I don't think you need to create an Inline class. Try removing the line includes=[PathologyInline] and see what happens.

I realize now that Django is great for the administration (data entry) of a website, simple searching and template inheritance, but Django and Python are not very good for complex web applications, where data is moved back and forth between a database and an html template. I have decided to combine Django and PHP, hopefully, applying the strengths of both. Thanks for you help!

That looks more like a one-to-many relationship to me, tho I'm somewhat unclear on what exactly Pathologies are. Also, so far as I understand, Inlines don't work on manytomany. That should work if you flip the order of the models, remove the manytomany and add a ForeignKey field to Publication in Pathology.
class Publication(models.Model):
pubtitle = models.TextField()
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
publication = models.ForeignKey(Publication)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]

Related

How can I restrict the list of objects in API view once an object has been added to a relationship?

I am working in django-rest-framework and I have three models: Event, Performer, and Link. I have many-to-many relationships established on the Event and Performer models as 'links' pointing to the Link model. In the API view, when I am creating or updating an event or performer, I am given a list of all links. I would like them to be removed as options once they've been associated with another object, but I can't seem to figure out how to. Below is my code:
class Link(models.Model):
created = models.DateTimeField(auto_now_add=True)
address = models.URLField()
def __str__(self):
return f"{self.address}"
class Meta:
ordering = ['created']
class Performer(models.Model):
created = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
links = models.ManyToManyField(Link)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Meta:
ordering = ['created']
class Event(models.Model):
created = models.DateTimeField(auto_now_add=True)
sale_date = models.DateTimeField()
event_date = models.DateTimeField()
performer = models.ForeignKey(Performer, on_delete=models.CASCADE)
links = models.ManyToManyField(Link)
class Meta:
ordering = ['event_date']
and I'm using this for serializers:
class LinkSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Link
fields = ['url', 'address']
class PerformerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Performer
fields = ['url', 'first_name', 'last_name', 'links']
class EventSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Event
fields = ['url', 'performer', 'sale_date', 'event_date', 'links']
I thought about using
ManyToManyField.limit_choices_to
but I don't know what my selector would look like. I also thought I could use
Link.objects.exclude(...)
or
Link.objects.filter(...)
call somewhere but I just don't know where. Thanks to anyone who can help!
Edit: thought I’d add that what I thought would work is to use ‘limit_choices_to’ to filter out any links that are included in a relationship, but I couldn’t figure out how to test if an object was in a relationship (and since there’s multiple relationships only testing for one isn’t perfect either)
You should make use of the Serializer class' get_queryset method:
class LinkSerializer(serializers.HyperlinkedModelSerializer):
def get_queryset(self):
return super().get_queryset().filter(performer=None, event=None)
class Meta:
model = Link
fields = ['url', 'address']
I figured out what I was trying to accomplish with this: I needed to restrict the choices for the field at the model level, which I was able to do by passing a predetermined restriction to the 'limit_choices_to=' parameter. See code below and thank you to #anthony2261 for the suggestion, your filter section helped me to understand how to filter even though it wasn't the type of filtering I needed!
# create a dict of filter conditions(?)
restrict_choices = {'performer': None, 'event': None}
class Performer(...):
...
# refer to the restriction defined previously
# when defining the links relationship.
links = models.ManyToManyField(Link, limit_choices_to=restrict_choices)

Django Administration - Customize list appearance and selection of ManyToManyField keys

I have a database with 1000+ songs. I have a custom model "Schedule" that accepts songs as field.
models.py
from django.db import models
class Song(models.Model):
title = models.CharField(max_length=255)
words = models.TextField()
slug = models.SlugField()
date = models.DateTimeField(auto_now_add=True)
snippet = models.CharField(max_length=50)
def __str__(self):
return self.title
class Schedule(models.Model):
songs = models.ManyToManyField(Song)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.date)
admin.py
from django.contrib import admin
from .models import Song, Schedule
#admin.register(Song)
class SongModel(admin.ModelAdmin):
search_fields = ('title',)
list_display = ('title',)
list_per_page = 100
#admin.register(Schedule)
class ScheduleModel(admin.ModelAdmin):
search_fields = ('date',)
list_display = ('date',)
list_per_page = 100
I want to be able to add any song I want to a schedule, but it is difficult do to so through the default list in the Django-Administration, which looks like this. I have to scroll and CTRL+select each one of them, then add them.
I'd like something more more practical where I can select, search, etc.
What are my options? I don't know where to start looking.
Option 1
It's only comfortable if you have very few related items (few songs in schedule). But it is super easy and will be better than what you have now. (django.contrib.admin comes with built-in select2.)
#admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
autocomplete_fields = ("songs",)
Option 2
(upd: damn, forgot it at first, it's also super simple and quite efficient)
It looks alright-ish. Usable. Not particularly comfortable. But better than ctrl-clicking the stuff.
#admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
filter_horizontal = ('songs',)
Option 3
If you want a comfortable UI without implementing custom pages or actions (which are unfortunately a complete mess), you should use a StackedInline admin.
It's quite a bit more difficult though.
First you will need a through model. (I don't think inlines are possible with auto-generated many-to-many models.) It's basucally your many-to-many between the two models. Something like that:
class ScheduleSongNM(models.Model):
song = models.ForeignKey("Song", null=False)
schedule = models.ForeignKey("Schedule", null=False)
Tell your Schedule model to use your custom through model:
class Schedule(models.Model):
songs = models.ManyToManyField(Song, through="ScheduleSongNM")
Now create an inline admin for the ScheduleSongNM:
class ScheduleSongInline(admin.StackedInline):
model = ScheduleSongNM
fields = ["song"]
autocomplete_fields = ["song"] # select2 works here too
Finally, tell your Schedule admin that it has an inline now:
#admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
inlines = [ScheduleSongInline]
...
Maybe I missed something (obviously I haven't tested it), but I think you got the general idea. In the end you get a box inside of your Schedule admin that looks something like that (plus auto completion for song names):

DRF serializers how to best handle indirect references to a FK?

Let's say I have the following models:
class Thing(models.Model):
thing_key = models.AutoField(primary_key=True)
state = models.ForeignKey(State, db_column='state_key', on_delete=models.CASCADE, default=0)
[...other fields unrelated to the question...]
class Meta:
db_table = 'THING'
class State(models.Model):
state_key = models.AutoField(primary_key=True)
flag = models.IntegerField(unique=True)
description = models.CharField(max_length=50)
class Meta:
db_table = 'STATE'
And let's say I need to create new Things based on data received via POST requests.
And let's say these POST requests do NOT contain the FK of Thing, which is state_key, but actually the flag field from the State model.
What is the best way to implement serializers that help accomplish the following things:
Create a new Thing even though the state_key is unknown.
Return a serialized representation of the newly created Thing without exposing the state_key.
After reading and re-reading the documentation, the best I could do is the following. It works, but I'm suspect there's a much more straightforward way to do it:
class FlagField(serializers.RelatedField):
def to_representation(self, value):
return value.flag
def to_internal_value(self, data):
return State.objects.get(flag=data)
class ThingSerializer(serializers.ModelSerializer):
state_flag = FlagField(queryset=State.objects.all(), source='state')
class Meta:
model = Thing
exclude = ['state']
Is this an acceptable approach? If not, what is wrong with it and how else could I accomplish the goal?
Thanks in advance!

Django one-to-many, add fields dynamically in Admin

I have the following code:
class Item(models.Model):
name = models.CharField(max_length=100)
keywords = models.CharField(max_length=255)
type = models.ForeignKey(Type)
class Meta:
abstract = True
class Variant(models.Model):
test_field = models.CharField(max_length=255)
class Product(Item):
price = models.DecimalField(decimal_places=2, max_digits=8,null=True, blank=True)
brand = models.ForeignKey(Brand)
variant = models.ForeignKey(Variant)
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in Product._meta.fields]
def __unicode__(self):
return self.name
Im using Grappelli.
I want my Product to have multiple Variations. Should I use a manytomanyfield?
I want to be able to add Variants to my Product directly in the Admin. Now I get an empty dropwdown with no variants(because they doesnt exists).
I thought Django did this automatically when u specified a Foreign Key?
How can I get the Variant fields to display directly on my Product page in edit?
I've read someting about inline fields in Admin?
Well, it's the other way around :)
1/ Place the foreign key field in your Variant, not in your Product (what you describe is actually a OneToMany relationship).
2/ Link the Variant to your Product in the relative ProductAdmin in admin.py as an inline (i.e VariantInline).
See the docs for further informations : https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#inlinemodeladmin-objects
Hope this helps !
Regards,

Django multiple tag field

I'm trying to find a good tutorial for django how to create multiple tags in a model.
For example:
class Tag(models.Model):
name = models.CharField()
class Sample(models.Model):
name = models.CharField()
urlA = models.CharField()
urlB = models.CharField()
tagA = models.ManyToManyField(Tag)
tagB = models.ManyToManyField(Tag)
I would like to display the tags as an input field and separate by ',' and split in the save method. So I'd like to see 2 different input for the 2 tag field.
If you have an easy way to do or know a good tutorial, please tell me! :)
Thank you guys!
Edit: you do not have to have the actual table sets over laid. You can generate any queryset you want to inn your views. Your url conf can be set up to display the detail view from multiple url. If i am still not understanding then please refine your question.
For having multiple anything tags categories your either going m21 or m2m. So when you create your tags you can add them one by one. Are you familiar with what the Django ORM has to offer with some of its admin functionality? Please give the documentation a good look through. Your approach to this problem is anything but reasonable. Not trying to rub you the wrong way I'm no genius. You would do something like so.
class Tag(models.Model):
title = models.CharField(max_length=250, blank=True)
slug = models.SlugField(blank=True
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
ordering = ['title']
#models.permalink
def get_absolute_url(self):
return "/tags/%s/" % self.slug
class Entry(models.Model):
title = models.CharField(max_length=250, blank=True)
body = models.TextField()
tags = models.ManyToMany('Tag')
slug = models.SlugField()
#models.permalink
def get_absolute_url(self):
return "/blog/%s/" % self.slug
There's a little more code to be done for the EntryAdmin and the TagAdmin models, Many other things that can be done as well. I am not sure what you are trying to achieve with that if you could be more clear? Thank you, the above is a rough illustration of how I would approach it.
I found a solution from here:
https://dev.to/thepylot/how-to-add-tags-to-your-models-in-django-django-packages-series-1-3704
django-taggit is very useful for tagging.
It is
a reusable application that primarily offers you a Tag model, and a manager for easily adding tags to any model.
pip install django-taggit
After that, open settings.py and edit the installed apps section:
INSTALLED_APPS = [
...
'taggit'
]
After that, edit your model and add tags like this:
tags = TaggableManager()
The TaggableManager will show up automatically as a field in a ModelForm or in the admin.
Documentation: https://django-taggit.readthedocs.io/en/latest/index.html

Categories