Sorry if this is confusing, I'm still a bit green with Django. So basically I have two models and I want a selection from one to have all the choices from another model. So basically:
class Show(models.Model):
venue = models.CharField(max_length=100, choices = VENUE NAME)
class Venues(models.Model):
Name = models.CharField(max_length=100)
Essentially I want the venue to have a list of the venue names that were input into that model. Is this possible?
In your case you should use many-to-one ForeignKey
It give you access to Venues object from your Show object and it simple to add this to your model.
class Show(models.Model):
venue = models.ForeignKey('Venues', on_delete=models.CASCADE)
class Venues(models.Model):
name = models.CharField(max_length=100)
To get your choices you can use:
Venues.objects.all()
And then the only thing you need is add object or ID to your Show object and save.
Choices are good too but not in this case. For example when you need some const and give user choices like this:
class Show(models.Model):
VENUES_CHOICES = (
(RESTAURANT, 'restaurant'),
(PUB, 'pub'),
)
venues = models.IntegerField(choices=VENUES_CHOICES, default=RESTAURANT)
Its great to use it in order status in my opinion.
add a str def like this in the Venues model will do
def __str__ (self):
return self.name
Related
Problem:
How to add relationship from chosen model instance to any other Django model dynamically via Django Admin interface?
Description:
I want to create Categories via Django Admin interface. Each Category has multiple Choices assigned to it. Choice(s) from given Category may be assigned only to objects of another specific Django class (model). Let's present a pseudocode example:
class Category(models.Model):
category_name = models.CharField()
class Choice(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="choices")
choice_name = models.CharField()
class ModelWithChoosableFields(models.Model):
possible_categories = ... # objects of class Category
selected_choices = ... # objects of class Choice
class Meta:
abstract = True
class Book(ModelWithChoosableFields):
...
class Animal(ModelWithChoosableFields):
...
Category with category_name = 'Genre' has three possible
Choices: choice_name = 'biography', choice_name = 'thriller'
and choice_name = 'poetry'.
Category with category_name = 'Animal type' has two possible
Choices: choice_name = 'mammal' and choice_name = 'reptile'.
Class Book may have one of the Choices from Category
category_name = 'Genre' assigned. However, Choices related to
category_name = 'Animal type' cannot be assigned to class Book.
Analogically, class Animal can only have Choices related to
category_name = 'Animal type' assigned to it.
In other words, in Admin panel for instance of class Book I want to have a way of selecting Choice objects from Categories appropriate for Book class.
The reason I want to do this is so that user using Django Admin interface can add dynamically possible Categories to chosen models (e.g. add Category category_name = "Conservation status" choosable for class Animal), add more Choices to Categories if needed (e.g. add another choice_name = 'fish' to category_name = 'Animal type'. This way it is very flexible for end admin user, no need to change anything in code.
I tried achieving it with Generic Relations - however, it wasn't successful, because AFAIK generic relation ties given object (e.g. Category) to instance of object of any other class, not generally to any other class (so, when using Generic Relations, for Category I would have to specify relationship with given Book object instance, not with Book class in general).
I wonder if such action is even feasible - I searched a lot and couldn't find anything. Maybe there is a simpler way? Thank you in advance!
With ContentTypes you can relate model instances to entire model classes, no overwriting necessary to achieve your goal.
Heres how to do it:
In your Category model define a many-to-many relationship to ContentType. This way, in your Category model-forms you will be able to choose which models this category applies to and you will be able to filter Choices based on whether their category contains a particular model. Use the limit_choices_to parameter of the ManyToManyField to restrict the ContentType choices to those with the correct app_label and of course exclude the Choice and Category models.
From the Book/Animal/Etc. models add many-to-many relationships to the Choice model and use the limit_choices_to parameter to limit the Choices to only those with a category which is related to the respective model.
Your models should then look somewhat like this:
from django.db import models
def get_ContentTypes():
appQ = models.Q(app_label='YourAppName') #change value of app_label to match your app's name
modelIsCatQ = models.Q(model='category')
modelIsChoice = models.Q(model='choice')
return appQ & ~modelIsCatQ & ~modelIsChoice
class Category(models.Model):
category_name = models.CharField(max_length=128)
asigned_models = models.ManyToManyField(ContentType,limit_choices_to=get_ContentTypes)
class Choice(models.Model):
choice_name = models.CharField(max_length=128)
category = models.ForeignKey(Category,on_delete=models.Model)
class Animal(models.Model):
choices = models.ManyToManyField(Choice,limit_choices_to=models.Q(category_assigned_models__model__startswith='animal'))
class Book(models.Model):
choices = models.ManyToManyField(Choice,limit_choices_to=models.Q(category_assigned_models__model__startswith='book'))
Aaand Voila. There you have it:
When creating/editing a category, you choose which models it should apply to
When creating/editing a Book/Animal/etc. you can only see the relevant choices.
I have a class which has an IntegerField attr.
In its ModelForm, in the field of this attr, I need to send a String, which later will store an Integer once it is processed in the view.
The problem is that Django doesn't allows this, and when I use form.cleaned_data.get('myattr') it's saying that it's wrong because it should be an Integer.
class Student(models.Model):
teacher = models.IntegerField(null=False) # I'm saving teacher's key here
class Teacher(models.Model:
name = models.CharField(max_length= 50, null=False)
key = models.IntegerField(null=False)
class StudentForm(forms.ModelForm):
teacher = forms.ModelChoiceField(queryset=Teacher.objects.all(), label='Select the teacher')
So, when the user is selecting the student's teacher, that select field will display the name of the teachers available. But in the model it will store their key, which I manage in view.
views.py:
teacher = form.cleaned_data.get('teacher') # it has the name
teacher = Teacher.objects.get(name=teacher).key # getting the key in order to store an Integer, but Django is banning my code before anyway.
How can I handle this without changing the data type of the model?
I even added to_field_name in the form field with the value of the Teachers' key.
One better approach here will be to setup a relationship between your student and teacher(using foregin key).
Depending of the need of your app here is how to do:
If one student can have several teachers and one teacher can have several students : https://docs.djangoproject.com/en/2.1/topics/db/examples/many_to_many/
If one student can have only one teacher but a teacher can have multiple students:
https://docs.djangoproject.com/en/2.1/topics/db/examples/many_to_one/
If one student can only have one teacher, and one teacher can only have one student:
https://docs.djangoproject.com/en/2.1/topics/db/examples/one_to_one/
This is the best way to manage this.
Then you only have to map the Student model in the Student form like:
class StudentForm(forms.ModelForm):
class Meta:
model = Student
#you can add the list of all the fields you want there
fields = ['teacher']
One extra step will be to define the str method of the model so Django will associate a string representation of your model in your form (Here for having a nice way to display Teacher in the student form).
class Teacher(models.Model):
name = models.CharField(max_length= 50, null=False)
#place other fields here ...
def __str__(self):
#if you print a Teacher django will return the string corresponding to the teacher name
return self.name
I'm making one of my first django apps with sqlite database. I have some models like for example:
class Connection(models.Model):
routeID = models.ForeignKey(Route, on_delete=models.CASCADE)
activityStatus = models.BooleanField()
car = models.ForeignKey(Car, on_delete=models.CASCADE)
class Route(models.Model):
name = models.CharField(max_length=20)
and forms
class RouteForm(ModelForm):
class Meta:
model = Route
fields = ['name']
class ConnectionForm(ModelForm):
class Meta:
model = Connection
fields = ['routeID', 'activityStatus', 'car']
And in my website, in the url for adding new Connection, I have cascade list containing RouteIDs. And I'd like it to contain RouteName, not ID, so it would be easier to choose. How should I change my ConnectionForm, so I could still use foreign key to Route table, but see RouteName instead of RouteID?
For now it's looking like this, but I'd love to have list of RouteNames, while still adding to Connection table good foreign key, RouteID
Update the Route Model's __str__ method:
class Route(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
Because the __str__() method is called whenever you call str() on an object. Django uses str(obj) in a number of places like in Modelform. By default it returns id or pk that is why you were seeing ids in model form. So by overriding it with name, you will see the names appear in choice field. Please see the documentation for more details on this.
Looking at graphene_django, I see they have a bunch of resolvers picking up django model fields mapping them to graphene types.
I have a subclass of JSONField I'd also like to be picked up.
:
# models
class Recipe(models.Model):
name = models.CharField(max_length=100)
instructions = models.TextField()
ingredients = models.ManyToManyField(
Ingredient, related_name='recipes'
)
custom_field = JSONFieldSubclass(....)
# schema
class RecipeType(DjangoObjectType):
class Meta:
model = Recipe
custom_field = ???
I know I could write a separate field and resolver pair for a Query, but I'd prefer it to be available as part of the schema for that model.
What I realize I could do:
class RecipeQuery:
custom_field = graphene.JSONString(id=graphene.ID(required=True))
def resolve_custom_field(self, info, **kwargs):
id = kwargs.get('id')
instance = get_item_by_id(id)
return instance.custom_field.to_json()
But -- this means a separate round trip, to get the id then get the custom_field for that item, right?
Is there a way I could have it seen as part of the RecipeType schema?
Ok, I can get it working by using:
# schema
class RecipeType(DjangoObjectType):
class Meta:
model = Recipe
custom_field = graphene.JSONString(resolver=lambda my_obj, resolve_obj: my_obj.custom_field.to_json())
(the custom_field has a to_json method)
I figured it out without deeply figuring out what is happening in this map between graphene types and the django model field types.
It's based on this:
https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers
Same function name, but parameterized differently.
Probably a very novice Django question, but here goes. In my Django project, I have this in my models
#models.py
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
class Test(models.Model):
classes = models.ForeignKey(Classes, on_delete=models.CASCADE)
name = models.TextField(max_length=100)
points = models.ManyToManyField(User, default=0)
I also have a form for Test, which is:
#forms.py
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = ('classes', 'name')
When I get to the actual form, the drop-down menu for 'classes' in TestForm merely comes up with 'Classes object' for the number of 'Classes' that I have in my DB. I want to change that so the form lists the names of the classes, which are stored in the 'Classes' model as 'classname'
Can anyone point me in the right direction please?
The easiest way to do it is to provide a string representation of your object, this would replace any where you access the class throughout your application
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
def __str__(self):
return "{0}: {1}".format(self.classcode, self.classname)
From the docs
The __str__ (__unicode__ on Python 2) method of the model will be called to generate string representations of the objects for use in the field’s choices; to provide customized representations, subclass ModelChoiceField and override label_from_instance.