django model add default columns - python-3.x

I have to following model:
class publication_type(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(blank=True,null=True,default=None)
And I would like to add a few "default" entrys to this model, that I can always refer to without assuming whether they exist yet or not, for example:
publication_type.objects.create(id=1,name="article",description="...")
Where would be the best position in the django code to position to put this code?

Related

Add unique users to ProjectMember model in Django [duplicate]

This question already has answers here:
Django - create a unique database constraint for 2 or more fields together
(4 answers)
Closed 1 year ago.
I'm new to Django. Can anyone out there for the rescue.
In my current proect, I've couple of models inside a Django app: Project, ProjectMember. Here's their model and admin structure.
models.py
class Project(models.Model):
name = models.CharField(max_length=100)
start_date = models.DateField()
end_date = models.DateField()
description = models.TextField(max_length=1000)
class ProjectMember(models.Model):
project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
admin.py
from .models import Project, ProjectMember
class ProjectMemberInline(admin.TabularInline):
model = ProjectMember
extra = 0
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'start_date', 'end_date')
inlines = [ProjectMemberInline]
admin.site.register(Project, ProjectAdmin)
What I want to achieve is, every Project(i.e. model) should have unique users(ProjectMember) and every user can be associated with multiple projects. But with the current structure, system allows duplicate ProjectMember insertion in the admin. Please see the screenshot, I've add here 2 same users.
Any help is appreciated.
What you have effectively done is define the "through" table for your own M2M relationship here. You have 2 options:
Redefine your tables to use an out of the box M2M relationship - https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many/
Add a unique_together constraint - https://docs.djangoproject.com/en/3.2/ref/models/options/#unique-together
There's nothing wrong with what you've done, it's just a question of whether you want to use what Django gives you, or roll your own, so the solution of choice is up to you.
Edit: As the other answer points out, uniqie_together is deprecated infavour of UniqueConstraint, but the concept is the same, and which one you use may depend on the version of Django you're on. It sounds like this is a new project, so probably a recent version, in which case UniqueConstraint...
We can work with Django's constraint framework such that we can add a UniqueConstraint [Django-doc] over the two ForeignKeys:
class ProjectMember(models.Model):
project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['project', 'user'],
name='onceperproject'
)
]
Most modern databases will enforce this, and thus prevent that you can add the same user twice per project, or the same project twice to a user.

Mongoengine collection naming with UpperCamelCase?

I have been adding some collections to a Flask app using mongoengine models and the code works fine.
I was inspecting the data using MongoCompass and just noticed that one of the collections is named notify_destination which is NOT the name I used or its lowercase version.
My model class is NotifyDestination and there is no meta tag - so why the underscore in the middle of the collection name?
class NotifyDestination(me.Document):
owner_id = me.ObjectIdField()
username = me.StringField()
Mongoengine documentation (2.3.4) just says
The name of the collection is by default the name of the class, converted to lowercase.
Is insertion of the underscore normal behavior of MongoEngine because of my using UpperCamelCase?
I still have time to specify & force a name using a meta = {} tag in the model if this behavior is not officially documented somewhere else.
(mongoengine contributor here) Yes, this is the default behavior, the doc is imprecise but it's basically converting from UpperCamelCase to snake_case.
This means that
class User(Document):
# will have "user" as default collection name
class MyCompanyUser(Document):
# will have "my_company_user" as default collection name
class USACompany(Document):
# will have "u_s_a_company" as default collection name
Note that the doc was fixed.

Export django model to database adding extra fields

For exportation into a dbdump, I need to create a table that is a exact clone of my model but with a "summary" column.
Given that the model is concrete, not abstract, to subclass it is a failure, as
class AnnotatedModel(MyModel):
summary = m.TextField(null=True, blank=True)
creates a new table with only the new field.
I have attempted to use metaclass inheritance instead, but I am stuck because of the model.Meta subclass of Django BaseModel. Other attemps to completely clone the model with copy deepcopy etc have been also unsuccessful. I have got some success using add_to_class but I am not sure if it is a documented user level function and it modifies deeply the class, so I have not been able to produce two different, separated models.
The goal is be to be able to run a loop, say
for x in MyModel.objects.using('input').all():
y = cast_to_AnnotatedModelInstance(x)
y.pk = None
y.summary = Foo(x)
y.save(using='output')
without modifying the original model which is in a separate package. Ideally, I would prefer x to be objects of MyModel and then casting to AnnotatedModel and save them.
At the moment, what I am doing is to expand the model with add_to_class
from foo.bar.models import MyModel
MyModel.add_to_class('summary',m.TextField(null=True, blank=True))
then create the export database explicitly
with c['output'].schema_editor() as editor:
editor.create_model(MyModel)
and then loop as in the question, with using('input').defer("summary") to access the original model of the application.
for x in MyModel.objects.using('input').defer("summary").all():
x.pk = None
x.summary = Foo(x)
x.save(using='output')
Note that because of the add_to_class, the model tries to read the column summary even in the original database, fortunately it can be skipped using defer.

How to define a function to get an field element of a Marshmallow Schema while still serialising through a nested Schema

So I have a Nested Many Schema (eg Users) inside another Schema (eg Computer). My input object to be deserialised by the Schema is complex and does not allow for assignment, and to modify it to allow for assignment is impractical.
The input object (eg ComputerObject) itself does not contain an a value called "Users", but nested in a few other objects is a function that can get the users (eg ComputerObject.OS.Accounts.getUsers()), and I want the output of that function to be used as the value for that field in the schema.
Two possible solutions exist that I know of, I could either define the field as field.Method(#call the function here) or I could do a #post_dump function to call the function and add it to the final output JSON as it can provide both the initial object and the output JSON.
The issue with both of these is that it then doesn't serialise it through the nested Schema Users, which contains more nested Schemas and so on, it would just set that field to be equal to the return value of getUsers, which I don't want.
I have tried to define it in a pre-dump so that it can then be serialised in the dump (note: this schema is used only for dumping and not for loading), but as that takes in the initial object I cannot assign to it.
Basically, I have a thing I am trying to do, and a bunch of hacky workarounds that could make it work but not without breaking other things or missing out on the validation altogether, but no actual solution it seems, anybody know how to do this properly?
For further info, the object that is being input is a complex Django Model, which might give me some avenues Im not aware of, my Django experience is somewhat lacking.
So figured this out myself eventually:
Instead of managing the data-getting in the main schema, you can define the method used in the sub-schema using post_dump with many=True, thus the following code would work correctly:
class User(Schema):
id = fields.UUID
#pre_dump(pass_many=True)
def get_data(self, data, **kwargs):
data = data.Accounts.getUsers()
return data
class Computer(Schema):
#The field will need to be called "OS" in order to correctly look in the "OS" attribute for further data
OS = fields.Nested(User, many=True, data_key="users")

Zend_Db_Table_Abstract $_name not working

I encountered a problem regarding changing default table name
class Application_Model_DbTable_Game extends Zend_Db_Table_Abstract
{
protected $_name = 'games';
Error:
Message: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'gamenomad_dev.game' doesn't exist
Help me... it's supposed to be simple!
*EDIT
The problem here is that Zend Framework is supposed to detect the changed table name from the default 'game' into 'games'.
In ZF you have to hardcode your database table to model. It doesn't scan for database changes. You have two ways:
Create class with table name
class Game extends Zend_Db_Table_Abstract
{
// default table name: game
}
If you want to use ZF's default paths, you should put DBTable model into application/models/dbtable directory and name your class like Application_Model_DbTable_Game - then ZF knows it has to look for game table
Create class with any name
e.g. ExtraGameTable and set its parameters to show table name:
class ExtraGameTable extends Zend_Db_Table_Abstract
{
protected $_name = 'game';
}
As stated in documentation: http://framework.zend.com/manual/en/zend.db.table.html
If you don't specify the table name, it defaults to the name of the
class. If you rely on this default, the class name must match the
spelling of the table name as it appears in the database.
You may try to combine it with some configuration file and load table names from there, but still - ZF won't know anything about underlying database changes.
Show the actual line and stacktrace to your problem, maybe you are generating your query in a way it doesn't read the actual table name.

Resources