I need a dropdown in my events model to show all possible locations available to bind to the event in Django (using DRF). An event can have many locations, a location can have many events.
Unfortunately, I'm having issues when I set the ModelChoiceField on the Event model, with queryset queryset=Location.objects.all(), giving error:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I'm assuming this is because, while Event Model is created after the Location Model, no data exists yet for Locations.
Then where can I define this dropdown field?
Locations Model:
class Location(models.Model):
location_name = models.CharField(max_length=200)
...
Events Model:
class Event(models.Model, forms.Form):
event_name = models.CharField(max_length=200)
location_id = models.IntegerField()
locations = forms.ModelChoiceField(queryset=Location.objects.all().order_by('location_name'), null=True)
EventLocation Join:
class EventLocation(models.Model):
event_id = models.ForeignKey(Event, blank=True, null=True)
location_id = models.ForeignKey(Location, blank=True, null=True)
The issue here is that you're mixing a Model and a Form when you declare the Event model like this:
class Event(models.Model, forms.Form):
event_name = models.CharField(max_length=200)
location_id = models.IntegerField()
locations = forms.ModelChoiceField(queryset=Location.objects.all().order_by('location_name'), null=True)
besides you're declaring locations as a form's field instead of a Model field.
In order to fix it, you must just declare the two models this way:
from django.db import models
class Location(models.Model):
location_name = models.CharField(max_length=200)
class Event(models.Model):
event_name = models.CharField(max_length=200)
location = models.ForeignKey(Location, null=True)
Notice that you don't need to declare an intermediate model (EventLocation) for the relation between both Event and Location. Just declare a model field as a foreign key and Django will take care of it for you to create it.
Then if you go the the Event admin site, you'll see it's possible to choose a location from the dropdown input:
Related
is it possible to issue a get result, only with certain fields in models, and not all? where fields must be defined inside models, like def or mixin. something like clean_data if a method is requested
view
cls = Class.objects.get(related_uuid='xxx')
you only need to display device and related_uuid, but define this in models.py itself, not in views.py
models
class Orders(models.Model):
device = models.CharField(max_length=150)
serial = models.CharField(max_length=150, blank=True)
related_uuid = models.CharField(max_length=22, blank=True)
I am trying to create a system where I set up an issue and it automatically creates custom fields that a user will have defined stored in another model. I set my current model up with a many to many relationship to the custom field model and overwrite the save method so that each of the custom defined fields will be added with a default value.
When I use the .add method after saving my issues model, nothing seems to happen, the many to many relationships are not created. The relationships are able to be made within the Django Admin interface.
class Issue(models.Model):
class Meta:
verbose_name = "Issues"
verbose_name_plural = "Issues"
title = models.TextField(null=False, blank=False)
description = models.TextField()
owner = models.ForeignKey(Organisation, on_delete=models.CASCADE)
category = models.ForeignKey(IssueCategory, on_delete=models.CASCADE)
state = models.ForeignKey(IssueStates, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
assignedTo = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
customFields = models.ManyToManyField(IssueCustomFields, blank=True)
def save(self, *args, **kwargs):
super(Issue, self).save(*args, **kwargs)
for x in IssueCustomFieldDefinitions.objects.filter(owner=self.owner):
issueCustom = IssueCustomFields.objects.create(
value=x.default,
fieldDefinition = x,
owner = self.owner,
)
self.customFields.add(issueCustom)
print(self.customFields.all())
I expect that when the Issue model is saved, it iterates through all the custom fields that th user has set up and creates an instance of it as well as establishing relationships. The relationship is never established (the instances are created though)
many to many relation is not depended on save method . if you assign relation between two model with many to many you don't need to save any of those model .
I am building a web app, where each product has its own "Profile". I need to add to the model some kind of field where i can add "Comments", with date and text, for keeping track of info such as change in formula, change of provider, change in price, etc.
Any ideas?
models.py
from django.db import models
# Create your models here.
class Horse(models.Model):
name = models.CharField(max_length=255)
nacimiento = models.DateField(blank=True, null=True)
nro = models.IntegerField()
event = models.TextField()
slug = models.SlugField(unique=True)
def __str__(self):
return '%s-%s' % (self.name, self.nro)
So for every event that happens, i need a new entrance with the description provided in the text field.
class HorseTracker(models.Model):
horse = models.ForeignKey(Horse, on_delete=models.CASCADE, related_name='horse')
comment = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
Each time you change something in your model you can create new instance of HorseTracker with description of changes you've made.
To make it more usefull you can use TabularInline in your HorseAdmin
class HorseTrackerInline(admin.TabularInline):
model = HorseTracker
class HorseAdmin(admin.ModelAdmin):
list_display = ['name', 'nacimiento', 'nro', 'event', 'slug', ]
inlines = [ HorseTrackerInline, ]
If you want to track various models I would suggest to use something like django-simple-history to keep track of the changes in your model.
Adding a history field to the model lets you save all the changes made to the fields and then access the history. If you want to add a custom message you can add fields to the historical model, and in a signal set the message.
from simple_history.models import HistoricalRecords
class MessageHistoricalModel(models.Model):
"""
Abstract model for history models tracking custom message.
"""
message = models.TextField(blank=True, null=True)
class Meta:
abstract = True
class Horse(models.Model):
name = models.CharField(max_length=255)
birthdate = models.DateField(blank=True, null=True)
nro = models.IntegerField()
event = models.TextField()
slug = models.SlugField(unique=True)
history = HistoricalRecords(bases=[MessageHistoricalModel,])
Then using signals you can get changes using diff and then save a custom message stating the changes an who made them.
from django.dispatch import receiver
from simple_history.signals import (post_create_historical_record)
#receiver(post_create_historical_record)
def post_create_historical_record_callback(sender, **kwargs):
history_instance = kwargs['history_instance'] # the historical record created
# <use diff to get the changed fields and create the message>
history_instance.message = "your custom message"
history_instance.save()
You could generate a pretty generic signal that works for all your models tracked with a 'history' field.
Note: I renamed "nacimiento" as "birthdate" to keep consistency in naming all the fields in english.
I am a novice in Django and I'm learning the ropes of the admin interface. I have a model with several foreign keys. These foreign keys then reference other foreign keys. On the admin website after I register the Property model and then try to add it I am given a dropdown box for each foreign key model. However this dropdown box only lists existing foreign keys. (http://i.stack.imgur.com/e5LCu.png)
What would be great is if instead of a dropdown box there were extra fields so I could add the foreign key models as I add the property model. That way I wouldn't have to manually add foreign keys and then go back and add some more, and then go back and finally add the property data.
How can I do this? This feels like a simple enough question but after intense Googling I still can't find the answer, so I apologize in advance.
Example of two of my models:
class Address(models.Model):
state = models.ForeignKey('State')
address1 = models.CharField(max_length=200)
address2 = models.CharField(max_length=200)
city = models.CharField(max_length=200)
postal_code = models.CharField(max_length=200)
class Property(models.Model):
address = models.ForeignKey('Address', blank=True, null=True)
borrower = models.ForeignKey('Person', blank=True, null=True)
company = models.ForeignKey('Company', blank=True, null=True)
contract = models.ForeignKey('Contract', blank=True, null=True)
loan_balance = models.IntegerField()
name = models.CharField(max_length=200)
primary_email = models.CharField(max_length=200)
primary_phone = models.CharField(max_length=200)
property_no = models.IntegerField()
Example of my admin.py:
# Register your models here.
class PropertyAdmin(admin.StackedInline):
model = Property
class PersonAdmin(admin.StackedInline):
model = Person
class CompanyAdmin(admin.StackedInline):
model = Company
class ContractAdmin(admin.StackedInline):
model = Contract
class CompletePropertyAdmin(admin.ModelAdmin):
inlines = [PropertyAdmin, PersonAdmin, CompanyAdmin, ContractAdmin]
admin.site.register(Property)
One solution to the problem can be, to create a custom form with fields from both the models and at the time of saving the values, first create the instance of Address model and then with that instance save your final Property model.
In Django, I have the following models.py
class Product(RandomPrimaryIdModel):
feature1 = models.CharField(max_length=20, blank=True, null=True)
feature2 = models.CharField(max_length=20, blank=True, null=True)
feature3 = models.CharField(max_length=20, blank=True, null=True)
class Mattress(Product):
category_type = models.CharField(max_length=50)
size = models.CharField(max_length=5)
def category(self):
return "bedding"
category = property(category)
I have the following views.py file
def update(request, id):
product = Product.objects.get(id=id)
...
In this method, update, can I call a method defined in the "Mattress" model from the Product model. For example, I want to write: if product.type == "mattress" where type has been defined in the Mattress Model and Mattress is a sub-model of Product.
Your example seems to sit between two different ways you can go, but is currently not correct. What is happening is that you are creating two tables: Product, and Mattress, and they are completely unrelated. Regardless of the fact that Mattress subclasses Product, it is just inheriting its structure. You cannot query anything in the Product table about a mattress because a mattress is in the Mattress table.
One way to go is to consider a Product just abstract, to be subclassed by actual products:
class Product(RandomPrimaryIdModel):
class Meta:
abstract=True
This will prevent a Product table from being created. Then you would directly query a mattress via: Mattress.objects.filter()
But this seems a bit limiting in terms of introducing many types of products, and having to manage different tables for them. The other way to go is to use a Product table, but use generic relations to support attaching any type of other table as a content object:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Product(RandomPrimaryIdModel):
feature1 = models.CharField(max_length=20, blank=True, null=True)
feature2 = models.CharField(max_length=20, blank=True, null=True)
feature3 = models.CharField(max_length=20, blank=True, null=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
With this, you would be able to set the content_object to be a Mattress instance. You can then use the ContentType to query:
p_type = ContentType.objects.get(name="mattress")
Product.objects.filter(content_type=p_type)
This looks like a case of automatic down casting. I needed a similar approach for a shopping cart that held generic 'ProductBase' instances but I needed to access the children's specific functions which were the actual products of type ProductDownloadable, ProductShipped, etc.
Django does not natively support this, but one could code it through introspection or use django-model-utils and once that is installed you could do:
# return a list 'child' classes of Product - in your case Mattresses
mattress_list = Product.objects.all().select_subclasses()
# return the direct 'child' class of Product - in your case Mattress class
mattress = Product.get_subclass(id=some_id) # returns the 'child' subclass
mattress.foo() # executes method on foo on Mattress class (not on Product class)